Part 1
요약·해설
Epoch·calendar 변환, offset·skew registration, leap-second discontinuity와 external continuous scale 선택을 설명합니다.
epoch · calendar
base · latest · skew
TAI · UTC · UNIX Leap
Part 2
접을 수 있는 영어 원문 전체
영어 원문 전체 펼치기
EAC650FAB071A82B65C538714889081F157C03E08AB8D00869AEC65E10654237
.. _timeutil_api:
Time Utilities
##############
Overview
********
:ref:`kernel_timing_uptime` in Zephyr is based on the a tick counter. With
the default :kconfig:option:`CONFIG_TICKLESS_KERNEL` this counter advances at a
nominally constant rate from zero at the instant the system started. The POSIX
equivalent to this counter is something like ``CLOCK_MONOTONIC`` or, in Linux,
``CLOCK_MONOTONIC_RAW``. :c:func:`k_uptime_get()` provides a millisecond
representation of this time.
Applications often need to correlate the Zephyr internal time with external
time scales used in daily life, such as local time or Coordinated Universal
Time. These systems interpret time in different ways and may have
discontinuities due to `leap seconds <https://what-if.xkcd.com/26/>`__ and
local time offsets like daylight saving time.
Because of these discontinuities, as well as significant inaccuracies in the
clocks underlying the cycle counter, the offset between time estimated from
the Zephyr clock and the actual time in a "real" civil time scale is not
constant and can vary widely over the runtime of a Zephyr application.
The time utilities API supports:
* :ref:`converting between time representations <timeutil_repr>`
* :ref:`synchronizing and aligning time scales <timeutil_sync>`
For terminology and concepts that support these functions see
:ref:`timeutil_concepts`.
Time Utility APIs
*****************
.. _timeutil_repr:
Representation Transformation
=============================
Time scale instants can be represented in multiple ways including:
* Seconds since an epoch. POSIX representations of time in this form include
``time_t`` and ``struct timespec``, which are generally interpreted as a
representation of `"UNIX Time"
<https://tools.ietf.org/html/rfc8536#section-2>`__.
* Calendar time as a year, month, day, hour, minutes, and seconds relative to
an epoch. POSIX representations of time in this form include ``struct tm``.
Keep in mind that these are simply time representations that must be
interpreted relative to a time scale which may be local time, UTC, or some
other continuous or discontinuous scale.
Some necessary transformations are available in standard C library
routines. For example, ``time_t`` measuring seconds since the POSIX EPOCH is
converted to ``struct tm`` representing calendar time with `gmtime()
<https://pubs.opengroup.org/onlinepubs/9699919799/functions/gmtime.html>`__.
Sub-second timestamps like ``struct timespec`` can also use this to produce
the calendar time representation and deal with sub-second offsets separately.
The inverse transformation is not standardized: APIs like ``mktime()`` expect
information about time zones. Zephyr provides this transformation with
:c:func:`timeutil_timegm` and :c:func:`timeutil_timegm64`.
.. doxygengroup:: timeutil_repr_apis
.. _timeutil_sync:
Time Scale Synchronization
==========================
There are several factors that affect synchronizing time scales:
* The rate of discrete instant representation change. For example Zephyr
uptime is tracked in ticks which advance at events that nominally occur at
:kconfig:option:`CONFIG_SYS_CLOCK_TICKS_PER_SEC` Hertz, while an external time
source may provide data in whole or fractional seconds (e.g. microseconds).
* The absolute offset required to align the two scales at a single instant.
* The relative error between observable instants in each scale, required to
align multiple instants consistently. For example a reference clock that's
conditioned by a 1-pulse-per-second GPS signal will be much more accurate
than a Zephyr system clock driven by a RC oscillator with a +/- 250 ppm
error.
Synchronization or alignment between time scales is done with a multi-step
process:
* An instant in a time scale is represented by an (unsigned) 64-bit integer,
assumed to advance at a fixed nominal rate.
* :c:struct:`timeutil_sync_config` records the nominal rates of a reference
time scale/source (e.g. TAI) and a local time source
(e.g. :c:func:`k_uptime_ticks`).
* :c:struct:`timeutil_sync_instant` records the representation of a single
instant in both the reference and local time scales.
* :c:struct:`timeutil_sync_state` provides storage for an initial instant, a
recently received second observation, and a skew that can adjust for
relative errors in the actual rate of each time scale.
* :c:func:`timeutil_sync_ref_from_local()` and
:c:func:`timeutil_sync_local_from_ref()` convert instants in one time scale
to another taking into account skew that can be estimated from the two
instances stored in the state structure by
:c:func:`timeutil_sync_estimate_skew`.
.. doxygengroup:: timeutil_sync_apis
.. _timeutil_concepts:
Concepts Underlying Time Support in Zephyr
******************************************
Terms from `ISO/TC 154/WG 5 N0038
<https://www.loc.gov/standards/datetime/iso-tc154-wg5_n0038_iso_wd_8601-1_2016-02-16.pdf>`__
(ISO/WD 8601-1) and elsewhere:
* A *time axis* is a representation of time as an ordered sequence of
instants.
* A *time scale* is a way of representing an instant relative to an origin
that serves as the epoch.
* A time scale is *monotonic* (increasing) if the representation of successive
time instants never decreases in value.
* A time scale is *continuous* if the representation has no abrupt changes in
value, e.g. jumping forward or back when going between successive instants.
* `Civil time <https://en.wikipedia.org/wiki/Civil_time>`__ generally refers
to time scales that legally defined by civil authorities, like local
governments, often to align local midnight to solar time.
Relevant Time Scales
====================
`International Atomic Time
<https://en.wikipedia.org/wiki/International_Atomic_Time>`__ (TAI) is a time
scale based on averaging clocks that count in SI seconds. TAI is a monotonic
and continuous time scale.
`Universal Time <https://en.wikipedia.org/wiki/Universal_Time>`__ (UT) is a
time scale based on Earth’s rotation. UT is a discontinuous time scale as it
requires occasional adjustments (`leap seconds
<https://en.wikipedia.org/wiki/Leap_second>`__) to maintain alignment to
changes in Earth’s rotation. Thus the difference between TAI and UT varies
over time. There are several variants of UT, with `UTC
<https://en.wikipedia.org/wiki/Coordinated_Universal_Time>`__ being the most
common.
UT times are independent of location. UT is the basis for Standard Time
(or "local time") which is the time at a particular location. Standard
time has a fixed offset from UT at any given instant, primarily
influenced by longitude, but the offset may be adjusted ("daylight
saving time") to align standard time to the local solar time. In a sense
local time is "more discontinuous" than UT.
`POSIX Time <https://tools.ietf.org/html/rfc8536#section-2>`__ is a time scale
that counts seconds since the "POSIX epoch" at 1970-01-01T00:00:00Z (i.e. the
start of 1970 UTC). `UNIX Time
<https://tools.ietf.org/html/rfc8536#section-2>`__ is an extension of POSIX
time using negative values to represent times before the POSIX epoch. Both of
these scales assume that every day has exactly 86400 seconds. In normal use
instants in these scales correspond to times in the UTC scale, so they inherit
the discontinuity.
The continuous analogue is `UNIX Leap Time
<https://tools.ietf.org/html/rfc8536#section-2>`__ which is UNIX time plus all
leap-second corrections added after the POSIX epoch (when TAI-UTC was 8 s).
Example of Time Scale Differences
---------------------------------
A positive leap second was introduced at the end of 2016, increasing the
difference between TAI and UTC from 36 seconds to 37 seconds. There was
no leap second introduced at the end of 1999, when the difference
between TAI and UTC was only 32 seconds. The following table shows
relevant civil and epoch times in several scales:
==================== ========== =================== ======= ==============
UTC Date UNIX time TAI Date TAI-UTC UNIX Leap Time
==================== ========== =================== ======= ==============
1970-01-01T00:00:00Z 0 1970-01-01T00:00:08 +8 0
1999-12-31T23:59:28Z 946684768 2000-01-01T00:00:00 +32 946684792
1999-12-31T23:59:59Z 946684799 2000-01-01T00:00:31 +32 946684823
2000-01-01T00:00:00Z 946684800 2000-01-01T00:00:32 +32 946684824
2016-12-31T23:59:59Z 1483228799 2017-01-01T00:00:35 +36 1483228827
2016-12-31T23:59:60Z undefined 2017-01-01T00:00:36 +36 1483228828
2017-01-01T00:00:00Z 1483228800 2017-01-01T00:00:37 +37 1483228829
==================== ========== =================== ======= ==============
Functional Requirements
-----------------------
The Zephyr tick counter has no concept of leap seconds or standard time
offsets and is a continuous time scale. However it can be relatively
inaccurate, with drifts as much as three minutes per hour (assuming an RC
timer with 5% tolerance).
There are two stages required to support conversion between Zephyr time and
common human time scales:
* Translation between the continuous but inaccurate Zephyr time scale and an
accurate external stable time scale;
* Translation between the stable time scale and the (possibly discontinuous)
civil time scale.
The API around :c:func:`timeutil_sync_state_update()` supports the first step
of converting between continuous time scales.
The second step requires external information including schedules of leap
seconds and local time offset changes. This may be best provided by an
external library, and is not currently part of the time utility APIs.
Selecting an External Source and Time Scale
-------------------------------------------
If an application requires civil time accuracy within several seconds then UTC
could be used as the stable time source. However, if the external source
adjusts to a leap second there will be a discontinuity: the elapsed time
between two observations taken at 1 Hz is not equal to the numeric difference
between their timestamps.
For precise activities a continuous scale that is independent of local and
solar adjustments simplifies things considerably. Suitable continuous scales
include:
- GPS time: epoch of 1980-01-06T00:00:00Z, continuous following TAI with an
offset of TAI-GPS=19 s.
- Bluetooth Mesh time: epoch of 2000-01-01T00:00:00Z, continuous following TAI
with an offset of -32.
- UNIX Leap Time: epoch of 1970-01-01T00:00:00Z, continuous following TAI with
an offset of -8.
Because C and Zephyr library functions support conversion between integral and
calendar time representations using the UNIX epoch, UNIX Leap Time is an ideal
choice for the external time scale.
The mechanism used to populate synchronization points is not relevant: it may
involve reading from a local high-precision RTC peripheral, exchanging packets
over a network using a protocol like NTP or PTP, or processing NMEA messages
received a GPS with or without a 1pps signal.
Part 3
한국어 전문 번역
개요
Zephyr uptime은 tick counter에 기반합니다. 기본 CONFIG_TICKLESS_KERNEL에서 system start 순간 0부터 nominally constant rate로 증가하며 POSIX CLOCK_MONOTONIC, Linux CLOCK_MONOTONIC_RAW와 비슷합니다. k_uptime_get()은 이를 millisecond로 표현합니다.
Application은 local time이나 UTC 같은 외부 civil time과 Zephyr internal time을 연결해야 할 때가 많습니다. Civil scale은 leap second와 daylight saving offset 때문에 discontinuity가 있고 cycle counter underlying clock도 부정확하므로, Zephyr clock과 실제 civil time 사이 offset은 constant가 아니며 runtime 동안 크게 변할 수 있습니다.
Time utility API는 time representation 변환과 time scale synchronization/alignment를 지원합니다.
Time utility API
Representation transformation
Instant는 epoch부터의 seconds로 나타낼 수 있습니다. POSIX time_t·struct timespec은 보통 UNIX Time으로 해석합니다. 또는 epoch를 기준으로 year·month·day·hour·minute·second를 나타내는 struct tm calendar time을 사용할 수 있습니다. 이들은 representation일 뿐 local·UTC·continuous/discontinuous 중 어떤 scale인지 함께 해석해야 합니다.
C gmtime()은 POSIX epoch seconds를 calendar struct tm으로 바꾸고 sub-second timespec은 나머지 fraction을 별도로 처리할 수 있습니다. 역방향은 표준화되지 않았고 mktime()은 timezone 정보가 필요하므로 Zephyr는 timeutil_timegm()과 timeutil_timegm64()를 제공합니다.
Time scale synchronization
Synchronization에는 discrete counter update rate, 한 instant에서 두 scale을 맞추는 absolute offset, 여러 instant를 일관되게 맞추는 relative rate error가 필요합니다. 예를 들어 GPS 1-PPS로 disciplined된 reference clock은 ±250 ppm RC oscillator의 Zephyr system clock보다 훨씬 정확합니다.
reference Hz · local Hz
같은 순간의 ref/local pair
두 번째 관측 pair
relative rate error
local ↔ reference interpolation
Offset은 base가, 장기 drift는 skew가 보정합니다.
각 scale instant는 fixed nominal rate로 증가한다고 가정한 unsigned 64-bit integer입니다. timeutil_sync_config가 reference·local nominal rate를, timeutil_sync_instant가 같은 순간의 두 표현을 기록합니다. timeutil_sync_state는 base·latest observation과 rate error를 보정할 skew를 보관합니다.
timeutil_sync_estimate_skew()는 두 syncpoint로 skew를 계산하고 ref_from_local()·local_from_ref()는 이를 적용해 scale 사이 instant를 변환합니다.
Zephyr time support의 기반 개념
Time axis는 ordered instant sequence입니다. Time scale은 epoch 역할의 origin에 상대적으로 instant를 표현하는 방법입니다. Monotonic scale은 successive instant 값이 감소하지 않고, continuous scale은 앞뒤 instant 사이에 갑작스러운 forward/backward jump가 없습니다. Civil time은 정부 등 civil authority가 법적으로 정의하며 local midnight를 solar time에 맞추기도 합니다.
관련 time scale
TAI(International Atomic Time)는 SI second를 세는 clock들을 평균한 monotonic·continuous scale입니다. UT(Universal Time)는 지구 자전에 기반하고 rotation 변화에 맞추는 leap second가 필요해 discontinuous합니다. 가장 흔한 variant가 UTC이며 TAI와 UT의 차이는 시간에 따라 바뀝니다.
UT는 location과 무관하고 local Standard Time의 기반입니다. Local time은 longitude 중심의 fixed offset을 가지지만 daylight saving time으로 local solar time에 맞춰 offset이 변할 수 있어 UT보다 더 discontinuous합니다.
POSIX Time은 1970-01-01T00:00:00Z부터 second를 세고 UNIX Time은 negative value로 epoch 이전까지 확장합니다. 두 scale은 모든 day가 정확히 86400 second라고 가정하면서 보통 UTC instant와 대응해 discontinuity를 상속합니다. Continuous analogue인 UNIX Leap Time은 UNIX time에 POSIX epoch 이후 leap-second correction을 모두 더합니다. Epoch 당시 TAI-UTC는 8초였습니다.
Time scale 차이 예
2016년 말 positive leap second로 TAI-UTC 차이가 36초에서 37초가 됐습니다. 1999년 말에는 leap second가 없었고 차이는 32초였습니다.
| UTC Date | UNIX time | TAI Date | TAI-UTC | UNIX Leap Time |
|---|---|---|---|---|
| 1970-01-01T00:00:00Z | 0 | 1970-01-01T00:00:08 | +8 | 0 |
| 1999-12-31T23:59:28Z | 946684768 | 2000-01-01T00:00:00 | +32 | 946684792 |
| 1999-12-31T23:59:59Z | 946684799 | 2000-01-01T00:00:31 | +32 | 946684823 |
| 2000-01-01T00:00:00Z | 946684800 | 2000-01-01T00:00:32 | +32 | 946684824 |
| 2016-12-31T23:59:59Z | 1483228799 | 2017-01-01T00:00:35 | +36 | 1483228827 |
| 2016-12-31T23:59:60Z | undefined | 2017-01-01T00:00:36 | +36 | 1483228828 |
| 2017-01-01T00:00:00Z | 1483228800 | 2017-01-01T00:00:37 | +37 | 1483228829 |
Functional requirements
Zephyr tick counter에는 leap second나 standard-time offset 개념이 없어 continuous하지만, 5% tolerance RC timer라면 hour당 3 minute까지 drift할 수 있습니다.
Human time 변환은 두 단계입니다. 먼저 continuous하지만 부정확한 Zephyr scale을 정확하고 stable한 external continuous scale에 맞추고, 다음으로 stable scale을 discontinuous할 수 있는 civil scale로 바꿉니다. timeutil_sync_state_update() 주변 API는 첫 단계만 지원합니다.
External source와 scale 선택
Civil time accuracy가 수 second면 UTC를 stable source로 쓸 수 있지만 external source가 leap second를 적용할 때 1 Hz 연속 관측의 실제 elapsed time과 timestamp numeric difference가 달라집니다.
정밀 작업은 local·solar adjustment와 무관한 continuous scale이 단순합니다. GPS time은 1980-01-06 epoch와 TAI-GPS=19s, Bluetooth Mesh time은 2000-01-01 epoch와 TAI offset -32, UNIX Leap Time은 1970-01-01 epoch와 TAI offset -8을 사용합니다.
C·Zephyr library가 UNIX epoch 기반 integral/calendar conversion을 지원하므로 external scale로 UNIX Leap Time이 이상적입니다.
Syncpoint 획득 방법은 API와 무관합니다. High-precision RTC, NTP/PTP packet, 1-PPS 유무와 관계없이 GPS NMEA message 등을 사용할 수 있습니다.
API 참고: timeutil_repr_apis
timeutil_timegm64(tm)Broken-down calendar time을 POSIX epoch부터의 second offset인 int64_t로 변환합니다.
매개변수
tm: struct tm pointer
반환값
int64_t: POSIX epoch time-scale seconds
timeutil_timegm(tm)Broken-down calendar time을 POSIX epoch부터의 time_t second offset으로 변환합니다.
매개변수
tm: struct tm pointer
반환값
time_t: 표현 가능한 POSIX epoch seconds(time_t)-1: 표현 불가; errno=ERANGE
API 참고: timeutil_sync_apis
Synchronization functions
timeutil_sync_state_update(tsp, inst)새 synchronization instant를 state에 기록합니다. Base가 없으면 base가 되고, 있으면 reference·local 두 scale 모두에서 base보다 strictly later여야 latest가 됩니다. Skew는 자동 갱신하지 않습니다.
매개변수
tsp: sync stateinst: new paired instant
반환값
0: 새 base 설치1: 새 latest 설치-EINVAL: base와 호환되지 않음
timeutil_sync_state_set_skew(tsp, skew, base)Persistent storage 또는 recent estimate에서 얻은 skew를 설치하고 optional base를 바꿉니다. Base를 교체하면 latest를 clear합니다. Skew는 positive이고 1에서 지나치게 멀지 않아야 합니다.
매개변수
tsp: sync stateskew: 적용할 positive scale factorbase: optional new base
반환값
0: 갱신 성공-EINVAL: invalid skew
timeutil_sync_estimate_skew(tsp)State의 base와 latest syncpoint 차이로 reference 대비 local clock skew를 추정합니다. Latest는 local scale에서 base 뒤여야 합니다.
매개변수
tsp: base와 latest가 있는 state
반환값
float: estimated skew0: 추정 불가
timeutil_sync_ref_from_local(tsp, local, refp)Local instant를 skew 보정해 reference scale instant로 interpolation합니다. Base 전후 모두 가능하지만 결과가 negative reference time이면 실패하고 output을 수정하지 않습니다.
매개변수
tsp: base와 skew가 설치된 statelocal: local-scale instantrefp: reference result pointer
반환값
0: skew=1로 성공1: skew!=1로 성공-EINVAL: state 부족 또는 NULL output-ERANGE: reference result가 negative
timeutil_sync_local_from_ref(tsp, ref, localp)Reference instant를 local scale로 interpolation합니다. Base 전후가 가능하고 local time 0 이전 결과도 error 없이 int64_t로 제공합니다. 실패하면 output을 수정하지 않습니다.
매개변수
tsp: base와 skew가 설치된 stateref: reference-scale instantlocalp: local result pointer
반환값
0: skew=1로 성공1: skew!=1로 성공-EINVAL: state 부족 또는 NULL output
timeutil_sync_skew_to_ppb(skew)Skew를 parts-per-billion error로 변환합니다. 1.0은 0, 1보다 작으면 clock이 nominal보다 빨라 positive, 1보다 크면 느려 negative입니다. Float precision 때문에 표현 가능한 minimum error는 약 120 ppb이고 precise source도 약 2000 ppb error일 수 있습니다. 3.14748보다 큰 skew는 32-bit 결과를 underflow할 수 있습니다.
매개변수
skew: clock scale factor
반환값
int32_t: ppb errorINT32_MIN: 표현 불가
Configuration·instant·state structures
timeutil_sync_config두 clock duration 변환에 필요한 immutable nominal rate를 보관합니다. Reference frequency resolution이 높을수록 Zephyr tick과의 translation·skew calculation이 정확합니다. 1 Hz RTC는 drift를 관찰하려면 sample 간격이 훨씬 길어야 합니다.
ref_Hz정확하다고 가정하는 positive reference instant counter rate입니다. Source에 따라 실제 drift는 있을 수 있습니다.
local_Hz부정확하지만 reasonably stable하다고 가정하는 positive local counter rate입니다. Crystal은 약 25 ppm, RC oscillator는 더 큰 error가 흔하며 sync layer가 skew를 계산·보정합니다.
timeutil_sync_instant같은 instant를 reference와 local 두 scale로 함께 기록한 registration point입니다.
refReference scale instant입니다. Initialized object에서는 절대 0이면 안 됩니다.
local같은 instant의 local scale 표현입니다. Valid object에서도 0일 수 있습니다.
timeutil_sync_state두 scale 사이 offset과 rate error skew를 보관합니다. 사용 전 zero-initialize합니다.
cfgReference·local nominal rate config pointer입니다.
base두 scale의 base registration instant입니다.
latestSkew 계산을 위해 보관하는 가장 최근 paired instant입니다.
skewObserved local tick duration을 nominal local-rate tick duration으로 바꾸는 scale factor입니다. Local counter가 빠르거나 느린 ppm error를 보정합니다. 0은 uninitialized이며 base 설치 시 0이면 1로 설정되고, 이후에는 state_set_skew()로 지정합니다.
Source
출처
영어 원문에는 문단, 문서 지시문, 표, 코드, 코드 심벌, 경로를 그대로 보존했습니다.