Time Stamps and Clocks
UTC and ISO 8601, clock drift in ppm, NTP, PTP and GPS, jitter, stamping at the source and synchronizing several loggers.
What a time stamp must be
A data point is a value and a time. Most analysis (rates, delays, correlations between channels, alarms, reports for an audit) depends on the time being right, unambiguous and ordered. A good time stamp is:
- Unambiguous: the time zone and the date are explicit, with no daylight-saving gap or overlap.
- Monotonic when it needs to be: never goes backwards; if the wall clock is corrected, the log should show it, not corrupt the order.
- Accurate to what you need: a second for a building log, a millisecond for a machine, a microsecond for fast synchronous channels.
- Traceable: you can tell which clock supplied it and when it was last synchronized.
- Taken at the right moment: when the sample was acquired, not when it was processed, transmitted or written.
UTC and ISO 8601
Store UTC and write it in ISO 8601: 2026-10-31T10:40:00Z (year, month, day, T, hour, minute, second, Z for UTC). It sorts correctly as text, has no ambiguity between day and month, and has no daylight-saving shift. Convert to local time only when displaying.
| Format | Example | Remarks |
|---|---|---|
| ISO 8601 with Z | 2026-10-31T10:40:00Z | Best for files and databases. Add fractions for sub-second: 12:00:00.250Z |
| ISO 8601 with offset | 2026-10-31T03:40:00-07:00 | Clear if you must show local time; the offset is kept with the value |
| Unix time (seconds) | 1 793 443 200 | Seconds since 1970-01-01 UTC. Compact and easy to subtract; add milliseconds as a decimal or in a separate column |
| Excel date serial | days since 1899-12-30 | Convenient in a spreadsheet; loses the zone and precision. Convert on import, do not store as primary |
| “10/31/26 3:40 PM” | (ambiguous) | Which month? Which zone? 12- or 24-hour? Avoid in data |
Worked example: Unix time
- Unix time 1 793 443 200 is 20 757 whole days after 1970-01-01, and is 2026-10-31T10:40:00Z.
- The 2038 problem. A signed 32-bit seconds counter overflows at 2 147 483 647, which is 2038-01-19 03:14:07 UTC. Use 64-bit time in new designs.
- Leap seconds. UTC occasionally adds a second; Unix time ignores it, and GPS time (no leap seconds) is currently 18 s ahead of UTC. For logs that need sub-second continuity use a smoothed clock (“leap smear”) or a monotonic counter beside UTC.
Clock drift
Every clock runs a little fast or slow, measured in parts per million (ppm). One ppm is 1 µs of error per second, or 0.0864 s per day. Drift also changes with temperature, so a clock that is right in the lab may be wrong on a roof.
error (s per day) = ppm × 0.0864
| Clock | Typical error | Per day | Per 30 days |
|---|---|---|---|
| Uncompensated 32.768 kHz crystal (typical) | 20.0 ppm | 1.73 s | 51.84 s |
| Cheap RTC module (DS1307-class) | 50.0 ppm | 4.32 s | 2.2 min |
| Temperature-compensated RTC (DS3231) | 2.0 ppm | 0.17 s | 5.18 s |
| TCXO | 0.5 ppm | 0.04 s | 1.30 s |
| Microcontroller internal RC oscillator | 10000.0 ppm | 14.4 min | 432.0 min |
Worked example: a 20 ppm RTC
- A 20 ppm clock is off by 20 × 0.0864 = 1.73 s per day, so it is a full second out after 0.6 days and a minute out after 35 days.
- How often to re-sync? To stay within 1.0 s with a 2 ppm clock, correct it at least every 5.8 days; with the 20 ppm clock, every 0.6 days.
- Two loggers with opposite 20 ppm errors differ by 40 ppm: 3.46 s per day. Comparing events between them without synchronization is meaningless at the second level after a week.
- A microcontroller’s internal RC oscillator can be 1 % (10 000 ppm) off, which is 14 minutes a day: never use it as a time base for a log without a crystal or a sync source.
Time sources: RTC, NTP, PTP and GPS
| Source | Typical accuracy | Needs | Best for |
|---|---|---|---|
| Battery-backed RTC (DS3231, PCF8523) | 2 to 20 ppm; seconds per month | A coin cell; set once; I²C | Standalone loggers without a network |
| NTP (Network Time Protocol) | About 1 to 50 ms over the internet; less than 1 ms on a good LAN | A network; a time server | Most networked loggers, PCs, Raspberry Pi |
| SNTP (simple NTP) | Tens of ms; one-shot corrections | A small client in a microcontroller | ESP32 and similar, set the RTC at boot and daily |
| GPS / GNSS | About 50 ns to 1 µs with the 1PPS pulse; 100 ms without | An antenna with sky view | Remote sites, no network, many synchronized loggers |
| PTP (IEEE 1588) | Under 1 µs; sub-µs with hardware stamping | PTP-capable switches and NICs, a grandmaster | Synchronized industrial and test systems |
| Radio time signals (WWVB, DCF77) | About 10 ms plus propagation | A low-frequency receiver | Cheap clocks that correct themselves |
| Cellular network time (NITZ) | About 1 s | A modem | Coarse setting of remote loggers |
- Set the clock, then discipline it. A one-time set at startup is not enough; correct drift regularly, and gently (slew the clock rather than jumping it) so that timestamps stay monotonic.
- Record the sync state: the source, the last sync time and the estimated error, in the data or its metadata (see Planning a Logging System).
- Without a network, check against the truth: note the logger’s time against a reference when you visit; the offset divided by the days gives the ppm, and you can correct the whole record afterwards.
- Linux:
chronyorsystemd-timesyncdfor NTP; a Raspberry Pi has no RTC by default, so add one or the time restarts from the last saved value after a power cut.
Where to stamp the data
The time should be captured as close to the measurement as possible. Each stage between the sensor and the file adds delay that varies:
| Stamp applied at… | Delay and uncertainty | Use when |
|---|---|---|
| The ADC or hardware timer (interrupt or DMA) | Microseconds, fixed | Fast or synchronized channels |
| The logger firmware, when it reads the sensor | Hundreds of µs to a few ms, depending on the loop | Most loggers |
| A gateway, when the message arrives | Network latency, such as 80 ms and variable; much more after an outage | Slow trends only; never after buffering |
| The database, when it is inserted | Seconds to hours after a buffering outage | Never as the only time |
Worked example: why stamping on arrival fails
A remote logger sends a reading every second, and buffers while the network is down. If the server stamps readings when they arrive, 600 readings held for a 10-minute outage all get the same minute, and the real order and spacing are lost. Stamp at the logger, send the stamp with the value, and keep the server’s receipt time as a separate field to measure delay.
- Send both times: the device time (
t_sample) and the receipt time (t_received); their difference is a free health check. - Keep a sample counter beside the time: missing counts reveal lost samples, even if the clock jumped.
Jitter and regular sampling
Jitter is the variation in the interval between samples. A hardware timer starting each conversion gives a few nanoseconds; a software loop with sleep(0.001) on a general-purpose operating system can wander by milliseconds, and an occasional stall of tens of ms.
Worked example: software timing at 1 kHz
Sampling at 1 000 Hz means a 1 ms interval. A 5 % jitter is 50 µs. For a signal at 100 Hz the worst amplitude error is 2π f Δt = 2π × 100 × 0.00 ≈ 3.14 %, which is acceptable; at 5 kHz the same jitter would be 157.1 %: not acceptable. Use a hardware timer for fast sampling.
- Drive the ADC from a timer, read the results in an interrupt or by DMA, and stamp them from the timer count (see Embedded Systems).
- Use absolute scheduling, not
sleep(interval): set the next wake-up ast0 + n × interval, so errors do not accumulate. - Do not use the wall clock to measure intervals; it can step when the time is corrected. Use a monotonic clock (
time.monotonic(),millis()) and convert to UTC at the end.
Synchronizing several loggers
| Need | Method |
|---|---|
| Seconds | NTP on all units, or the same RTC set from one reference |
| Milliseconds | NTP on a local server over wired Ethernet, or a shared GPS receiver |
| Microseconds | PTP with hardware stamping, or a GPS 1PPS pulse wired to every logger |
| Simultaneous samples | One converter, or a shared sample clock (and trigger) to all converters |
| Events only | A shared marker: a pulse, a flash, a tap, recorded on every channel; align the data to it afterwards |
- Start together: a common start trigger plus a common clock removes the need to correct later.
- Use a marker even when synchronized: a recorded event in every log lets you verify the alignment, and fix it in the analysis.
- Convert to a common axis (seconds since the marker, or UTC) before joining logs from different sources (see Data, Files and Parsing).
Time zones, daylight saving and rollovers
| Problem | What happens | Prevention |
|---|---|---|
| Daylight-saving change | In autumn a local hour occurs twice (two different readings share a stamp); in spring one hour is missing | Store UTC; show local time only |
| Time zone not recorded | A log from another site cannot be placed in time | Store the offset or use UTC, and note the site zone |
| Clock set wrongly after a power cut | A logger without an RTC restarts at 2000-01-01 or 1970-01-01 | Battery-backed RTC; flag data written before a first sync |
| Millisecond counter rollover | A 32-bit millis() wraps after 49.7 days, and a microsecond counter after 1.2 hours | Subtract with unsigned arithmetic, or keep a 64-bit counter; log the wrap |
| Time stepped backwards | A sync corrects the clock by seconds; samples appear out of order | Slew, do not step; keep a sample counter; sort on the counter |
| Spreadsheet date mangling | Excel drops fractions of seconds or reads dates in a local format | Keep the primary data in ISO 8601 text or Unix time |
Related
- Data Logging: the overview of this guide.
- Sampling, Aliasing and Filtering: timing and jitter at high sample rates.
- Storage, Formats and Data Rates: how to store time stamps compactly.
- Data, Files and Parsing: parsing and converting time stamps in code.
- Industrial Communication: PTP and NTP on industrial networks.
FAQ
Which time zone should my log use?
UTC in ISO 8601 with a Z (or an explicit offset). Convert to local time only for display. It avoids daylight-saving ambiguity and makes logs from different places comparable.
How accurate is NTP?
About 1 to 50 ms over the internet and under 1 ms on a good local network; enough for most logging. For microseconds use PTP or GPS.
My logger loses a few seconds a month. Is it faulty?
Probably not: a 2 to 20 ppm crystal drifts 5 to 50 seconds a month. Add periodic synchronization, or a temperature-compensated RTC.
Should I stamp the data on the device or on the server?
On the device, at the time of the measurement, and also record the server’s receipt time. A server stamp alone is wrong after any buffering or outage.
References
- ISO 8601-1:2019, Date and time: representations for information interchange; RFC 3339 (internet profile).
- RFC 5905 (NTP version 4); IEEE 1588-2019 (PTP); the chrony and ntp.org documentation.
- Mills, D. L., Computer Network Time Synchronization; RTC datasheets (Maxim DS3231, NXP PCF8523).
Last reviewed: October 2026. Clock accuracies are typical; check your hardware’s datasheet and measure the real drift over time.
