Hifitime: nanosecond time handling that knows about leap seconds
An overflow-safe, high-performance datetime library providing leap-second-correct nanosecond precision across UTC, GPST, and relativistic time-scales. Flight-proven in lunar and deep-space missions.
At a glance
- What is it?
- Hifitime is a Rust library with Python bindings for engineering and scientific work where a timestamp has to be exact across UTC, TAI, GPST and relativistic time scales. It counts leap seconds from a shipped table, keeps nanosecond precision, and asks you to pick a time scale rather than hiding the difference behind an implicit assumption.
- Who is it for?
- Hifitime earns a place in flight software, laboratory timing code and orbital data pipelines where a leap second or a scale mismatch changes the answer, and the Rust and Python surfaces are close enough that a mixed team can use one model on both sides. It is the wrong choice for a web service that only needs UTC wall-clock arithmetic, because the API is a superset of what such a service needs and the extra scales are the whole point.
- Can I use it commercially?
- Yes, with conditions. MPL-2.0 is a weak copyleft licence: you can use it inside commercial and closed-source software, but if you distribute changes to its own files, you must publish those changes under the same licence.
- Is it still maintained?
- Yes. The repository last received commits 4 days ago.
- What is it written in?
- Mainly Rust, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The problem a leap second creates for a timestamp
Most datetime libraries in wide use store a count of seconds and a separate nanosecond field, and call that a time. Hifitime starts from a stricter premise: the same instant expressed on two different time scales is two different numbers, and a library that hides the difference will hand you a wrong answer at some point.
The project description says it plainly, providing overflow-safe, high-performance datetime handling with nanosecond precision across UTC, GPST and relativistic time scales, and it describes itself as flight-proven in lunar and deep-space missions. The README adds the precision guarantee: nanosecond precision for 65,536 centuries around the reference epoch of the initialization time scale, for example 01 January 1900 for TAI.
The audience is therefore not a web application team. It is people writing code where a nanosecond is meaningful and a second of drift is a defect: spacecraft dynamics, sensor fusion, seismology, market data reconciliation, anything that has to reconcile timestamps recorded by instruments that do not share a clock discipline.
The project classifies itself in its Python package metadata as `Development Status :: 5 - Production/Stable`, and the crate keywords include `no-std` and `leap-second`.
Epoch, Duration and the TimeScale enum
The API is small at the top level and the documentation is explicit about who needs what. Most users will rely on the `Epoch` and `Duration` structures, optionally the `Weekday` enum for week-based computations, and only scientific applications need the `TimeScale` enum.
An `Epoch` is the absolute instant and a `Duration` is the interval between two of them. The difference between two epochs is itself a `Duration`, which is the trick that makes leap seconds observable rather than theoretical:
use hifitime::prelude::*;
use core::str::FromStr;
// Create an epoch in UTC
let epoch = Epoch::from_gregorian_utc(2000, 2, 29, 14, 57, 29, 37);
// Or from a string
let epoch_from_str = Epoch::from_str("2000-02-29T14:57:29.000000037 UTC").unwrap();
assert_eq!(epoch, epoch_from_str);
// Creating it from TAI will effectively show the number of leap seconds in between UTC an TAI at that epoch
let epoch_tai = Epoch::from_gregorian_tai(2000, 2, 29, 14, 57, 29, 37);
// The difference between two epochs is a Duration
let num_leap_s = epoch - epoch_tai;
assert_eq!(format!("{num_leap_s}"), "32 s");That last assertion is the clearest statement of the design. Build the same wall clock reading in UTC and in TAI, subtract, and the answer is 32 seconds, which is the count of leap seconds between the two scales at that date. The library does not ask you to trust a table of offsets; it derives the difference from the same arithmetic it uses for everything else.
Converting between scales without losing the nanoseconds
Once an epoch exists, moving it to another scale is a method call, and the library offers two different flavours of that conversion depending on what you need.
One form returns a subdivision of the target scale, such as a count of days in the GPS time scale. The other returns an exact `Duration` measured in the target scale, which is what you want when the value has to be compared against a published number:
// Trivially convert to another time scale
// Either by grabbing a subdivision of time in that time scale
assert_eq!(epoch.to_gpst_days(), 7359.623402777777); // Compare to the GPS time scale
// Or by fetching the exact duration
let mjd_offset = Duration::from_str("51603 days 14 h 58 min 33 s 184 ms 37 ns").unwrap();
assert_eq!(epoch.to_mjd_tt_duration(), mjd_offset); // Compare to the modified Julian days in the Terrestrial Time time scale.The modified Julian day in Terrestrial Time is a good illustration of the target audience. Nobody building a web form needs that number, but a spacecraft trajectory or an atomic clock comparison does, and the point of the library is that the conversion is a checked, tested expression rather than a hand-rolled offset.
A `Duration` can also be built three ways: with the `TimeUnits` helper trait, with the built-in `Unit` enum, or parsed from a string, and all three are asserted equal in the documentation.
use hifitime::prelude::*;
use core::str::FromStr;
// Create a duration using the `TimeUnits` helping trait.
let d = 5.minutes() + 7.minutes() + 35.nanoseconds();
assert_eq!(format!("{d}"), "12 min 35 ns");
// Or using the built-in enums
let d_enum = 12 * Unit::Minute + 35.0 * Unit::Nanosecond;
// But it can also be created from a string
let d_from_str = Duration::from_str("12 min 35 ns").unwrap();
assert_eq!(d, d_from_str);Formatting: ISO8601, RFC2822, RFC3339 and a C89 token set
An exact instant still has to be printed for a human, a log file or a downstream parser, so the formatting layer is not an afterthought. The documentation shows the same epoch rendered through the `Formatter` type with a constant format specifier.
use hifitime::efmt::consts::{ISO8601, RFC2822, RFC3339};
use hifitime::prelude::*;
let epoch = Epoch::from_gregorian_utc(2000, 2, 29, 14, 57, 29, 37);
// The default Display shows the UTC time scale
assert_eq!(format!("{epoch}"), "2000-02-29T14:57:29.000000037 UTC");
// Format it in RFC 2822
let fmt = Formatter::new(epoch, RFC2822);
assert_eq!(format!("{fmt}"), format!("Tue, 29 Feb 2000 14:57:29"));The default `Display` output carries the time scale name, which is the small design decision that saves the most bugs: a printed epoch says whether it is UTC, and the ISO8601 and RFC3339 renderings keep the offset or the zone label rather than dropping it.
When the built-in constants are not enough, the library also supports the C89 token set, and the same format string works for parsing and for printing, which means a round trip through a legacy format is a two-liner rather than a custom parser.
use core::str::FromStr;
use hifitime::prelude::*;
let epoch = Epoch::from_gregorian_utc_hms(2015, 2, 7, 11, 22, 33);
// Parsing with a custom format
assert_eq!(
Epoch::from_format_str("Sat, 07 Feb 2015 11:22:33", "%a, %d %b %Y %H:%M:%S").unwrap(),
epoch
);Installing and the first use in Rust and Python
The README names the two installation routes, `cargo add hifitime` for a Rust project and `pip install hifitime` for Python, and warns that when you build from source the Python package only appears if the `python` feature is enabled. The crate is published on crates.io with the crate name `hifitime` and the Python package of the same name is built with `maturin` and PyO3.
The quickest first exercise is to build the same instant in two scales and subtract them, which is the leap second example above. In Rust that is a `cargo add` followed by a few lines in a `main`. In Python the equivalent calls are spelled differently, since the bindings expose constructors with an `init_from_gregorian` prefix:
>>> from hifitime import *
>>> epoch = Epoch("2000-02-29T14:57:29.000000037 UTC")
>>> epoch
2000-02-29T14:57:29.000000037 UTC
>>> epoch_tai = Epoch.init_from_gregorian_tai(2000, 2, 29, 14, 57, 29, 37)
>>> epoch_tai
2000-02-29T14:57:29.000000037 TAI
>>> epoch.timedelta(epoch_tai)
32 s
>>> epoch.to_gpst_days()
7359.623402777777
>>> epoch.to_mjd_tt_duration()
51603 days 14 h 58 min 33 s 184 ms 37 nsTwo things to check when you run this. First, the Python constructor takes a string while the Rust one takes components, so porting code between the two languages is not mechanical. Second, the difference of 32 s is a property of the scale pair, not of the date, so a test that hard-codes it will fail once the leap second table changes.
For sampling at a fixed interval, the `TimeSeries` iterator walks between two epochs and is available in both languages, inclusive of the end point:
use hifitime::prelude::*;
let start = Epoch::from_gregorian_utc_at_midnight(2017, 1, 14);
let end = start + 12.hours();
let step = 2.hours();
let time_series = TimeSeries::inclusive(start, end, step);
let mut cnt = 0;
for epoch in time_series {
#[cfg(feature = "std")]
println!("{}", epoch);
cnt += 1
}
// Check that there are indeed seven two-hour periods in a half a day,
// including start and end times.
assert_eq!(cnt, 7)no_std, feature flags and the Python bridge
The crate manifest shows the deployment options a bare-metal or embedded target needs. The default feature set is `std`, and the crate is categorised as `no-std`. The `std` feature pulls in `serde`, `serde_derive`, `web-time` and the `snafu` error handling with std and backtrace support, so a build that does not need serialization can drop them. The Python bindings are behind the `python` feature, which enables `std` and the `pyo3` extension module, and the Python package metadata turns the same features on through the `maturin` build configuration.
One comment in the manifest is worth reading before you enable the dynamic library target. A `cdylib` is built only when `std` is on, and in `no_std` a dynamic link target faces an unwinding panics not supported condition. In other words, the combination of no standard library and a shared library is not something the project supports, which is a narrow but real constraint for anyone planning to ship a C ABI wrapper.
The Python side needs Python 3.9 or newer, and the extension is generated from `hifitime.pyi` with a `generate_stubs.py` helper in the repository. The optional `serde` support means an `Epoch` can be serialised into a JSON or message payload, and the `web-time` dependency is what provides the current system time in the browser context, since the `Epoch::now()` call is documented behind the `std` feature.
Where Hifitime is the wrong tool, and what the licence asks of you
The library is specialised, and the specialisation is the cost. A service that only needs a UTC timestamp and a duration does not need a `TimeScale` enum, does not need a leap second table, and does not need nanosecond precision, and adopting Hifitime there means carrying a dependency whose main selling point never gets used. The API is also not drop-in compatible with the standard datetime types most codebases already use, so the migration cost is real even when the library is the right answer.
The leap second data is a repository artefact rather than a service. The tree carries `naif0012.txt` and a `data/` directory, and the version history shows the project has had to correct its own calendar arithmetic: release 4.2.6 is titled Fix Gregorian date calculations, dated 2026-03-23. That is worth knowing before you treat the table as fixed truth, and it is a reason to check the shipped data against the authority your domain is measured against.
On maintenance, the last push was on 2026-10-19, and the most recent release is 4.3.1 dated 2026-08-07, described as a few correctness fixes and performance improvements. Version 4.3.0 arrived on 2026-05-01 and added relativistic time scales TCG and TCB, Lunar Time TL and TCL, and thorough formal verification, and the README points at a write-up on how the Kani model checker found bugs in Hifitime. Formal verification is a genuine asset for a timing library, and it also implies the code is being held to a standard most alternatives never meet.
The licence is MPL-2.0 in both the crate manifest and the Python package metadata. That is a file-level copyleft licence: modifying the library's own source files and distributing the result requires those files to stay available under the same licence, while code that merely calls the library is unaffected. This is a licensing description, not legal advice, and the `LICENSE.txt` file in the repository is the version that governs.
Editorial conclusion
Hifitime earns a place in flight software, laboratory timing code and orbital data pipelines where a leap second or a scale mismatch changes the answer, and the Rust and Python surfaces are close enough that a mixed team can use one model on both sides. It is the wrong choice for a web service that only needs UTC wall-clock arithmetic, because the API is a superset of what such a service needs and the extra scales are the whole point. Before adopting it, check that the leap second table in the repository matches the authority your mission or lab is held to, confirm your platform can build the crate, since the Python feature pulls in `pyo3` and the default `std` feature pulls in `serde` and `web-time`, and read the `MPL-2.0` terms if you plan to modify the library rather than just call it.
Frequently asked questions
What is Hifitime used for?
Hifitime is a Rust library with Python bindings for handling timestamps in different time scales with nanosecond precision, including leap second correctness. It is aimed at engineering and scientific software where a difference of seconds between time scales changes the result.
How do I install Hifitime in Rust and in Python?
The README gives `cargo add hifitime` for a Rust project and `pip install hifitime` for Python. When building from source, the Python package is only produced if the `python` feature is enabled, and the Python build uses `maturin` with PyO3.
How does Hifitime count leap seconds?
You build the same wall clock reading in two scales and subtract the two epochs, and the resulting `Duration` is the number of leap seconds between them. The documentation shows a UTC and a TAI epoch for 29 February 2000 differing by 32 s, and the leap second data ships in the repository as `naif0012.txt` and a `data/` directory.
Does Hifitime work without the Rust standard library?
The crate is categorised as `no-std` and its default features are `std`, which pulls in `serde`, `serde_derive`, `web-time` and `snafu`. The manifest notes that a `cdylib` is only built when `std` is enabled, and that in `no_std` a dynamic link target faces an unwinding panics not supported condition.
What licence is Hifitime released under?
Both the crate manifest and the Python package metadata declare MPL-2.0, and the repository carries a `LICENSE.txt` file with the terms. MPL-2.0 is a file-level copyleft licence, so modified copies of the library source keep that licence while code that only calls the library is unaffected.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/nyx-space-hifitime)Was this useful?