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_historic_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, terrestrial time (TT), GPS time (GPST), and most other GNSS time scales.
Unix time is explicitly not included, as it is not a continuous time scale: the difference between two Unix times does not reflect the physically elapsed time, because leap seconds are not accounted for.
Where possible, times can be converted between time scales using the into_time_scale() function.
use finetime::{GalileoTime, GpsTime, TaiTime, UtcTime, Month, IntoTimeScale, Second};
let epoch_utc = UtcTime::from_historic_datetime(2025, Month::August, 3, 20, 25, 42).unwrap();
let epoch_tai = TaiTime::from_historic_datetime(2025, Month::August, 3, 20, 26, 19).unwrap();
let epoch_gps = GpsTime::from_historic_datetime(2025, Month::August, 3, 20, 26, 0).unwrap();
let epoch_galileo = GalileoTime::from_historic_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_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. To support calendrical functionality, it is additionally necessary to implement the AbsoluteTimeScale 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, IntoTimeScale};
let epoch_utc = UtcTime::from_historic_datetime(2025, Month::August, 3, 20, 25, 42).unwrap();
let epoch_tt = TtTime::from_fine_historic_datetime(2025, Month::August, 3, 20, 26, 51, MilliSeconds::new(184)).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_historic_datetime(2020, Month::September, 30, 23, 59, 58).unwrap();
let epoch2 = UtcTime::from_historic_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_historic_datetime(2016, Month::December, 31, 23, 59, 59).unwrap();
let epoch2 = UtcTime::from_historic_datetime(2016, Month::December, 31, 23, 59, 60).unwrap();
let epoch3 = UtcTime::from_historic_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, Second};
let epoch1 = TaiTime::from_historic_datetime(2016, Month::December, 31, 23, 59, 59).unwrap();
let _ = TaiTime::from_historic_datetime(2016, Month::December, 31, 23, 59, 60).unwrap_err();
let epoch3 = TaiTime::from_historic_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, Second};
let epoch1 = GpsTime::from_historic_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_historic_datetime(2024, Month::August, 13, 21, 30, 0).unwrap());
assert_eq!(epoch3, GpsTime::from_fine_historic_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.
§Comparison with hifitime, chrono, time, and jiff.
There are a multitude of high-quality Rust timekeeping crates out there already.
In particular, chrono, time, jiff, and hifitime will already cover most people’s use cases.
Most users will be interested in jiff, chrono and time, which are highly suitable for day-to-day timekeeping.
They handle civilian time zones (which finetime does not) and integrate much better with the operating system: however, they do not permit high-accuracy timestamps in frequently-used scientific and engineering time scales, like GPS, TAI, and TT. This makes them unsuitable for astrodynamics, physics, and engineering.
For users that are not interested in such niche applications and time scales, any of jiff, chrono, and time will certainly handle your needs: finetime might as well, but is certainly not the only option.
On the other hand, hifitime does handle such specialist time scales (although, in turn, it does not cover civilian time scales beyond UTC).
Additionally, hifitime supports nanosecond precision and is validated against the timekeeping part of the SPICE astrodynamics library.
Yet, hifitime’s Epoch type is limited to nanosecond precision and uses a segmented time type that dynamically stores the underlying time standard used.
This introduces quite some complexity in what could be a simple tick counting type.
This complexity definitely does not affect its correctness at all: hifitime is well-validated.
However, it does affect the efficiency of the time representation used: Epoch always consists of at least an 80-bit Duration and an at minimum 8-bit TimeScale.
Additionally, this means that the Epoch type cannot easily be extended to admit subnanosecond accuracy: in some GNSS applications, such accuracy is becoming necessary.
finetime is meant to address these concerns: it efficiently stores the underlying time stamp as a simple tick count. This means that all arithmetic on time stamps reduces to simple arithmetic directly on the underlying tick count: as efficient as it would be when written by hand.
Additionally, the finetime TimePoint type is generic over the time scale used, the underlying tick count representation, and the units in which it is expressed.
This makes it possible to natively use multiple time stamp types of differing time scale, bitwidth, and precision: all encoded safely and statically, to prevent mix-ups.
Conversion routines are written to support convenient and zero-overhead casting to other TimePoint times, where they are compatible.
Consequently, finetime is suitable for subnanosecond applications as well as for scenarios where a wide time range must be represented, or at low storage overhead; even within the same program.
Modules§
- errors
- All errors that may be returned by public functions of this library are defined in this module. This is useful in reducing the number of “unnecessary” inter-module dependencies, by ensuring that using the results/error of a function does not require importing its entire module.
Structs§
- Bdt
- Time scale representing the BeiDou Time (BDT). BDT has no leap seconds and increases monotonically at a constant rate. It is distributed as part of the BeiDou broadcast messages, making it useful in a variety of high-accuracy situations.
- Date
- Generic representation of date. Identifies an exact individual date within the calendar, in terms of days before (negative) or after (positive) 1970-01-01. This makes it useful as universal type that can be converted to and from other calendrical types.
- 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. - Duration
Component - A duration is represented as multiple “duration components”, each consisting of a number and a duration designator.
- Fraction
- Description of an integer ratio. Written to support efficient compile-time arithmetic. To support conversions between large magnitudes, this is implemented in u128. The numerator may be 0, but the denominator may never be.
- 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
- Time scale representing the Global Positioning System Time (GPST). GPST has no leap seconds and increases monotonically at a constant rate. It is distributed as part of the GPS broadcast messages, making it useful in a variety of high-accuracy situations.
- 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
- Time scale representing the Galileo System Time (GST). GST has no leap seconds and increases monotonically at a constant rate. It is distributed as part of the Galileo broadcast messages, making it useful in a variety of high-accuracy situations.
- Historic
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.
- Julian
Date - Representation of a proleptic Julian 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.
- Julian
Day - Representation of calendrical dates in terms of Julian Days (JD). A Julian day 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.
- Modified
Julian Date - The Modified Julian Day (MJD) representation of any given date.
- Qzsst
- Time scale representing the Quasi-Zenith Satellite System Time (QZSST). QZSST has no leap seconds and increases monotonically at a constant rate. It is distributed as part of the QZSST broadcast messages, making it useful in a variety of high-accuracy situations.
- Static
Leap Second Provider - Default leap second provider that uses a pre-compiled table to obtain the leap seconds. Will suffice for most non-critical applications and is useful in testing, but cannot be updated after compilation. This makes it unsuitable for long-running applications.
- Tai
- Time scale representing the International Atomic Time standard (TAI). TAI has no leap seconds and increases monotonically at a constant rate. This makes it highly suitable for scientific and high-accuracy timekeeping.
- Tcg
- Time scale representing the Geocentric Coordinate Time (TCG). This scale is equivalent to the proper time as experienced by an (idealistic) clock outside of Earth’s gravity well, but co-moving with the Earth. The resulting proper time is useful as independent variable for high-accuracy ephemerides for Earth satellites, and as intermediate variable when transforming into barycentric coordinate time.
- Time
Point - A
TimePointidentifies a specific instant in time. It is templated on aRepresentationandPeriod, which the define the characteristics of theDurationtype used to represent the time elapsed since the epoch of the underlying time scaleScale. - Tt
- Time scale representing the Terrestrial Time (TT) scale. This scale is a constant 32.184 seconds ahead of TAI, but otherwise completely synchronized. It is used primarily as independent variable in the context of planetary ephemerides.
- Utc
- Time scale representing Coordinated Universal Time (UTC). This scale is adjusted using leap seconds to closely match the rotation of the Earth. This makes it useful as civil time scale, but also means that external, discontinuous synchronization is required.
Enums§
- Duration
Designator - The set of duration symbols that are supported when expressing durations as strings.
- Literal
Ratio - Unit that is described as an exact ratio with respect to unity.
- Month
- Representation of a month in a Roman calendar.
- WeekDay
- Indication of a specific day-of-the-week. While explicit values are assigned to each day (to make implementation easier), no ordering is implied.
Constants§
- STATIC_
LEAP_ SECOND_ PROVIDER - Convenience constant that may be used to directly obtain a
StaticLeapSecondProviderobject.
Traits§
- Absolute
Time Scale TimeScalethat is fixed in calendrical time by an absolute epoch. Note that this does not yet unambiguously define the scale: for that, it must be linked to a well-defined scale like TAI or UTC (for example, by implementing theTerrestrialTimetrait).- Convert
Unit - Trait representing a lossless conversion from one unit to another. Note that the underlying value representation stays the same. For floating point representations, floating point rounding is permitted.
- Fractional
Digits - Represents the ability to iterate the fractional digits of some value.
- From
Date Time - This trait may be implemented for time points that can be constructed based on a date-time pair: they can connect a date and time-of-day to a specific time instant within their internal scale and vice versa.
- From
Fine Date Time - This trait may be implemented for time points that can be created based on “fine” date-time pairs, which have subsecond accuracy.
- From
Leap Second Date Time - This trait is the leap second equivalent of
FromDateTime. It permits the creation of time points from date-times when a non-standard leap second provider must be used. - From
Time Scale - Trait representing the ability to convert from one scale into another. Note that this conversion must always succeed: barring arithmetic overflows (on which panics are advised), it must always be possible to relate the time of two scales.
- Into
Date Time - This trait represents the fact that some time instant may be mapped back to the date-time pair that it corresponds with, at an accuracy of seconds.
- Into
Fine Date Time - Into
Leap Second Date Time - This trait is the leap second equivalent of
IntoDateTime. It permits the retrieval of date-times from time points when a non-standard leap second provider must be used. - Into
Time Scale - Trait representing the ability to convert from one scale into another. Note that this conversion must always succeed: barring arithmetic overflows (on which panics are advised), it must always be possible to relate the time of two scales.
- Leap
Second Provider - Since leap seconds are hard to predict in advance (due to irregular variations in the Earth’s
rotation), their insertion and deletion is based on short-term predictions. This means that
it is not possible to develop a leap second table that holds “for all eternity” without
external influence. Different applications may have different manners of obtaining these
updates from external sources - if at all possible. To accommodate all such applications, we
support a generic manner of introducing leap seconds, via the
LeapSecondProviderinterface. - MulCeil
- Trait representing multiplication that always succeeds, but that will round towards positive infinity if the output is not an integer.
- MulFloor
- Trait representing multiplication that always succeeds, but that will round towards negative infinity if the output is not an integer.
- MulRound
- Trait representing multiplication that always succeeds, but that will round-to-nearest (upwards on tie) if the result is not an integer.
- Terrestrial
Time - In general, “terrestrial time” refers not just to the specific realization TT, but to an idealized clock on the Earth geoid. It turns out that a lot of time scales are simply a variant on terrestrial time (or, equivalently, TAI). All these time scales may easily be converted into one another through a simple epoch offset: their internal clock rates are identical.
- Time
Scale - A
TimeScaleidentifies the relativistic time scale in which someTimePointis expressed. - TryConvert
Unit - Trait representing a fallible conversion from one unit to another, failing if the requested conversion cannot be computed losslessly. For floating point representations, this conversion shall always succeed.
- TryFrom
Exact - Extension of
TryFromthat behaves exactly the same, but may also define exact float conversions. - TryInto
Exact - Trait representing the converse of
TryFromExact. Similar to the standardTryFromandTryIntotraits, it is advised not to implement this trait directly but rather to implementTryFromExactand letTryIntoExactbe derived. - TryMul
- Trait representing a fallible multiplication that fails if the result cannot be represented by the output type without rounding error. “Small” errors like floating point error are permissible.
- Uniform
Date Time Scale - Some time scales are uniform with respect to date-times: they do not apply leap seconds. In
such cases, their implementation of the
DateTimemapping reduces to a simple add-and-multiply of days, hours, minutes, and seconds with respect to the “arbitrary” measurement epoch in which their resulting time points are measured. - Unit
Ratio - Trait representing the fact that something is a unit ratio.
Type Aliases§
- Atto
- Atto
Seconds - A duration that is expressed in terms of attoseconds.
- BeiDou
Time - Binary
Fraction1 - Binary
Fraction2 - Binary
Fraction3 - Binary
Fraction4 - Binary
Fraction5 - Binary
Fraction6 - Binary
Fraction7 - Binary
Fraction8 - Binary
Fraction9 - Binary
Fraction10 - Centi
- Days
- A duration that is expressed in units of days.
- Deca
- Deci
- Exa
- Femto
- Femto
Seconds - A duration that is expressed in units of femtoseconds.
- Galileo
Time - Giga
- Glonass
Time GlonassTimeis a time point that is expressed according to the GLONASS Time time scale.- GpsTime
- Half
Days - A duration that is expressed in units of half days.
- Hecto
- Hours
- A duration that is expressed in units of hours.
- Kilo
- Mega
- Micro
- Micro
Seconds - A duration that is expressed in units of microseconds.
- Milli
- 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
- Nano
Seconds - A duration that is expressed in units of nanoseconds.
- Peta
- Pico
- Pico
Seconds - A duration that is expressed in units of picoseconds.
- Quecto
- Quetta
- Qzss
Time - Ronna
- Ronto
- Second
- Seconds
- A duration that is expressed in units of seconds.
- Seconds
PerDay - Seconds
PerHalf Day - Represents the number of seconds in half a day. Rather arbitrary “unit ratio”, but turns out to be useful in representing Julian days and modified Julian days.
- Seconds
PerHour - Seconds
PerMinute - Seconds
PerMonth - The number of seconds in 1/12 the average Gregorian year.
- Seconds
PerWeek - Seconds
PerYear - The number of seconds in an average Gregorian year.
- TaiTime
- TcgTime
- Tera
- TtTime
- UtcTime
- Weeks
- A duration that is expressed in terms of weeks.
- Years
- The length of an average year in the Gregorian calendar.
- Yocto
- Yotta
- Zepto
- Zetta