Expand description
§deep-time
A fully featured and high performance Rust date and time library with attosecond precision that provides astronomical and civil timekeeping.
§Overview
- Auto-parsers for datetimes and durations that handle thousands of formats, relative dates and multiple languages, requires the
parsefeature - No std, no alloc, and wide-spread const fn
- Extensively validated against outputs from Astropy, Jiff, and other libraries and sources
- Fast ISO parser
- Time scales e.g. UTC with leap seconds support, including historical, TT, TAI, TDB, NAIF ET, LTC, GPS, etc. An optional feature
tdb_fairhead1990can be enabled which provides the ERFA TDB model - Strptime
- Strftime (multi-language day and month names available)
- First class timezone support provided by the Rust library jiff enabled with the
jiff-tzfeature - To and from all kinds of inputs and outputs, functions mostly prefixed with
toandfrom, available on the library’s types, see the main time types functions: Dt. Including JD, MJD, Unix, NTP, etc. - Calendar aware and, with the
jiff-tzfeature, timezone aware math - To and from jiff, chrono, and hifitime types
- No-alloc string return type
- Const fn libm math functions
- Safe, saturating arithmetic throughout
- No
unsafein the library -#![forbid(unsafe_code)] - Lunar and Mars modules
- Sidereal time with a const fn implementation of ERFA Equation of the Origins / Equinoxes
- UT1 and EOP
- Light-time (Shapiro delay, etc.), requires the
physicsfeature - Proper time along trajectories, requires the
physicsfeature - Relativity: Drift, Spacetime, Position, and Velocity — see docs/relativity.md for the underlying model. Requires the
physicsfeature. - CCSDS CUC, CDS, and CCS
- Binary size is mainly controlled through feature gating
§Examples
use deep_time::{Dt, Lang, LiteStr, ParseCfg, Scale, YmdHms};
// ============================================
// Parsing
// ============================================
// Smart auto-parsing (multi-language + timezone)
let cfg = ParseCfg {
lang: Lang::Fr,
..Default::default()
};
let dt = Dt::from_str_parse("15 août 2024 à 14:30 [Europe/Paris]", &cfg).unwrap();
let s = dt.to_str_rfc9557("Europe/Paris").unwrap();
assert_eq!("2024-08-15T14:30:00+02:00[Europe/Paris]", s);
// or with .parse
let dt: Dt = "1 jan 2000 07:00 [America/New_York] TAI".parse().unwrap(); // noon
assert_eq!(Dt::ZERO, dt);
// Relative dates are also supported
let ref_time = Dt::from_ymd(2026, 6, 16, Scale::UTC, 12, 0, 0, 0);
let en_cfg = ParseCfg {
ref_time: Some(ref_time),
..Default::default()
};
let dt = Dt::from_str_parse("2 days from now at 9am", &en_cfg).unwrap();
assert_eq!(dt, Dt::from_ymd(2026, 6, 18, Scale::UTC, 9, 0, 0, 0));
let dt = Dt::from_str_parse("next Monday at 14:00", &en_cfg).unwrap();
assert_eq!(dt, Dt::from_ymd(2026, 6, 22, Scale::UTC, 14, 0, 0, 0));
// Relative dates use Dt::now if the `std` feature is enabled and no
// ref_time is provided in the ParseCfg
let _ = Dt::from_str_parse("next Monday at 14:00", &ParseCfg::DEFAULT).unwrap();
// Fast ISO parsing with time scale and no alloc output
let dt = Dt::from_str_iso("2000-01-01T12:00:00 TAI").unwrap();
let lite_str: LiteStr<512> = dt.to_str_lite_iso8601().unwrap();
assert_eq!("2000-01-01T12:00:00+00:00", lite_str.as_str());
// ============================================
// Formatting
// ============================================
let s = dt.to_str_in_tz("%A, %d %B %Y %I:%M%P", "America/New_York", Lang::En).unwrap();
assert_eq!("Saturday, 01 January 2000 07:00am", s);
let s = dt.to_str_in_tz("%A, %-d de %B de %Y %H:%M", "America/New_York", Lang::Es).unwrap();
assert_eq!("Sábado, 1 de enero de 2000 07:00", s);
// ============================================
// Duration parsing
// ============================================
let span: Dt = Dt::from_str_duration("3 days 12 hours", Lang::En).unwrap();
let dur = span.to_str_lite_media_duration();
assert_eq!("3:12:00:00", dur.to_string());
// ============================================
// Time scale conversions + round-tripping
// ============================================
let dt = Dt::from_ymd(2000, 1, 1, Scale::TAI, 0, 0, 0, 123456789);
let tt = dt.to(Scale::TT);
let tdb = tt.to(Scale::TDB);
let ltc = tdb.to(Scale::LTC);
let utc = ltc.to(Scale::UTC);
let tcl = utc.to(Scale::TCL);
let tcg = tcl.to(Scale::TCG);
let tai = tcg.to_tai();
// round trips work for pretty much everything except UTCHist
assert_eq!(dt, tai);
let ymd: YmdHms = tai.to_ymd();
assert_eq!(ymd.attos(), 123456789);
// ============================================
// Other conversions
// ============================================
// unix
let dt = Dt::from_ymd(1970, 1, 1, Scale::UTC, 0, 0, 0, 0);
let unix = dt.to_unix().to_sec_f();
assert_eq!(unix, 0.0);
// or to milliseconds
let unix: i128 = dt.add_ms(1000).to_unix().to_ms();
assert_eq!(unix, 1000);
// to and from jd
let jd = Dt::ZERO.to_jd_f_raw();
assert_eq!(2451545.0, jd);
let dt = Dt::from_jd_f(jd, Scale::TAI);
assert_eq!(0, dt.attos);
// ============================================
// Calendar math
// ============================================
// calendar math and negative year
let dt = Dt::from_ymd(-2000, 1, 31, Scale::TAI, 12, 0, 0, 0);
let ymd = dt.add_mo(1).to_ymd();
assert_eq!(ymd.day(), 29);
// Timezone-aware calendar math (respects DST transitions, requires jiff-tz feature)
let dt = Dt::from_str_iso("2025-03-30T00:30:00Z").unwrap(); // Just before London DST start
// Normal (naive) addition — ignores DST rules
let normal = dt.add_hr(1);
// Timezone-aware addition — correctly handles the transition
let aware = dt.add_hr_tz(1, "Europe/London").unwrap();
println!("Normal: {}", normal.to_str_rfc9557("Europe/London").unwrap());
println!("Aware: {}", aware.to_str_rfc9557("Europe/London").unwrap());
// ============================================
// Leap seconds
// ============================================
// genuine leap second input round trips
let dt: Dt = "2015-06-30T23:59:60".parse().unwrap();
let s = dt.to_str_iso8601();
assert_eq!("2015-06-30T23:59:60+00:00", s);§Documentation
§Installation
- This crate has no default features.
- Enable
parsefor the auto-parsers andjiff-tzfor timezone support and DST-aware calendar math.
For example, add this to your Cargo.toml in the dependencies section:
[dependencies]
deep-time = { version = "0.1", features = ["parse", "jiff-tz"] }§Feature Flags
| Feature | Description | Requires |
|---|---|---|
parse | Enables the auto-parsers (from_str_parse, from_str_duration, etc.) | alloc |
jiff-tz | Enables timezone-aware calendar math (add_days_tz, add_hr_tz, etc.) and to_str_in_tz | std |
jiff-tz-bundle | Same as jiff-tz but bundles the full timezone database | std |
jiff | Enables basic Jiff interop | alloc |
chrono | Enables Chrono interop | alloc |
hifitime | Enables Hifitime interop | — |
serde | Enables Serialize / Deserialize for Dt and other types | alloc |
js | WebAssembly support (includes serde and JS bindings) | std |
tsify | TypeScript definitions via tsify (for WASM) | js |
std | Enables std functionality including Dt::now() and file handling | — |
alloc | Enables allocation (required for parsing and some conversions) | — |
es / de / fr | Language support, parsing different languages requires alloc, formatting does not | — |
euro | Enables all European languages | |
lang | Enables all languages | euro |
panic-handler | Provides an optional simple #[panic_handler] for no_std environments | no_std |
defmt | Enables defmt::Format trait implementations the main types. Intended for use with the defmt logging framework on embedded systems. | — |
wire | Enables wire format (serialization) support | — |
tdb_fairhead1990 | Replaces the fast TDB and TCB conversions with the full ERFA TDB model | — |
physics | Enables relativistic physics support (Drift, Spacetime, Position, Velocity, Observer, light-time, etc.) | — |
mars | Enables Mars time support (to_msd, to_mars_ls, etc.) | — |
sidereal | Enables sidereal time support | — |
eop | Enables Earth Orientation Parameters (UT1, etc.) | alloc |
locale | Enables system locale detection | std |
§Optional No-Alloc Panic Handler
deep-time supports no_std + no_alloc environments. When targeting bare-metal or embedded systems, you can enable a minimal panic handler:
[dependencies]
deep-time = { version = "0.1", features = ["panic-handler"] }This provides a simple #[panic_handler] that uses core::hint::spin_loop() (more power-efficient than a plain loop {}).
You only need this if you are building a binary crate in a no_std environment without your own panic handler.
§Notes
- The fast ISO 8601 parser (
from_str_iso) works without theparsefeature. - Multi-language parsing requires the
parsefeature, but multi-language formatting works without it. - The
.parse()implementation onDtautomatically chooses between the full parser and the ISO parser depending on enabled features.
Re-exports§
Modules§
- an_err
AnErr<K, const N: usize = 31>is aCopyerror type consisting of an error kind and a bounded human-readable reason string (Nbytes). Additional context can be appended to the reason.- civil_
parts - Intermediate “parts” of a civil date and time.
- constants
- Fundamental constants for time-scale conversions, relativistic corrections, and astronomical calculations.
- eop
- Earth Orientation Parameters (EOP) data parser and interpolator.
- error
DtErrKindand main error typeDtErr.DtErris a type alias toAnErr.- historical_
utc - Pre-1972 TAI−UTC historical offsets and linear drift rates
from the official USNO
tai-utc.dat(used by IAU SOFA). - leap_
seconds - Leap seconds table from the official IANA leap-seconds.list Updated through IERS Bulletin C as of April 2026. Last leap second: 2017-01-01 (TAI-UTC = 37 s) File expires: 28 December 2026
- lunar
- Lunar time-scale constants and conversion methods.
- mars
- Mars time-scale constants and conversion methods (MSD, MTC, Ls, LMST, LTST, Mars Year).
- math
- Tested,
const fnversions of libm float math functions. e.g.use deep_time::math::sin; - sidereal
- Sidereal rotation and time calculations for celestial bodies.
- tdb_
fairhead1990 - TDB−TT using the full ERFA model (Fairhead & Bretagnon 1990).
- tz
- Time zone name helpers.
Macros§
- an_err
- Ergonomic constructor and chaining macro for
AnErr. - f
- Convert a number to the crates
Realtype (f64).
Structs§
- Drift
- Quadratic polynomial that describes the accumulated difference between an
observer’s proper time (the time measured by a real clock moving through
spacetime) and a chosen coordinate time such as TT, TAI, or any other
Scale. - Dt
- The library’s central time type. A high-precision instant/duration with attosecond resolution.
- Every
- Builder type that enables the ergonomic
start.every(step)syntax. - LiteStr
- A fixed-capacity, stack-allocated buffer that can hold a UTF-8 string.
- Observer
- An observer at a specific instant.
- Parse
Cfg - Configuration options for
Dt::from_str_parse. - Position
- A 3-dimensional position vector expressed in Cartesian coordinates (x, y, z) with units of meters (SI).
- Spacetime
- The three local spacetime quantities that fully determine how fast an observer’s proper time advances relative to coordinate time.
- StrP
Time Fmt - A pre-validated, reusable date/time format string.
- Time
Range - An iterator over evenly spaced
Dtvalues. - Velocity
- A 3-dimensional velocity vector expressed in Cartesian coordinates (vx, vy, vz) with units of meters per second (SI).
- YmdHms
- Combined date + time object.
Enums§
- Lang
- Language codes following ISO 639-1 standard (two-letter codes). Default is En (English)
- Mode
- Used by
ParseCfginDt::from_str_parse. Controls how purely numeric dates are parsed. - Order
- Used by
ParseCfginDt::from_str_parse. Controls how ambiguous dates (e.g.01/02/03) are parsed. - Scale
- Time scales supported by the library.
Traits§
- Attos
Traits - Trait that adds ergonomic conversions from attoseconds values for i64, i128, and f64.
- Time
Traits - Trait that adds ergonomic time-unit methods to integers and floats.
Type Aliases§
- Real
- Alias for f64, maybe upgrade one day