Crate finetime

Source
Expand description

§Finetime: Accurate, flexible, and efficient time keeping

finetime is a Rust library for accurate, flexible, and efficient timekeeping, designed for applications where precision and performance are critical.

  • Accurate: Supports exact arithmetic with attosecond-level precision over arbitrary time ranges, without sacrificing correctness or performance.
  • Flexible: Built on Rust generics, finetime allows durations and time points to be expressed as integers or floats of any native Rust bitwidth, in any SI time unit, and using any time scale.
  • Efficient: Represents time values as tick counts since an epoch, enabling compact storage and fast processing without conversion overhead.
  • Verified: Key correctness properties have been formally proven using the Kani model checker, ensuring a high degree of reliability.
  • Portable: The finetime library is fully no_std, such that it may be used even in bare metal environments.

With this fine degree of control and precision, finetime is suitable for all types of applications, from nanoseconds in embedded systems to femtoseconds in scientific computing, or picoseconds for precise orbit determination.

§Getting started

finetime requires the cargo build system for the Rust programming language to be present on your system. The library may be added as dependency for your Rust project by running cargo add finetime. Afterwards, it may be used directly by importing finetime into your Rust source code.

§Expressing time points

In finetime, time points are always bound to a specific timekeeping standard, indicated as TimeScale. One such example is Coordinated Universal Time (UTC). Time points may be constructed directly from some given datetime in the historic calendar:

use finetime::{UtcTime, Month};
let epoch = UtcTime::from_datetime(2025, Month::August, 3, 20, 25, 42).unwrap();

Note that constructing time points from datetimes may fail, because the given arguments do not form a valid time-of-day, or because the given date did not occur in the historic calendar: finetime makes this explicit. Users must acknowledge this possibility by unwrapping the returned Result before being able to use the created UtcTime.

A wide variety of time scales may be encountered in the context of precise timekeeping. finetime provides implementations for the most prevalent time scales: UTC, TAI, Unix time, terrestrial time (TT), GPS time (GPST), and most other GNSS time scales. Where possible, times can be converted between time scales using the into_time_scale() function.

use finetime::{GalileoTime, GpsTime, TaiTime, UnixTime, UtcTime, Month};
let epoch_utc = UtcTime::from_datetime(2025, Month::August, 3, 20, 25, 42).unwrap();
let epoch_tai = TaiTime::from_datetime(2025, Month::August, 3, 20, 26, 19).unwrap();
let epoch_unix = UnixTime::from_datetime(2025, Month::August, 3, 20, 25, 42).unwrap();
let epoch_gps = GpsTime::from_datetime(2025, Month::August, 3, 20, 26, 0).unwrap();
let epoch_galileo = GalileoTime::from_datetime(2025, Month::August, 3, 20, 26, 0).unwrap();
assert_eq!(epoch_utc.into_time_scale(), epoch_tai);
assert_eq!(epoch_utc.into_time_scale(), epoch_unix);
assert_eq!(epoch_utc.into_time_scale(), epoch_gps);
assert_eq!(epoch_utc.into_time_scale(), epoch_galileo);

If a desired time scale is not present, users may provide their own by implementing the TimeScale trait.

There is also support for subsecond datetime values, and conversion into more fine-grained TimePoint types to support higher-fidelity time types.

use finetime::{UtcTime, TtTime, Month, MilliSeconds};
let epoch_utc = UtcTime::from_datetime(2025, Month::August, 3, 20, 25, 42).unwrap();
let epoch_tt = TtTime::from_subsecond_datetime(2025, Month::August, 3, 20, 26, 51, MilliSeconds::new(184i64)).unwrap();
assert_eq!(epoch_utc.into_unit().into_time_scale(), epoch_tt);

These conversions must always be performed explicitly via the into_unit() method: this ensures that units are not accidentally mixed. If this is not done, finetime simply refuses to compile unit-ambiguous expressions. Exact integer arithmetic is supported to ensure the absence of round-off errors when converting between units.

§Expressing durations

Within finetime, the difference between two TimePoints is expressed as a Duration:

use finetime::{UtcTime, Month, Seconds};
let epoch1 = UtcTime::from_datetime(2020, Month::September, 30, 23, 59, 58).unwrap();
let epoch2 = UtcTime::from_datetime(2020, Month::October, 1, 0, 2, 3).unwrap();
let duration = epoch2 - epoch1;
assert_eq!(duration, Seconds::new(125));

Leap second boundaries are handled seamlessly:

use finetime::{UtcTime, Month, Seconds};
let epoch1 = UtcTime::from_datetime(2016, Month::December, 31, 23, 59, 59).unwrap();
let epoch2 = UtcTime::from_datetime(2016, Month::December, 31, 23, 59, 60).unwrap();
let epoch3 = UtcTime::from_datetime(2017, Month::January, 1, 0, 0, 0).unwrap();
assert_eq!(epoch2 - epoch1, Seconds::new(1));
assert_eq!(epoch3 - epoch2, Seconds::new(1));
assert_eq!(epoch3 - epoch1, Seconds::new(2));

The same goes when a time scale does not apply leap seconds:

use finetime::{TaiTime, Month, Seconds};
let epoch1 = TaiTime::from_datetime(2016, Month::December, 31, 23, 59, 59).unwrap();
let _ = TaiTime::from_datetime(2016, Month::December, 31, 23, 59, 60).unwrap_err();
let epoch3 = TaiTime::from_datetime(2017, Month::January, 1, 0, 0, 0).unwrap();
assert_eq!(epoch3 - epoch1, Seconds::new(1));

As with TimePoints, unit compatibility is checked at compile time, with conversions permit using the into_unit() method:

use finetime::{GpsTime, Month, Hours, MilliSeconds};
let epoch1 = GpsTime::from_datetime(2024, Month::August, 13, 19, 30, 0).unwrap();
let epoch2 = epoch1 + Hours::new(2).into_unit();
let epoch3 = epoch1.into_unit() + MilliSeconds::new(1);
assert_eq!(epoch2, GpsTime::from_datetime(2024, Month::August, 13, 21, 30, 0).unwrap());
assert_eq!(epoch3, GpsTime::from_subsecond_datetime(2024, Month::August, 13, 19, 30, 0, MilliSeconds::new(1)).unwrap());

§Casting between representations

Both TimePoint and Duration are generic over the underlying representation used to represent time spans. By default, a good choice is i64 (or i128 if i64 overflows), since the resulting time types will not suffer from round-off error. Sometimes it is desirable to convert to another representation, for whatever reason. In such cases, cast() and try_cast() may be used, depending on whether the underlying conversion is fallible or not:

use finetime::{Seconds, MilliSeconds};
let duration_i64 = Seconds::new(3i64);
let duration_float1: Seconds<f64> = duration_i64.try_cast().unwrap();
let duration_i32 = Seconds::new(3i32);
let duration_float2: Seconds<f64> = duration_i32.cast();
assert_eq!(duration_float1, duration_float2);

Using count(), the raw underlying representation of a Duration may be retrieved:

use finetime::{MilliSeconds};
let duration = MilliSeconds::new(32_184);
let count = duration.count();
assert_eq!(count, 32_184);

This representation is nothing more than the number of time units contained in the Duration.

Re-exports§

pub use errors::*;

Modules§

arithmetic
Implementation of auxiliary arithmetic functionality. Useful because implementing exact Duration and TimePoint arithmetic requires quite some additional non-standard functionality of their underlying representation types that are not well-captured using default traits and functionality.
errors
Description of all types of errors that may appear in this library. Separated into a separate module to permit reuse without importing entire namespaces with unrelated functionality.

Structs§

Bdt
The BeiDou Time (BDT) time scale is broadcast by BeiDou satellites. It is a continuous time scale, but may apply frequency adjustments to stay consistent with UTC (beyond the leap seconds, which are not applied). It starts at 00:00:00 UTC, January 1, 2006.
Date
Implementation of a date in the historic calendar. After 15 October 1582, this coincides with the Gregorian calendar; until 4 October 1582, this is the Julian calendar. The days inbetween do not exist.
Duration
A Duration represents the difference between two time points. It has an associated Representation, which determines how the count of elapsed ticks is stored. The Period determines the integer (!) ratio of each tick to seconds. This may be used to convert between Durations of differing time units.
Glonasst
The GLONASS Time (GLONASST) time scale is broadcast by GLONASS satellites. It follows UTC (or rather, UTC(SU), which is a realization of UTC) and adds three hours (Moscow time). Indeed, this means that it also incorporates leap seconds.
Gpst
The Global Positioning System (GPS) time scale is broadcast by GPS satellites. It is based on internal atomic clocks that are synchronized with TAI. The signal is defined to be a constant 19 seconds behind TAI.
GregorianDate
Representation of a proleptic Gregorian date. Only represents logic down to single-day accuracy: i.e., leap days are included, but leap seconds are not. This is useful in keeping this calendar applicable to all different time scales. Can represent years from -2^31 up to 2^31 - 1.
Gst
The Galileo System Time (GST) time scale is broadcast by Galileo satellites. It is based on internal atomic clocks that are synchronized with TAI. The signal is defined to be a constant 19 seconds behind TAI.
JulianDate
Representation of calendrical dates in terms of Julian Days (JD). A Julian date is the number of elapsed days since the start of the Julian period: noon on January 1, 4713 BC in the proleptic Julian calendar, or equivalently, on November 24, 4714 BC in the proleptic Gregorian calendar.
Local
The Local TimeScale is not actually a TimeScale. Instead, it is useful in scenarios where some TimePoint may be defined, but cannot (yet) be related to an actual time scale. This is useful, for example, in defining calendar arithmetic: calendrical dates are often not actually defined with respect to a unique, well-specified time scale. In this manner, we can represent those time points uniformly without linking them to an arbitrary time scale.
ModifiedJulianDate
The Modified Julian Day (MJD) representation of any given date.
Qzsst
The Quasi-Zenith Satellite System (QZSS) time scale is broadcast by QZSS satellites. It is effectively defined in the same manner as GPS, for interoperability. However, it uses different clocks for its realization. Hence, we define it separately, to make this distinction clear and to permit type safety in cases where this difference is important (like when comparing the realization accuracy of different time scales).
Tai
Time scale representing the international atomic time standard (TAI). TAI has no leap seconds and increases monotonically at a constant interval, making it useful as fundamental time scale to build the rest of this library on.
Tcg
The Geocentric Coordinate Time (TCG) is the time of a hypothetical clock that is placed at the center of the non-rotating geocentric reference frame.
TimePoint
A time point indicates an elapsed duration with respect to the epoch of some time scale. It may utilize arbitrary units and arbitrary precision, defined by the underlying Representation and Period.
Tt
Terrestrial time is the proper time of a clock located on the Earth geoid. It is used in astronomical tables, mostly. Effectively, it is little more than a constant offset from TAI.
Unix
The Unix time scale is the scale used throughout most operating systems nowadays. It is also the default used in libc, for example. It counts seconds since the Unix epoch (1970-01-01 UTC), but excludes leap seconds. In other words, Unix time stops for a second during a leap second. Outside of leap seconds, this means that the same exact time will be shown as during UTC, but durations that span across leap seconds are off by a second. Also, time stamps stored during leap seconds will be ambiguous.
Utc
Representation of the Coordinated Universal Time (UTC) standard. UTC utilizes leap seconds to synchronize the time to within 0.9 seconds of UT1, the solar time of the Earth. Since these leap seconds may be updated, this struct makes use of a backing mutable static to permit runtime changes to the leap second table, as needed for long-running programs.

Enums§

LeapSecondError
Month
Months as known in the Gregorian and Julian calendars.

Traits§

FromDate
Helper trait that is used to indicate that a certain unit can be used to express datetimes. In practice, that just means that it must be able to convert from days, hours, minutes, and seconds.
FromTimeScale
Used to indicate that it is possible to convert from one TimeScale to another.
IntoTimeScale
Used to indicate that it is possible to convert from one TimeScale to another.
TerrestrialTimeScale
With “terrestrial time scale”, a time scale is meant whose Platonic clock ticks in sync with an ideal clock that is located on the Earth geoid. Because of this, conversion to and from TAI and other terrestrial time scales is only a simple epoch offset. This makes it trivial to implement efficient conversions between all such time scales.
TimeScale
A time scale is a specification for measuring time. In this implementation, we specify this by relating times to an elapsed duration since some reference epoch.
TryFromTimeScale
Used to indicate that it is possible to convert from one TimeScale to another, though it is allowed for this operation to fail. This is the case when applying leap seconds, for example: the result may then be ambiguous or undefined, based on folds and gaps in time.
TryIntoTimeScale
Used to indicate that it is possible to convert from one TimeScale to another, though it is allowed for this operation to fail. This is the case when applying leap seconds, for example: the result may then be ambiguous or undefined, based on folds and gaps in time.

Type Aliases§

AttoSeconds
A duration that is expressed in terms of attoseconds.
BeiDouTime
BeiDouTime is a time point that is expressed according to the BeiDou Time time scale.
Days
A duration that is expressed in units of days.
FemtoSeconds
A duration that is expressed in units of femtoseconds.
GalileoTime
GalileoTime is a time point that is expressed according to the Galileo System Time time scale.
GlonassTime
GlonassTime is a time point that is expressed according to the GLONASS Time time scale.
GpsTime
GpsTime is a time point that is expressed according to the GPS time scale.
Hours
A duration that is expressed in units of hours.
LocalDays
Typedef for a specialization of LocalTime to a unit of days. Useful as intermediate type for normalization of other calendrical types.
LocalTime
A LocalTime represents some generic time point that has not yet been linked to a time scale. Hence, it may not be compared with time points from other scales, as there is no way to link them in time. It is best seen as an intermediate type that may be linked to some kind of time scale identification to instantiate a “full” time point.
MicroSeconds
A duration that is expressed in units of microseconds.
MilliSeconds
A duration that is expressed in units of milliseconds.
Minutes
A duration that is expressed in units of minutes.
Months
The length of 1/12 of an average year in the Gregorian calendar.
NanoSeconds
A duration that is expressed in units of nanoseconds.
PicoSeconds
A duration that is expressed in units of picoseconds.
QzssTime
QzssTime is a time point that is expressed according to the QZSS time scale.
Seconds
A duration that is expressed in units of seconds.
TaiTime
TaiTime is a specialization of TimePoint that uses the TAI time scale.
TcgTime
TcgTime is a specialization of TimePoint that uses the Geocentric Coordinate Time (TCG) time scale.
TtTime
A time point that is expressed in Terrestrial Time.
UnixTime
UnixTime is a TimePoint that uses the Unix time scale.
UtcTime
UtcTime is a specialization of TimePoint that uses the UTC time scale.
Weeks
A duration that is expressed in terms of weeks.
Years
The length of an average year in the Gregorian calendar.