1.. _timeutil_api: 2 3Time Utilities 4############## 5 6Overview 7******** 8 9:ref:`kernel_timing_uptime` in Zephyr is based on the a tick counter. With 10the default :kconfig:option:`CONFIG_TICKLESS_KERNEL` this counter advances at a 11nominally constant rate from zero at the instant the system started. The POSIX 12equivalent to this counter is something like ``CLOCK_MONOTONIC`` or, in Linux, 13``CLOCK_MONOTONIC_RAW``. :c:func:`k_uptime_get()` provides a millisecond 14representation of this time. 15 16Applications often need to correlate the Zephyr internal time with external 17time scales used in daily life, such as local time or Coordinated Universal 18Time. These systems interpret time in different ways and may have 19discontinuities due to `leap seconds <https://what-if.xkcd.com/26/>`__ and 20local time offsets like daylight saving time. 21 22Because of these discontinuities, as well as significant inaccuracies in the 23clocks underlying the cycle counter, the offset between time estimated from 24the Zephyr clock and the actual time in a "real" civil time scale is not 25constant and can vary widely over the runtime of a Zephyr application. 26 27The time utilities API supports: 28 29* :ref:`converting between time representations <timeutil_repr>` 30* :ref:`synchronizing and aligning time scales <timeutil_sync>` 31* :ref:`comparing, adding, and subtracting representations <timeutil_manip>` 32 33For terminology and concepts that support these functions see 34:ref:`timeutil_concepts`. 35 36Time Utility APIs 37***************** 38 39.. _timeutil_repr: 40 41Representation Transformation 42============================= 43 44Time scale instants can be represented in multiple ways including: 45 46* Seconds since an epoch. POSIX representations of time in this form include 47 ``time_t`` and ``struct timespec``, which are generally interpreted as a 48 representation of "UNIX Time" (see :rfc:`8536#section-2`). 49 50* Calendar time as a year, month, day, hour, minutes, and seconds relative to 51 an epoch. POSIX representations of time in this form include ``struct tm``. 52 53Keep in mind that these are simply time representations that must be 54interpreted relative to a time scale which may be local time, UTC, or some 55other continuous or discontinuous scale. 56 57Some necessary transformations are available in standard C library 58routines. For example, ``time_t`` measuring seconds since the POSIX EPOCH is 59converted to ``struct tm`` representing calendar time with `gmtime() 60<https://pubs.opengroup.org/onlinepubs/9699919799/functions/gmtime.html>`__. 61Sub-second timestamps like ``struct timespec`` can also use this to produce 62the calendar time representation and deal with sub-second offsets separately. 63 64The inverse transformation is not standardized: APIs like ``mktime()`` expect 65information about time zones. Zephyr provides this transformation with 66:c:func:`timeutil_timegm` and :c:func:`timeutil_timegm64`. 67 68To convert between ``struct timespec`` and ``k_timeout_t`` durations, 69use :c:func:`timespec_to_timeout` and :c:func:`timespec_from_timeout`. 70 71.. code-block:: c 72 73 k_timeout_t to; 74 struct timespec ts; 75 76 timespec_from_timeout(K_FOREVER, &ts); 77 to = timespec_to_timeout(&ts); /* to == K_FOREVER */ 78 79 timespec_from_timeout(K_MSEC(100), &ts); 80 to = timespec_to_timeout(&ts); /* to == K_MSEC(100) */ 81 82.. doxygengroup:: timeutil_repr_apis 83 84.. _timeutil_sync: 85 86Time Scale Synchronization 87========================== 88 89There are several factors that affect synchronizing time scales: 90 91* The rate of discrete instant representation change. For example Zephyr 92 uptime is tracked in ticks which advance at events that nominally occur at 93 :kconfig:option:`CONFIG_SYS_CLOCK_TICKS_PER_SEC` Hertz, while an external time 94 source may provide data in whole or fractional seconds (e.g. microseconds). 95* The absolute offset required to align the two scales at a single instant. 96* The relative error between observable instants in each scale, required to 97 align multiple instants consistently. For example a reference clock that's 98 conditioned by a 1-pulse-per-second GPS signal will be much more accurate 99 than a Zephyr system clock driven by a RC oscillator with a +/- 250 ppm 100 error. 101 102Synchronization or alignment between time scales is done with a multi-step 103process: 104 105* An instant in a time scale is represented by an (unsigned) 64-bit integer, 106 assumed to advance at a fixed nominal rate. 107* :c:struct:`timeutil_sync_config` records the nominal rates of a reference 108 time scale/source (e.g. TAI) and a local time source 109 (e.g. :c:func:`k_uptime_ticks`). 110* :c:struct:`timeutil_sync_instant` records the representation of a single 111 instant in both the reference and local time scales. 112* :c:struct:`timeutil_sync_state` provides storage for an initial instant, a 113 recently received second observation, and a skew that can adjust for 114 relative errors in the actual rate of each time scale. 115* :c:func:`timeutil_sync_ref_from_local()` and 116 :c:func:`timeutil_sync_local_from_ref()` convert instants in one time scale 117 to another taking into account skew that can be estimated from the two 118 instances stored in the state structure by 119 :c:func:`timeutil_sync_estimate_skew`. 120 121.. doxygengroup:: timeutil_sync_apis 122 123.. _timeutil_manip: 124 125``timespec`` Manipulation 126========================= 127 128Checking the validity of a ``timespec`` can be done with :c:func:`timespec_is_valid`. 129 130.. code-block:: c 131 132 struct timespec ts = { 133 .tv_sec = 0, 134 .tv_nsec = -1, /* out of range! */ 135 }; 136 137 if (!timespec_is_valid(&ts)) { 138 /* error-handing code */ 139 } 140 141In some cases, invalid ``timespec`` objects may be re-normalized using 142:c:func:`timespec_normalize`. 143 144.. code-block:: c 145 146 if (!timespec_normalize(&ts)) { 147 /* error-handling code */ 148 } 149 150 /* ts should be normalized */ 151 __ASSERT(timespec_is_valid(&ts) == true, "expected normalized timespec"); 152 153It is possible to compare two ``timespec`` objects for equality using :c:func:`timespec_equal`. 154 155.. code-block:: c 156 157 if (timespec_equal(then, now)) { 158 /* time is up! */ 159 } 160 161It is possible to compare and fully order (valid) ``timespec`` objects using 162:c:func:`timespec_compare`. 163 164.. code-block:: c 165 166 int cmp = timespec_compare(a, b); 167 168 switch (cmp) { 169 case 0: 170 /* a == b */ 171 break; 172 case -1: 173 /* a < b */ 174 break; 175 case +1: 176 /* a > b */ 177 break; 178 } 179 180It is possible to add, subtract, and negate ``timespec`` objects using 181:c:func:`timespec_add`, :c:func:`timespec_sub`, and :c:func:`timespec_negate`, 182respectively. Like :c:func:`timespec_normalize`, these functions will output 183a normalized ``timespec`` when doing so would not result in overflow. 184On success, these functions return ``true``. If overflow would occur, the 185functions return ``false``. 186 187.. code-block:: c 188 189 /* a += b */ 190 if (!timespec_add(&a, &b)) { 191 /* overflow */ 192 } 193 194 /* a -= b */ 195 if (!timespec_sub(&a, &b)) { 196 /* overflow */ 197 } 198 199 /* a = -a */ 200 if (!timespec_negate(&a)) { 201 /* overflow */ 202 } 203 204.. doxygengroup:: timeutil_timespec_apis 205 206 207.. _timeutil_concepts: 208 209Concepts Underlying Time Support in Zephyr 210****************************************** 211 212Terms from `ISO/TC 154/WG 5 N0038 213<https://www.loc.gov/standards/datetime/iso-tc154-wg5_n0038_iso_wd_8601-1_2016-02-16.pdf>`__ 214(ISO/WD 8601-1) and elsewhere: 215 216* A *time axis* is a representation of time as an ordered sequence of 217 instants. 218* A *time scale* is a way of representing an instant relative to an origin 219 that serves as the epoch. 220* A time scale is *monotonic* (increasing) if the representation of successive 221 time instants never decreases in value. 222* A time scale is *continuous* if the representation has no abrupt changes in 223 value, e.g. jumping forward or back when going between successive instants. 224* `Civil time <https://en.wikipedia.org/wiki/Civil_time>`__ generally refers 225 to time scales that legally defined by civil authorities, like local 226 governments, often to align local midnight to solar time. 227 228Relevant Time Scales 229==================== 230 231`International Atomic Time 232<https://en.wikipedia.org/wiki/International_Atomic_Time>`__ (TAI) is a time 233scale based on averaging clocks that count in SI seconds. TAI is a monotonic 234and continuous time scale. 235 236`Universal Time <https://en.wikipedia.org/wiki/Universal_Time>`__ (UT) is a 237time scale based on Earth’s rotation. UT is a discontinuous time scale as it 238requires occasional adjustments (`leap seconds 239<https://en.wikipedia.org/wiki/Leap_second>`__) to maintain alignment to 240changes in Earth’s rotation. Thus the difference between TAI and UT varies 241over time. There are several variants of UT, with `UTC 242<https://en.wikipedia.org/wiki/Coordinated_Universal_Time>`__ being the most 243common. 244 245UT times are independent of location. UT is the basis for Standard Time 246(or "local time") which is the time at a particular location. Standard 247time has a fixed offset from UT at any given instant, primarily 248influenced by longitude, but the offset may be adjusted ("daylight 249saving time") to align standard time to the local solar time. In a sense 250local time is "more discontinuous" than UT. 251 252POSIX Time (see :rfc:`8536#section-2`) is a time scale 253that counts seconds since the "POSIX epoch" at 1970-01-01T00:00:00Z (i.e. the 254start of 1970 UTC). UNIX Time is an extension of POSIX 255time using negative values to represent times before the POSIX epoch. Both of 256these scales assume that every day has exactly 86400 seconds. In normal use 257instants in these scales correspond to times in the UTC scale, so they inherit 258the discontinuity. 259 260The continuous analogue is UNIX Leap Time which is UNIX time plus all 261leap-second corrections added after the POSIX epoch (when TAI-UTC was 8 s). 262 263Example of Time Scale Differences 264--------------------------------- 265 266A positive leap second was introduced at the end of 2016, increasing the 267difference between TAI and UTC from 36 seconds to 37 seconds. There was 268no leap second introduced at the end of 1999, when the difference 269between TAI and UTC was only 32 seconds. The following table shows 270relevant civil and epoch times in several scales: 271 272==================== ========== =================== ======= ============== 273UTC Date UNIX time TAI Date TAI-UTC UNIX Leap Time 274==================== ========== =================== ======= ============== 2751970-01-01T00:00:00Z 0 1970-01-01T00:00:08 +8 0 2761999-12-31T23:59:28Z 946684768 2000-01-01T00:00:00 +32 946684792 2771999-12-31T23:59:59Z 946684799 2000-01-01T00:00:31 +32 946684823 2782000-01-01T00:00:00Z 946684800 2000-01-01T00:00:32 +32 946684824 2792016-12-31T23:59:59Z 1483228799 2017-01-01T00:00:35 +36 1483228827 2802016-12-31T23:59:60Z undefined 2017-01-01T00:00:36 +36 1483228828 2812017-01-01T00:00:00Z 1483228800 2017-01-01T00:00:37 +37 1483228829 282==================== ========== =================== ======= ============== 283 284Functional Requirements 285----------------------- 286 287The Zephyr tick counter has no concept of leap seconds or standard time 288offsets and is a continuous time scale. However it can be relatively 289inaccurate, with drifts as much as three minutes per hour (assuming an RC 290timer with 5% tolerance). 291 292There are two stages required to support conversion between Zephyr time and 293common human time scales: 294 295* Translation between the continuous but inaccurate Zephyr time scale and an 296 accurate external stable time scale; 297* Translation between the stable time scale and the (possibly discontinuous) 298 civil time scale. 299 300The API around :c:func:`timeutil_sync_state_update()` supports the first step 301of converting between continuous time scales. 302 303The second step requires external information including schedules of leap 304seconds and local time offset changes. This may be best provided by an 305external library, and is not currently part of the time utility APIs. 306 307Selecting an External Source and Time Scale 308------------------------------------------- 309 310If an application requires civil time accuracy within several seconds then UTC 311could be used as the stable time source. However, if the external source 312adjusts to a leap second there will be a discontinuity: the elapsed time 313between two observations taken at 1 Hz is not equal to the numeric difference 314between their timestamps. 315 316For precise activities a continuous scale that is independent of local and 317solar adjustments simplifies things considerably. Suitable continuous scales 318include: 319 320- GPS time: epoch of 1980-01-06T00:00:00Z, continuous following TAI with an 321 offset of TAI-GPS=19 s. 322- Bluetooth Mesh time: epoch of 2000-01-01T00:00:00Z, continuous following TAI 323 with an offset of -32. 324- UNIX Leap Time: epoch of 1970-01-01T00:00:00Z, continuous following TAI with 325 an offset of -8. 326 327Because C and Zephyr library functions support conversion between integral and 328calendar time representations using the UNIX epoch, UNIX Leap Time is an ideal 329choice for the external time scale. 330 331The mechanism used to populate synchronization points is not relevant: it may 332involve reading from a local high-precision RTC peripheral, exchanging packets 333over a network using a protocol like NTP or PTP, or processing NMEA messages 334received a GPS with or without a 1pps signal. 335 336``timespec`` Concepts 337===================== 338 339Originally from POSIX, ``struct timespec`` has been a part of the C standard 340since C11. The definition of ``struct timespec`` is as shown below. 341 342.. code-block:: c 343 344 struct timespec { 345 time_t tv_sec; /* seconds */ 346 long tv_nsec; /* nanoseconds */ 347 }; 348 349The ``tv_nsec`` field is only valid with values in the range ``[0, 999999999]``. The 350``tv_sec`` field is the number of seconds since the epoch. If ``struct timespec`` is 351used to express a difference, the ``tv_sec`` field may fall into a negative range. 352