Coverage Report

Created: 2026-05-16 06:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/hifitime-4.3.0/src/timescale/tcl.rs
Line
Count
Source
1
/*
2
* Hifitime
3
* Copyright (C) 2017-onward Christopher Rabotin <christopher.rabotin@gmail.com> et al. (cf. https://github.com/nyx-space/hifitime/graphs/contributors)
4
* This Source Code Form is subject to the terms of the Mozilla Public
5
* License, v. 2.0. If a copy of the MPL was not distributed with this
6
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
7
*
8
* Documentation: https://nyxspace.com/
9
*/
10
11
use crate::{Duration, TimeUnits};
12
13
/// Mean fractional rate of TCL relative to TT.
14
///
15
/// Paper option iii removes this secular TCL-TT drift when defining TL.
16
/// The paper gives approximately 6.8e-10, i.e. about 58.7 us/day.
17
pub(crate) const TCL_MINUS_TT_MEAN_RATE: f64 = 6.8e-10;
18
19
/// TL option iii:
20
///
21
/// ```text
22
///     TL = TCL + Δf * (TCL - TCL0) + const0
23
/// ```
24
/// If:
25
/// ```text
26
///     dTCL / dTT = 1 + k
27
/// ```
28
/// then choosing:
29
/// ```text
30
///     1 + Δf = 1 / (1 + k)
31
///
32
/// gives:
33
/// ```text
34
///     dTL / dTT = 1
35
/// ```
36
/// so TL has no secular drift relative to TT.
37
pub(crate) const TL_DELTA_F: f64 = -TCL_MINUS_TT_MEAN_RATE / (1.0 + TCL_MINUS_TT_MEAN_RATE);
38
39
/// Recommended experimental convention:
40
/// ```text
41
///     TL = TCL = TT at T0
42
/// ```
43
/// with:
44
/// ```text
45
///     T0 = 1977-01-01T00:00:00 TAI
46
///        = 1977-01-01T00:00:32.184 TT
47
/// ```
48
pub(crate) const TL_CONST0_S: f64 = 0.0;
49
50
#[inline]
51
0
pub fn tt_since_t77_to_tcl_since_t77(tt_since_t77: Duration) -> Duration {
52
    // Mean TCL model:
53
    //
54
    //     TCL - TCL0 = (TT - TT0) * (1 + k)
55
    //
56
    // Do not factor this into tt_since_t77 * (1.0 + k), matching the
57
    // style used for TCG/TCB to reduce avoidable rounding noise.
58
0
    tt_since_t77 + tt_since_t77 * TCL_MINUS_TT_MEAN_RATE
59
0
}
60
61
#[inline]
62
0
pub fn tcl_since_t77_to_tt_since_t77(tcl_since_t77: Duration) -> Duration {
63
    // Inverse of:
64
    //
65
    //     TCL = TT * (1 + k)
66
    //
67
    // so:
68
    //
69
    //     TT = TCL / (1 + k)
70
    //        = TCL * (1 - k / (1 + k))
71
0
    tcl_since_t77 - tcl_since_t77 * (TCL_MINUS_TT_MEAN_RATE / (1.0 + TCL_MINUS_TT_MEAN_RATE))
72
0
}
73
74
#[inline]
75
0
pub fn tcl_since_t77_to_tl_since_t77(tcl_since_t77: Duration) -> Duration {
76
    // Option iii:
77
    //
78
    //     TL = TCL + Δf * (TCL - TCL0) + const0
79
    //
80
    // with const0 = 0 and TCL0 = T0.
81
0
    tcl_since_t77 + tcl_since_t77 * TL_DELTA_F + TL_CONST0_S.seconds()
82
0
}
83
84
#[inline]
85
0
pub fn tl_since_t77_to_tcl_since_t77(tl_since_t77: Duration) -> Duration {
86
    // Since TL = TCL / (1 + k), the inverse is:
87
    //
88
    //     TCL = TL * (1 + k)
89
    //
90
    // const0 is zero in this convention.
91
0
    let tl_minus_const0 = tl_since_t77 - TL_CONST0_S.seconds();
92
0
    tl_minus_const0 + tl_minus_const0 * TCL_MINUS_TT_MEAN_RATE
93
0
}
94
95
#[cfg(test)]
96
mod ut_tcl {
97
    use super::*;
98
    use crate::{Epoch, TimeScale, TimeUnits};
99
100
    /// This test uses the private prime_epoch_offset, hence its definition here.
101
    #[test]
102
    fn tcl_accumulates_mean_drift_from_tt() {
103
        let tt = Epoch::from_gregorian_at_midnight(2024, 2, 29, TimeScale::TT);
104
        let tcl = tt.to_time_scale(TimeScale::TCL);
105
106
        let tt_since_t77 = tt.duration - TimeScale::TCL.prime_epoch_offset();
107
        let expected = tt_since_t77 * TCL_MINUS_TT_MEAN_RATE;
108
109
        let actual = tcl.duration - tt_since_t77;
110
111
        assert!(
112
            (actual - expected).abs() <= 1.nanoseconds(),
113
            "actual={actual}, expected={expected}"
114
        );
115
    }
116
}