1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
use crate::{Dt, Scale};
use hifitime::{Duration, Epoch};
impl Dt {
/// Converts this `Dt` to a `hifitime::Epoch` (TAI scale).
///
/// Round-trips perfectly with [`Dt::from_hifitime`].
pub fn to_hifitime(&self, current: Scale) -> Epoch {
let nanos = self.to(current, Scale::TAI).to_ns();
let j1900 = Epoch::from_gregorian_tai(1900, 1, 1, 12, 0, 0, 0);
let j2000 = Epoch::from_gregorian_tai(2000, 1, 1, 12, 0, 0, 0);
let offset_ns = j2000.to_tai_duration().total_nanoseconds()
- j1900.to_tai_duration().total_nanoseconds();
let ns_since_j1900 = nanos + offset_ns;
let dur = Duration::from_total_nanoseconds(ns_since_j1900);
let (centuries, nanos) = dur.to_parts();
Epoch::from_tai_parts(centuries, nanos)
}
/// Converts this `Span` to a [`hifitime::Duration`] (nanosecond precision).
///
/// - Sub-nanosecond attoseconds are **truncated toward zero**.
/// - The conversion is fully exact up to the nanosecond (128-bit integer arithmetic).
/// - Internally uses [`hifitime::Duration::from_total_nanoseconds`], which
/// automatically normalizes centuries/nanoseconds and saturates at
/// [`Duration::MAX`] / [`Duration::MIN`] if outside hifitime's range
/// (±32,768 centuries).
#[inline]
pub fn to_hifitime_duration(&self) -> Duration {
Duration::from_total_nanoseconds(self.to_attos() / 1_000_000_000i128)
}
/// Creates a `Dt` from a `hifitime::Epoch`.
///
/// - The conversion is exact (within hifitime's nanosecond precision).
/// - Uses a runtime-computed offset so it always matches whatever
/// calendar math hifitime uses (including negative years).
pub fn from_hifitime_epoch(epoch: Epoch) -> Self {
let ns_since_j1900 = epoch.to_tai_duration().total_nanoseconds();
let j1900 = Epoch::from_gregorian_tai(1900, 1, 1, 12, 0, 0, 0);
let j2000 = Epoch::from_gregorian_tai(2000, 1, 1, 12, 0, 0, 0);
let offset_ns = j2000.to_tai_duration().total_nanoseconds()
- j1900.to_tai_duration().total_nanoseconds();
let ns_since_zero_tai = ns_since_j1900 - offset_ns;
Self::from_ns(ns_since_zero_tai, Scale::TAI)
}
/// Creates a `Dt` from a `hifitime::Duration` (nanosecond precision).
///
/// This is the **exact reverse** of [`Dt::to_hifitime_duration`].
#[inline]
pub fn from_hifitime_duration(dur: Duration) -> Self {
Self::from_ns(dur.total_nanoseconds(), Scale::TAI)
}
}