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,
finetimeallows 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
Kanimodel checker, ensuring a high degree of reliability. - Portable: The
finetimelibrary is fullyno_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
DurationandTimePointarithmetic 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
Durationrepresents the difference between two time points. It has an associatedRepresentation, which determines how the count of elapsed ticks is stored. ThePerioddetermines the integer (!) ratio of each tick to seconds. This may be used to convert betweenDurations 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.
- Gregorian
Date - 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.
- Julian
Date - 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
LocalTimeScaleis not actually aTimeScale. Instead, it is useful in scenarios where someTimePointmay 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. - Modified
Julian Date - 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.
- Time
Point - 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
RepresentationandPeriod. - 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§
- Leap
Second Error - Month
- Months as known in the Gregorian and Julian calendars.
Traits§
- From
Date - 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.
- From
Time Scale - Used to indicate that it is possible to convert from one
TimeScaleto another. - Into
Time Scale - Used to indicate that it is possible to convert from one
TimeScaleto another. - Terrestrial
Time Scale - 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.
- Time
Scale - 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.
- TryFrom
Time Scale - Used to indicate that it is possible to convert from one
TimeScaleto 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. - TryInto
Time Scale - Used to indicate that it is possible to convert from one
TimeScaleto 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§
- Atto
Seconds - A duration that is expressed in terms of attoseconds.
- BeiDou
Time BeiDouTimeis a time point that is expressed according to the BeiDou Time time scale.- Days
- A duration that is expressed in units of days.
- Femto
Seconds - A duration that is expressed in units of femtoseconds.
- Galileo
Time GalileoTimeis a time point that is expressed according to the Galileo System Time time scale.- Glonass
Time GlonassTimeis a time point that is expressed according to the GLONASS Time time scale.- GpsTime
GpsTimeis a time point that is expressed according to the GPS time scale.- Hours
- A duration that is expressed in units of hours.
- Local
Days - Typedef for a specialization of
LocalTimeto a unit of days. Useful as intermediate type for normalization of other calendrical types. - Local
Time - A
LocalTimerepresents 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. - Micro
Seconds - A duration that is expressed in units of microseconds.
- Milli
Seconds - 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.
- Nano
Seconds - A duration that is expressed in units of nanoseconds.
- Pico
Seconds - A duration that is expressed in units of picoseconds.
- Qzss
Time QzssTimeis a time point that is expressed according to the QZSS time scale.- Seconds
- A duration that is expressed in units of seconds.
- TaiTime
TaiTimeis a specialization ofTimePointthat uses the TAI time scale.- TcgTime
TcgTimeis a specialization ofTimePointthat uses the Geocentric Coordinate Time (TCG) time scale.- TtTime
- A time point that is expressed in Terrestrial Time.
- Unix
Time UnixTimeis aTimePointthat uses theUnixtime scale.- UtcTime
UtcTimeis a specialization ofTimePointthat 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.