Chapter 9: Time and timekeeping
The chapter introduction explains why computer time is tricky for applications, measurements, and synchronization across machines.
After this chapter you will be able to
- System clock changes. Explain why resilient applications must allow for the system clock to move backward as well as forward.
- Distributed time agreement. Explain the time-agreement challenge for distributed systems and the scale of synchronization the introduction attributes to NTP on a local network.
- Rotational timekeeping mismatch. Explain why a day is not always exactly 86,400 seconds and why that matters to software.
- TAI and UTC tradeoff. Distinguish TAI’s fixed-length seconds from UTC’s periodic leap-second adjustments, and explain the tradeoff each addresses.
- Ticks counters and epoch. Explain how a digital clock uses regular ticks, counters, and an epoch to determine the current time.
- Time sources across power states. Distinguish the source of regular ticks when a computer is off from the source when it is running.
- Absolute and computer clocks. Distinguish absolute time, the real-time clock, and the system clock, including which clock applications use and why its time can jump.
- Monotonic and steady clocks. Explain the guarantees of monotonically increasing and steady clocks, and why a steady clock is useful for measuring durations rather than reporting absolute time.
- Seconds and fractional fields. Describe the typical two-integer representation of time: one field counts elapsed seconds and the other represents a fraction of a second, whose precision depends on the device.
- Epochs and integer trade-offs. Explain that elapsed time is measured from an arbitrary starting point called an epoch, and describe the simplicity and efficiency of fixed-width integers alongside their finite range and limited precision.
- Time zone offset representation. Explain why time zones are not purely technical divisions and describe the common representation given here: an integer number of seconds offset from UTC.
- Local system time reading. Describe what the example program reads and prints, and identify chrono::Local as the source of its time-zone-aware value.
- Clock struct as namespace. Explain why the application moves time-reading and time-adjusting functions to static methods of a Clock struct, and what this allows later.
- Clock output formats. Describe what the clock application's timestamp, rfc2822, and rfc3339 formats represent.
- Clock interface with clap. Describe how clap::Arg and clap::App organize clock’s command-line interface, including the input-validation aim and generated help output.
- Manual clock project setup. Describe how to recreate clock v0.1.1 manually: use a standard Cargo project, make Cargo.toml match listing 9.6 except for the authors field, and replace src/main.rs with listing 9.7.
- Common time-setting sequence. Trace how the two implementations turn a user-provided time into an updated system clock, including the time-zone conversion and OS-specific call.
- Setting time through libc. Explain that POSIX-compliant systems can set their system clock by calling libc's settimeofday, and note that the shown code does not check whether the call succeeds.
- Windows time-setting API. Explain that the Windows version uses kernel32.dll through the winapi crate and constructs a SYSTEMTIME value, which has more fields than the seconds-and-subseconds structure used by its libc counterparts.
- Time-setting error checks. Explain why calls that set the system time need error checks, and distinguish the robust Result-based approach from the section’s operating-system-error workaround.
- Request-response clock adjustment. Trace how an NTP client uses a time request and response to move its local clock toward the server’s time.
- Four NTP exchange timestamps. Trace the request and response between a client and a time server, identifying where T1 through T4 are recorded and why those four timestamps are collected.
- Offset and delay meanings. Distinguish the time offset θ from the network delay δ, including what each says about the local clock or the reliability of a response.
- Simplified adjustment safeguards. Describe the section’s simplified way of combining multiple server responses and the limits placed on adjustments.
- Timestamp precision mismatch. Explain why converting between chrono and NTP timestamps may lose accuracy.
- From and Into conversions. Describe how implementing From enables conversion between timestamp types and supports calls to .into().
What it builds on
- Supporting command-line arguments (chapter 2) · Prior exposure to command-line arguments.
Section by section
Introduction
The chapter introduction explains why computer time is tricky for applications, measurements, and synchronization across machines.
- System clock changes: Explain why resilient applications must allow for the system clock to move backward as well as forward.
Why it matters: Unexpected clock changes can affect an application that relies on time. - Multiple clocks and measurements: Describe why a computer's multiple physical and virtual clocks warrant care when measuring time-sensitive code.
Why it matters: A timing result deserves scrutiny when the clock used to obtain it has limitations. - Distributed time agreement: Explain the time-agreement challenge for distributed systems and the scale of synchronization the introduction attributes to NTP on a local network.
Why it matters: Machines working together may need a shared sense of time even when synchronization is imperfect.
Key terms: system clock, resilient applications, physical and virtual clocks, micro benchmarks, distributed systems, Network Time Protocol (NTP), local network
9.1 Background
Explains why accurate timekeeping is difficult and contrasts atomic time, adjusted civil time, and the clocks available on a computer.
- Rotational timekeeping mismatch: Explain why a day is not always exactly 86,400 seconds and why that matters to software.
Why it matters: This mismatch explains why keeping clocks aligned with the sun can cause software problems. - TAI and UTC tradeoff: Distinguish TAI’s fixed-length seconds from UTC’s periodic leap-second adjustments, and explain the tradeoff each addresses.
Why it matters: The two approaches balance predictable time units against keeping clock time aligned with the day. - Computer clocks and missing hardware: Describe the real-time clock and system time, and explain the Raspberry Pi’s need for another way to obtain accurate time.
Why it matters: A device that must timestamp events needs a dependable time source, especially when it cannot reach a network.
Key terms: earth’s rotation, leap second, timestamp, TAI, UTC, leap seconds, real-time clock, system time, hardware interrupts, NTP
9.2 Sources of time
Explains how computers obtain time from regular ticks and counters, and why CPU-based timestamps can be unreliable for precise profiling.
- Ticks counters and epoch: Explain how a digital clock uses regular ticks, counters, and an epoch to determine the current time.
Why it matters: This is the basic model behind a clock’s answer to “what time is it?” - Time sources across power states: Distinguish the source of regular ticks when a computer is off from the source when it is running.
Why it matters: It explains how a computer can keep time even while its main power is off. - Limits of CPU timestamps: Explain why CPU clock timestamps can cause problems when measuring short execution times.
Why it matters: A pair of CPU timestamps is not necessarily a precise measure of a function’s runtime.
Key terms: ticks, counters, epoch, battery-powered clock, quartz crystal, CPU clock frequency, CPU clock, out-of-order execution, timestamps, profiling
9.3 Definitions
This section defines the clocks and clock properties needed to discuss computer timekeeping.
- Absolute and computer clocks: Distinguish absolute time, the real-time clock, and the system clock, including which clock applications use and why its time can jump.
Why it matters: The distinction explains why an application's time can change abruptly even though the computer has a clock that runs while powered off. - Monotonic and steady clocks: Explain the guarantees of monotonically increasing and steady clocks, and why a steady clock is useful for measuring durations rather than reporting absolute time.
Why it matters: Choosing a steady clock lets you compare two readings for elapsed time without assuming its readings are calendar times. - Clock quality terms: Distinguish high accuracy, high resolution, and a fast clock using the properties defined here.
Why it matters: These terms describe different clock properties, so a quick reading is not necessarily a more accurate one.
Key terms: absolute time, wall clock time, calendar time, real-time clock, CMOS clock, system clock, monotonically increasing, steady clock, high accuracy, skew
9.4 Encoding time
This section explains how computers encode time using numeric fields and epochs, why fixed-width integers are useful but limited, and how real implementations differ.
- Seconds and fractional fields: Describe the typical two-integer representation of time: one field counts elapsed seconds and the other represents a fraction of a second, whose precision depends on the device.
Why it matters: Separating seconds from fractions makes it easier to interpret what a time value represents. - Epochs and integer trade-offs: Explain that elapsed time is measured from an arbitrary starting point called an epoch, and describe the simplicity and efficiency of fixed-width integers alongside their finite range and limited precision.
Why it matters: The epoch and integer limits determine how to interpret a timestamp and where that representation can fail. - Variation across time representations: Distinguish the general encoding approach from particular implementations, which may use different integer types, units, epochs, and fractional-field types.
Why it matters: A numeric timestamp cannot be interpreted reliably without knowing the convention that produced it.
Key terms: 32-bit integers, fraction of a second, precision, epoch, fixed-width integers, fixed-range, imprecise, rounding errors, FILETIME, time_t
9.4.1 Representing time zones
The section explains that time zones are political divisions and describes a common way to represent their offset from UTC.
- Time zone offset representation: Explain why time zones are not purely technical divisions and describe the common representation given here: an integer number of seconds offset from UTC.
Why it matters: This distinguishes the real-world definition of a time zone from a simple way to store its UTC offset.
Key terms: time zones, UTC, seconds offset
9.5 clock v0.1.0: Teaching an application how to tell the time
This section introduces a small Rust clock program that reads local system time, prints an ISO 8601 timestamp, and uses a time-zone-aware value.
- Local system time reading: Describe what the example program reads and prints, and identify chrono::Local as the source of its time-zone-aware value.
Why it matters: It connects the clock program’s visible output to the local-time value it uses. - Compile-time time zone safeguards: Explain the compile-time safeguard described for timestamps without time zones and illegal time arithmetic.
Why it matters: The typed time value helps prevent invalid timestamp operations before the program runs.
Key terms: system time, local time zone, chrono::Local, ISO 8601, timestamps, time zones, illegal time arithmetic
9.6 clock v0.1.1: Formatting timestamps to comply with ISO 8601 and email standards
Introduces the clock application and previews a run using the --use-standard timestamp flag, without explaining the formatting yet.
9.6.1 Refactoring the clock v0.1.0 code to support a wider architecture
This section refactors clock around a fieldless Clock struct and explains the Never type used by an unimplemented method.
- Clock struct as namespace: Explain why the application moves time-reading and time-adjusting functions to static methods of a Clock struct, and what this allows later.
Why it matters: It explains why the code gains a struct before it needs to store anything. - Never return type and panic: Explain what the exclamation-mark return type means for set() and what happens if its unimplemented placeholder runs.
Why it matters: It distinguishes a method that cannot return from one that simply has no useful return value. - Fieldless struct memory footprint: Describe what the section says about a struct with no fields.
Why it matters: It clarifies that introducing the fieldless struct does not add a stored object.
Key terms: Clock, static methods, namespace, Never type, unimplemented!(), todo!(), zero-sized type, ZST
9.6.2 Formatting the time
The section identifies the clock application's three time formats and explains how its RFC 3339 output relates to ISO 8601.
- Clock output formats: Describe what the clock application's timestamp, rfc2822, and rfc3339 formats represent.
Why it matters: These choices determine whether the clock prints an epoch count or a conventionally formatted time. - RFC 3339 and ISO 8601: Distinguish RFC 3339 compliance from ISO 8601 compliance as described in the section.
Why it matters: The distinction prevents treating the two timestamp standards as interchangeable.
Key terms: timestamp, UNIX timestamp, epoch, rfc2822, rfc3339, RFC 3339, ISO 8601
9.6.3 Providing a full command-line interface
This section explains why the clock application uses clap to parse and validate command-line arguments and how its arguments are organized.
- Raw command-line arguments: Explain why the clock application uses a parsing crate instead of handling command-line arguments directly through std::env::args.
Why it matters: This explains the problem clap solves for the clock application. - Clock interface with clap: Describe how clap::Arg and clap::App organize clock’s command-line interface, including the input-validation aim and generated help output.
Why it matters: This connects clock’s supported command-line inputs to the clap types used to present its interface.
Key terms: command-line arguments, std::env::args, Vec<String>, clap, clap::Arg, clap::App, --help, usage documentation
9.6.4 clock v0.1.1: Full project
This section explains how to recreate the clock v0.1.1 Cargo project using the provided configuration and source listings.
- Manual clock project setup: Describe how to recreate clock v0.1.1 manually: use a standard Cargo project, make Cargo.toml match listing 9.6 except for the authors field, and replace src/main.rs with listing 9.7.
Why it matters: These file placements let you assemble the version of the clock project described in this section.
Key terms: cargo, Cargo.toml, src/main.rs, clock v0.1.1
9.7 clock v0.1.2: Setting the time
9.7.1 Common behavior
This section outlines the shared steps for setting system time on different operating systems and warns that abruptly changing the clock can destabilize applications.
- Common time-setting sequence: Trace how the two implementations turn a user-provided time into an updated system clock, including the time-zone conversion and OS-specific call.
Why it matters: The sequence shows what the operating-system implementations share and where OS-specific work enters. - Abrupt clock change risk: Explain why directly setting the clock can cause instability and describe the gradual alternative mentioned.
Why it matters: Setting the correct time abruptly can still be harmful to programs that rely on time moving forward steadily.
Key terms: DateTime<FixedOffset>, DateTime<Local>, system call, unsafe block, Clock struct, monotonically increasing time, system’s clock
9.7.2 Setting the time for operating systems that use libc
This section explains how the clock application sets system time on non-Windows operating systems through libc and introduces the libc time types involved.
- Setting time through libc: Explain that POSIX-compliant systems can set their system clock by calling libc's settimeofday, and note that the shown code does not check whether the call succeeds.
Why it matters: It identifies the system-clock operation and an important limitation of the example. - Libc time type conventions: Describe libc's lowercase type names and _t suffix for type aliases, identify what time_t and suseconds_t represent, and explain why timekeeping code uses aliases instead of fixed integer types.
Why it matters: These conventions make the unfamiliar libc types in the clock code easier to interpret.
Key terms: libc, settimeofday, system clock, timeval, time_t, suseconds_t, type aliases
9.7.3 Setting the time on MS Windows
This section identifies the Windows API and time structure used by the clock application to set the time.
- Windows time-setting API: Explain that the Windows version uses kernel32.dll through the winapi crate and constructs a SYSTEMTIME value, which has more fields than the seconds-and-subseconds structure used by its libc counterparts.
Why it matters: It explains why setting the time on Windows needs a different API and a more detailed time value than the libc version.
Key terms: kernel32.dll, winapi crate, SYSTEMTIME, FILETIME
9.7.4 clock v0.1.2: The full code listing
This subsection points readers to the complete clock v0.1.2 project files and notes that platform-specific behavior requires changes to Cargo.toml.
9.8 Improving error handling
The section explains why setting the system time needs error handling and contrasts returning a Result with checking the operating system’s error report.
- Time-setting error checks: Explain why calls that set the system time need error checks, and distinguish the robust Result-based approach from the section’s operating-system-error workaround.
Why it matters: A time-setting call should not be treated as successful merely because it was made.
Key terms: settimeofday(), SetSystemTime(), Clock::set(t), Result, std::io::Error::last_os_error()
9.9 clock v0.1.3: Resolving differences between clocks with the Network Time Protocol (NTP)
Introduces NTP as a way to synchronize clocks, contrasting its two operating modes and explaining why choosing a time source is not straightforward.
- Always-on clock synchronization: Explain how NTP’s always-on mode synchronizes clocks and what it requires of participating devices.
Why it matters: This mode shows that clock synchronization can be a continuous collaboration rather than a one-off request. - Request-response clock adjustment: Trace how an NTP client uses a time request and response to move its local clock toward the server’s time.
Why it matters: A received timestamp alone is not enough: time passes while the message travels. - Time-source hierarchy and uncertainty: Describe NTP’s hierarchy of time sources and why asking several computers does not immediately establish the correct time.
Why it matters: A trusted source hierarchy helps, but receiving several time reports still leaves differences in network delay.
Key terms: clock synchronization, always on mode, peer-to-peer, daemon, request/response mode, timestamp, network latency, local clock, hierarchy, atomic clocks
9.9.1 Sending NTP requests and interpreting responses
The section explains how an NTP client-server exchange produces four timestamps used to compare the local clock with a time server.
- Four NTP exchange timestamps: Trace the request and response between a client and a time server, identifying where T1 through T4 are recorded and why those four timestamps are collected.
Why it matters: These four points let the client compare its clock with the server’s without treating either message as instantaneous.
Key terms: request, response, time server, T1–T4, NTPResult
9.9.2 Adjusting the local time as a result of the server’s response
Explains how the NTP client interprets server responses and makes cautious adjustments to its local clock without claiming to know an absolute, correct time.
- Offset and delay meanings: Distinguish the time offset θ from the network delay δ, including what each says about the local clock or the reliability of a response.
Why it matters: These distinctions explain what the client can infer from a server response before changing its clock. - Repeated clock adjustments: Explain why NTP adjusts clocks repeatedly and incrementally rather than treating one response as a final answer.
Why it matters: A clock becomes better aligned through repeated corrections, not a single definitive reading. - Simplified adjustment safeguards: Describe the section’s simplified way of combining multiple server responses and the limits placed on adjustments.
Why it matters: Combining responses and bounding corrections reduces the impact of questionable readings on the local clock.
Key terms: time offset, θ (theta), δ (delta), relative timestamps, NTP, θ, δ, weighted mean, 1 / θ2, time servers
9.9.3 Converting between time representations that use different precisions and epochs
This section explains why converting between chrono and NTP timestamps may lose precision and how Rust’s From trait enables conversions using .into().
- Timestamp precision mismatch: Explain why converting between chrono and NTP timestamps may lose accuracy.
Why it matters: A timestamp conversion can produce a valid value without preserving all of its original precision. - From and Into conversions: Describe how implementing From enables conversion between timestamp types and supports calls to .into().
Why it matters: It explains why the timestamp-conversion code can call .into() after implementing From.
Key terms: chrono, NTP, nanosecond precision, picoseconds, From, from(), Into, .into()
9.9.4 clock v0.1.3: The full code listing
This section points readers to the complete clock v0.1.3 code listing and its source file, without teaching a new concept.
9.10 Summary
Concepts explained in this chapter
- clockA system clock is the operating system's maintained representation of the current time, from which applications obtain time values.
- Unix epochAn epoch is the defined reference point from which elapsed time is measured.
- NTPNTP is a network protocol for synchronizing computer clocks using timestamp exchanges between clients and time servers.
- timestampA timestamp is a representation of a point in time, commonly expressed as an elapsed value or formatted date and time.
- time zoneA time zone is a regional convention associating local civil times with offsets or rules relative to a reference time scale.
- system timeSystem time is the time value maintained by an operating system for representing the current date and time.
- meanElapsed time is the duration between two temporal events or points.
- real-time clockA real-time clock is a hardware clock that maintains calendar time independently of the main processor and usually continues running while the system is powered off.
- time_ttime_t is a libc type alias representing elapsed whole seconds since the Unix epoch.
- conditional compilationA cfg attribute is a Rust attribute that conditionally includes an item based on compile-time configuration predicates.
- static methodA static method is a function associated with a type rather than with an instance of that type.
- From traitFrom is a Rust standard-library trait for infallibly converting a value of one type into another type.
- data conversionA type cast is an explicit conversion of a value from one data type to another.
- exceptionAn exception is a synchronous or otherwise special execution event that interrupts normal program flow because of an error or exceptional condition.
- result typeResult is Rust's standard result type that contains either a successful value or an error value.
- CargoCargo is Rust's package manager and build system for creating, compiling, running, documenting, and managing Rust projects.
- cargo.tomlCargo.toml is a Rust package manifest that declares project metadata and dependencies.
- referenceA reference is a non-owning value that provides access to another value without transferring its ownership.
- unsafe blockAn unsafe block is a Rust code region in which operations requiring explicit programmer responsibility for safety are permitted.
These guides are generated from the text of Manning books by Manning's knowledge graph and link to the sections they draw on. The full books are available on liveBook and at manning.com.
