/rust/registry/src/index.crates.io-1949cf8c6b5b557f/hifitime-4.3.1/src/epoch/initializers.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 core::str::FromStr; |
12 | | |
13 | | use snafu::ResultExt; |
14 | | |
15 | | use crate::{ |
16 | | efmt::Format, errors::ParseSnafu, Duration, Epoch, HifitimeError, TimeScale, Unit, Weekday, |
17 | | ET_OFFSET_US, MJD_J1900, MJD_OFFSET, NANOSECONDS_PER_DAY, UNIX_REF_EPOCH, |
18 | | }; |
19 | | |
20 | | // Defines the methods that should be classmethods in Python, but must be redefined as per https://github.com/PyO3/pyo3/issues/1003#issuecomment-844433346 |
21 | | impl Epoch { |
22 | | #[must_use] |
23 | | /// Creates a new Epoch from a Duration as the time difference between this epoch and TAI reference epoch. |
24 | | #[cfg_attr(kani, kani::ensures(|result| result.time_scale == crate::TimeScale::TAI))] |
25 | 243 | pub const fn from_tai_duration(duration: Duration) -> Self { |
26 | 243 | Self { |
27 | 243 | duration, |
28 | 243 | time_scale: TimeScale::TAI, |
29 | 243 | } |
30 | 243 | } |
31 | | |
32 | 0 | pub fn to_duration_since_j1900(&self) -> Duration { |
33 | 0 | self.to_time_scale(TimeScale::TAI).duration |
34 | 0 | } |
35 | | |
36 | | #[must_use] |
37 | | /// Creates a new Epoch from its centuries and nanosecond since the TAI reference epoch. |
38 | | #[cfg_attr(kani, kani::ensures(|result| result.time_scale == crate::TimeScale::TAI))] |
39 | 0 | pub fn from_tai_parts(centuries: i16, nanoseconds: u64) -> Self { |
40 | 0 | Self::from_tai_duration(Duration::from_parts(centuries, nanoseconds)) |
41 | 0 | } |
42 | | |
43 | | #[must_use] |
44 | | /// Initialize an Epoch from the provided TAI seconds since 1900 January 01 at midnight |
45 | | #[cfg_attr(kani, kani::ensures(|result| result.time_scale == crate::TimeScale::TAI))] |
46 | | #[cfg_attr(kani, kani::requires(seconds.is_finite()))] |
47 | 243 | pub fn from_tai_seconds(seconds: f64) -> Self { |
48 | 243 | Self::from_tai_duration(seconds * Unit::Second) |
49 | 243 | } |
50 | | |
51 | | #[must_use] |
52 | | /// Initialize an Epoch from the provided TAI days since 1900 January 01 at midnight |
53 | | #[cfg_attr(kani, kani::ensures(|result| result.time_scale == crate::TimeScale::TAI))] |
54 | | #[cfg_attr(kani, kani::requires(days.is_finite()))] |
55 | 0 | pub fn from_tai_days(days: f64) -> Self { |
56 | 0 | Self::from_tai_duration(days * Unit::Day) |
57 | 0 | } |
58 | | |
59 | | #[must_use] |
60 | | /// Initialize an Epoch from the provided UTC seconds since 1900 January 01 at midnight |
61 | | #[cfg_attr(kani, kani::ensures(|result| result.time_scale == crate::TimeScale::UTC))] |
62 | 26.9k | pub fn from_utc_duration(duration: Duration) -> Self { |
63 | 26.9k | Self::from_duration(duration, TimeScale::UTC) |
64 | 26.9k | } |
65 | | |
66 | | #[must_use] |
67 | | /// Initialize an Epoch from the provided UTC seconds since 1900 January 01 at midnight |
68 | | #[cfg_attr(kani, kani::ensures(|result| result.time_scale == crate::TimeScale::UTC))] |
69 | | #[cfg_attr(kani, kani::requires(seconds.is_finite()))] |
70 | 3.07k | pub fn from_utc_seconds(seconds: f64) -> Self { |
71 | 3.07k | Self::from_utc_duration(seconds * Unit::Second) |
72 | 3.07k | } |
73 | | |
74 | | #[must_use] |
75 | | /// Initialize an Epoch from the provided UTC days since 1900 January 01 at midnight |
76 | | #[cfg_attr(kani, kani::ensures(|result| result.time_scale == crate::TimeScale::UTC))] |
77 | | #[cfg_attr(kani, kani::requires(days.is_finite()))] |
78 | 0 | pub fn from_utc_days(days: f64) -> Self { |
79 | 0 | Self::from_utc_duration(days * Unit::Day) |
80 | 0 | } |
81 | | |
82 | | #[must_use] |
83 | | /// Initialize an Epoch from the provided duration since 1980 January 6 at midnight |
84 | | #[cfg_attr(kani, kani::ensures(|result| result.time_scale == crate::TimeScale::GPST))] |
85 | 0 | pub fn from_gpst_duration(duration: Duration) -> Self { |
86 | 0 | Self::from_duration(duration, TimeScale::GPST) |
87 | 0 | } |
88 | | |
89 | | #[must_use] |
90 | | /// Initialize an Epoch from the provided duration since 1980 January 6 at midnight |
91 | | #[cfg_attr(kani, kani::ensures(|result| result.time_scale == crate::TimeScale::QZSST))] |
92 | 0 | pub fn from_qzsst_duration(duration: Duration) -> Self { |
93 | 0 | Self::from_duration(duration, TimeScale::QZSST) |
94 | 0 | } |
95 | | |
96 | | #[must_use] |
97 | | /// Initialize an Epoch from the provided duration since August 21st 1999 midnight |
98 | | #[cfg_attr(kani, kani::ensures(|result| result.time_scale == crate::TimeScale::GST))] |
99 | 0 | pub fn from_gst_duration(duration: Duration) -> Self { |
100 | 0 | Self::from_duration(duration, TimeScale::GST) |
101 | 0 | } |
102 | | |
103 | | #[must_use] |
104 | | /// Initialize an Epoch from the provided duration since January 1st midnight |
105 | | #[cfg_attr(kani, kani::ensures(|result| result.time_scale == crate::TimeScale::BDT))] |
106 | 0 | pub fn from_bdt_duration(duration: Duration) -> Self { |
107 | 0 | Self::from_duration(duration, TimeScale::BDT) |
108 | 0 | } |
109 | | |
110 | | #[must_use] |
111 | | #[cfg_attr(kani, kani::ensures(|result| result.time_scale == crate::TimeScale::TAI))] |
112 | | #[cfg_attr(kani, kani::requires(days.is_finite()))] |
113 | 205 | pub fn from_mjd_tai(days: f64) -> Self { |
114 | 205 | Self::from_mjd_in_time_scale(days, TimeScale::TAI) |
115 | 205 | } |
116 | | |
117 | | #[cfg_attr(kani, kani::ensures(|result| result.time_scale == time_scale))] |
118 | | #[cfg_attr(kani, kani::requires(days.is_finite()))] |
119 | 1.66k | pub fn from_mjd_in_time_scale(days: f64, time_scale: TimeScale) -> Self { |
120 | 1.66k | Self { |
121 | 1.66k | duration: (days - MJD_J1900) * Unit::Day, |
122 | 1.66k | time_scale, |
123 | 1.66k | } |
124 | 1.66k | } |
125 | | |
126 | | #[must_use] |
127 | | #[cfg_attr(kani, kani::ensures(|result| result.time_scale == crate::TimeScale::UTC))] |
128 | | #[cfg_attr(kani, kani::requires(days.is_finite()))] |
129 | 0 | pub fn from_mjd_utc(days: f64) -> Self { |
130 | 0 | Self::from_mjd_in_time_scale(days, TimeScale::UTC) |
131 | 0 | } |
132 | | #[must_use] |
133 | | #[cfg_attr(kani, kani::ensures(|result| result.time_scale == crate::TimeScale::GPST))] |
134 | | #[cfg_attr(kani, kani::requires(days.is_finite()))] |
135 | 0 | pub fn from_mjd_gpst(days: f64) -> Self { |
136 | 0 | Self::from_mjd_in_time_scale(days, TimeScale::GPST) |
137 | 0 | } |
138 | | #[must_use] |
139 | | #[cfg_attr(kani, kani::ensures(|result| result.time_scale == crate::TimeScale::QZSST))] |
140 | | #[cfg_attr(kani, kani::requires(days.is_finite()))] |
141 | 0 | pub fn from_mjd_qzsst(days: f64) -> Self { |
142 | 0 | Self::from_mjd_in_time_scale(days, TimeScale::QZSST) |
143 | 0 | } |
144 | | #[must_use] |
145 | | #[cfg_attr(kani, kani::ensures(|result| result.time_scale == crate::TimeScale::GST))] |
146 | | #[cfg_attr(kani, kani::requires(days.is_finite()))] |
147 | 0 | pub fn from_mjd_gst(days: f64) -> Self { |
148 | 0 | Self::from_mjd_in_time_scale(days, TimeScale::GST) |
149 | 0 | } |
150 | | #[must_use] |
151 | | #[cfg_attr(kani, kani::ensures(|result| result.time_scale == crate::TimeScale::BDT))] |
152 | | #[cfg_attr(kani, kani::requires(days.is_finite()))] |
153 | 0 | pub fn from_mjd_bdt(days: f64) -> Self { |
154 | 0 | Self::from_mjd_in_time_scale(days, TimeScale::BDT) |
155 | 0 | } |
156 | | |
157 | | #[must_use] |
158 | | #[cfg_attr(kani, kani::ensures(|result| result.time_scale == crate::TimeScale::TAI))] |
159 | | #[cfg_attr(kani, kani::requires(days.is_finite()))] |
160 | 982 | pub fn from_jde_tai(days: f64) -> Self { |
161 | 982 | Self::from_jde_in_time_scale(days, TimeScale::TAI) |
162 | 982 | } |
163 | | |
164 | | #[cfg_attr(kani, kani::ensures(|result| result.time_scale == time_scale))] |
165 | | #[cfg_attr(kani, kani::requires(days.is_finite()))] |
166 | 1.45k | pub fn from_jde_in_time_scale(days: f64, time_scale: TimeScale) -> Self { |
167 | 1.45k | Self { |
168 | 1.45k | duration: (days - MJD_J1900 - MJD_OFFSET) * Unit::Day - time_scale.prime_epoch_offset(), |
169 | 1.45k | time_scale, |
170 | 1.45k | } |
171 | 1.45k | } |
172 | | |
173 | | #[must_use] |
174 | | #[cfg_attr(kani, kani::ensures(|result| result.time_scale == crate::TimeScale::UTC))] |
175 | | #[cfg_attr(kani, kani::requires(days.is_finite()))] |
176 | 476 | pub fn from_jde_utc(days: f64) -> Self { |
177 | 476 | Self::from_jde_in_time_scale(days, TimeScale::UTC) |
178 | 476 | } |
179 | | #[must_use] |
180 | | #[cfg_attr(kani, kani::ensures(|result| result.time_scale == crate::TimeScale::GPST))] |
181 | | #[cfg_attr(kani, kani::requires(days.is_finite()))] |
182 | 0 | pub fn from_jde_gpst(days: f64) -> Self { |
183 | 0 | Self::from_jde_in_time_scale(days, TimeScale::GPST) |
184 | 0 | } |
185 | | #[must_use] |
186 | | #[cfg_attr(kani, kani::ensures(|result| result.time_scale == crate::TimeScale::QZSST))] |
187 | | #[cfg_attr(kani, kani::requires(days.is_finite()))] |
188 | 0 | pub fn from_jde_qzsst(days: f64) -> Self { |
189 | 0 | Self::from_jde_in_time_scale(days, TimeScale::QZSST) |
190 | 0 | } |
191 | | #[must_use] |
192 | | #[cfg_attr(kani, kani::ensures(|result| result.time_scale == crate::TimeScale::GST))] |
193 | | #[cfg_attr(kani, kani::requires(days.is_finite()))] |
194 | 0 | pub fn from_jde_gst(days: f64) -> Self { |
195 | 0 | Self::from_jde_in_time_scale(days, TimeScale::GST) |
196 | 0 | } |
197 | | #[must_use] |
198 | | #[cfg_attr(kani, kani::ensures(|result| result.time_scale == crate::TimeScale::BDT))] |
199 | | #[cfg_attr(kani, kani::requires(days.is_finite()))] |
200 | 0 | pub fn from_jde_bdt(days: f64) -> Self { |
201 | 0 | Self::from_jde_in_time_scale(days, TimeScale::BDT) |
202 | 0 | } |
203 | | |
204 | | #[must_use] |
205 | | /// Initialize an Epoch from the provided TT seconds (approximated to 32.184s delta from TAI) |
206 | | #[cfg_attr(kani, kani::ensures(|result| result.time_scale == crate::TimeScale::TT))] |
207 | | #[cfg_attr(kani, kani::requires(seconds.is_finite()))] |
208 | 37 | pub fn from_tt_seconds(seconds: f64) -> Self { |
209 | 37 | Self::from_tt_duration(seconds * Unit::Second) |
210 | 37 | } |
211 | | |
212 | | #[must_use] |
213 | | /// Initialize an Epoch from the provided TT seconds (approximated to 32.184s delta from TAI) |
214 | | #[cfg_attr(kani, kani::ensures(|result| result.time_scale == crate::TimeScale::TT))] |
215 | 37 | pub fn from_tt_duration(duration: Duration) -> Self { |
216 | 37 | Self::from_duration(duration, TimeScale::TT) |
217 | 37 | } |
218 | | |
219 | | #[must_use] |
220 | | /// Initialize an Epoch from the Ephemeris Time seconds past 2000 JAN 01 (J2000 reference) |
221 | | #[cfg_attr(kani, kani::ensures(|result| result.time_scale == crate::TimeScale::ET))] |
222 | | #[cfg_attr(kani, kani::requires(seconds_since_j2000.is_finite()))] |
223 | 156k | pub fn from_et_seconds(seconds_since_j2000: f64) -> Epoch { |
224 | 156k | Self::from_et_duration(seconds_since_j2000 * Unit::Second) |
225 | 156k | } |
226 | | |
227 | | /// Initializes an Epoch from the duration between J2000 and the current epoch as per NAIF SPICE. |
228 | | /// |
229 | | /// # Limitation |
230 | | /// This method uses a Newton Raphson iteration to find the appropriate TAI duration. This method is only accuracy to a few nanoseconds. |
231 | | /// Hence, when calling `as_et_duration()` and re-initializing it with `from_et_duration` you may have a few nanoseconds of difference (expect less than 10 ns). |
232 | | /// |
233 | | /// # Warning |
234 | | /// The et2utc function of NAIF SPICE will assume that there are 9 leap seconds before 01 JAN 1972, |
235 | | /// as this date introduces 10 leap seconds. At the time of writing, this does _not_ seem to be in |
236 | | /// line with IERS and the documentation in the leap seconds list. |
237 | | /// |
238 | | /// In order to match SPICE, the as_et_duration() function will manually get rid of that difference. |
239 | | #[must_use] |
240 | | #[cfg_attr(kani, kani::ensures(|result| result.time_scale == crate::TimeScale::ET))] |
241 | 156k | pub fn from_et_duration(duration_since_j2000: Duration) -> Self { |
242 | 156k | Self::from_duration(duration_since_j2000, TimeScale::ET) |
243 | 156k | } |
244 | | |
245 | | #[must_use] |
246 | | /// Initialize an Epoch from Dynamic Barycentric Time (TDB) seconds past 2000 JAN 01 midnight (difference than SPICE) |
247 | | /// NOTE: This uses the ESA algorithm, which is a notch more complicated than the SPICE algorithm, but more precise. |
248 | | /// In fact, SPICE algorithm is precise +/- 30 microseconds for a century whereas ESA algorithm should be exactly correct. |
249 | | #[cfg_attr(kani, kani::ensures(|result| result.time_scale == crate::TimeScale::TDB))] |
250 | | #[cfg_attr(kani, kani::requires(seconds_j2000.is_finite()))] |
251 | 110 | pub fn from_tdb_seconds(seconds_j2000: f64) -> Epoch { |
252 | 110 | Self::from_tdb_duration(seconds_j2000 * Unit::Second) |
253 | 110 | } |
254 | | |
255 | | #[must_use] |
256 | | /// Initialize from Dynamic Barycentric Time (TDB) (same as SPICE ephemeris time) whose epoch is 2000 JAN 01 noon TAI. |
257 | | #[cfg_attr(kani, kani::ensures(|result| result.time_scale == crate::TimeScale::TDB))] |
258 | 110 | pub fn from_tdb_duration(duration_since_j2000: Duration) -> Epoch { |
259 | 110 | Self::from_duration(duration_since_j2000, TimeScale::TDB) |
260 | 110 | } |
261 | | |
262 | | #[must_use] |
263 | | /// Initialize from the JDE days |
264 | | #[cfg_attr(kani, kani::requires(days.is_finite()))] |
265 | 31 | pub fn from_jde_et(days: f64) -> Self { |
266 | 31 | Self::from_jde_tdb(days) |
267 | 31 | } |
268 | | |
269 | | #[must_use] |
270 | | #[cfg_attr(kani, kani::requires(days.is_finite()))] |
271 | | /// Initialize from Dynamic Barycentric Time (TDB) (same as SPICE ephemeris time) in JD days |
272 | 643 | pub fn from_jde_tdb(days: f64) -> Self { |
273 | 643 | Self::from_jde_tai(days) - Unit::Microsecond * ET_OFFSET_US |
274 | 643 | } |
275 | | |
276 | | #[must_use] |
277 | | /// Initialize an Epoch from the number of seconds since the GPS Time Epoch, |
278 | | /// defined as UTC midnight of January 5th to 6th 1980 (cf. <https://gssc.esa.int/navipedia/index.php/Time_References_in_GNSS#GPS_Time_.28GPST.29>). |
279 | | #[cfg_attr(kani, kani::ensures(|result| result.time_scale == crate::TimeScale::GPST))] |
280 | | #[cfg_attr(kani, kani::requires(seconds.is_finite()))] |
281 | 0 | pub fn from_gpst_seconds(seconds: f64) -> Self { |
282 | 0 | Self::from_duration(seconds * Unit::Second, TimeScale::GPST) |
283 | 0 | } |
284 | | |
285 | | #[must_use] |
286 | | /// Initialize an Epoch from the number of days since the GPS Time Epoch, |
287 | | /// defined as UTC midnight of January 5th to 6th 1980 (cf. <https://gssc.esa.int/navipedia/index.php/Time_References_in_GNSS#GPS_Time_.28GPST.29>). |
288 | | #[cfg_attr(kani, kani::ensures(|result| result.time_scale == crate::TimeScale::GPST))] |
289 | | #[cfg_attr(kani, kani::requires(days.is_finite()))] |
290 | 0 | pub fn from_gpst_days(days: f64) -> Self { |
291 | 0 | Self::from_duration(days * Unit::Day, TimeScale::GPST) |
292 | 0 | } |
293 | | |
294 | | #[must_use] |
295 | | /// Initialize an Epoch from the number of nanoseconds since the GPS Time Epoch, |
296 | | /// defined as UTC midnight of January 5th to 6th 1980 (cf. <https://gssc.esa.int/navipedia/index.php/Time_References_in_GNSS#GPS_Time_.28GPST.29>). |
297 | | /// This may be useful for time keeping devices that use GPS as a time source. |
298 | | #[cfg_attr(kani, kani::ensures(|result| result.time_scale == crate::TimeScale::GPST))] |
299 | 0 | pub fn from_gpst_nanoseconds(nanoseconds: u64) -> Self { |
300 | 0 | Self::from_duration(Duration::from_parts(0, nanoseconds), TimeScale::GPST) |
301 | 0 | } |
302 | | |
303 | | #[must_use] |
304 | | /// Initialize an Epoch from the number of seconds since the QZSS Time Epoch, |
305 | | /// defined as UTC midnight of January 5th to 6th 1980 (cf. <https://gssc.esa.int/navipedia/index.php/Time_References_in_GNSS#GPS_Time_.28GPST.29>). |
306 | | #[cfg_attr(kani, kani::ensures(|result| result.time_scale == crate::TimeScale::QZSST))] |
307 | | #[cfg_attr(kani, kani::requires(seconds.is_finite()))] |
308 | 0 | pub fn from_qzsst_seconds(seconds: f64) -> Self { |
309 | 0 | Self::from_duration(seconds * Unit::Second, TimeScale::QZSST) |
310 | 0 | } |
311 | | |
312 | | #[must_use] |
313 | | /// Initialize an Epoch from the number of days since the QZSS Time Epoch, |
314 | | /// defined as UTC midnight of January 5th to 6th 1980 (cf. <https://gssc.esa.int/navipedia/index.php/Time_References_in_GNSS#GPS_Time_.28GPST.29>). |
315 | | #[cfg_attr(kani, kani::ensures(|result| result.time_scale == crate::TimeScale::QZSST))] |
316 | | #[cfg_attr(kani, kani::requires(days.is_finite()))] |
317 | 0 | pub fn from_qzsst_days(days: f64) -> Self { |
318 | 0 | Self::from_duration(days * Unit::Day, TimeScale::QZSST) |
319 | 0 | } |
320 | | |
321 | | #[must_use] |
322 | | /// Initialize an Epoch from the number of nanoseconds since the QZSS Time Epoch, |
323 | | /// defined as UTC midnight of January 5th to 6th 1980 (cf. <https://gssc.esa.int/navipedia/index.php/Time_References_in_GNSS#GPS_Time_.28GPST.29>). |
324 | | /// This may be useful for time keeping devices that use QZSS as a time source. |
325 | | #[cfg_attr(kani, kani::ensures(|result| result.time_scale == crate::TimeScale::QZSST))] |
326 | 0 | pub fn from_qzsst_nanoseconds(nanoseconds: u64) -> Self { |
327 | 0 | Self::from_duration(Duration::from_parts(0, nanoseconds), TimeScale::QZSST) |
328 | 0 | } |
329 | | |
330 | | #[must_use] |
331 | | /// Initialize an Epoch from the number of seconds since the GST Time Epoch, |
332 | | /// starting August 21st 1999 midnight (UTC) |
333 | | /// (cf. <https://gssc.esa.int/navipedia/index.php/Time_References_in_GNSS>). |
334 | | #[cfg_attr(kani, kani::ensures(|result| result.time_scale == crate::TimeScale::GST))] |
335 | | #[cfg_attr(kani, kani::requires(seconds.is_finite()))] |
336 | 0 | pub fn from_gst_seconds(seconds: f64) -> Self { |
337 | 0 | Self::from_duration(seconds * Unit::Second, TimeScale::GST) |
338 | 0 | } |
339 | | |
340 | | #[must_use] |
341 | | /// Initialize an Epoch from the number of days since the GST Time Epoch, |
342 | | /// starting August 21st 1999 midnight (UTC) |
343 | | /// (cf. <https://gssc.esa.int/navipedia/index.php/Time_References_in_GNSS>) |
344 | | #[cfg_attr(kani, kani::ensures(|result| result.time_scale == crate::TimeScale::GST))] |
345 | | #[cfg_attr(kani, kani::requires(days.is_finite()))] |
346 | 0 | pub fn from_gst_days(days: f64) -> Self { |
347 | 0 | Self::from_duration(days * Unit::Day, TimeScale::GST) |
348 | 0 | } |
349 | | |
350 | | #[must_use] |
351 | | /// Initialize an Epoch from the number of nanoseconds since the GPS Time Epoch, |
352 | | /// starting August 21st 1999 midnight (UTC) |
353 | | /// (cf. <https://gssc.esa.int/navipedia/index.php/Time_References_in_GNSS>) |
354 | | #[cfg_attr(kani, kani::ensures(|result| result.time_scale == crate::TimeScale::GST))] |
355 | 0 | pub fn from_gst_nanoseconds(nanoseconds: u64) -> Self { |
356 | 0 | Self::from_duration(Duration::from_parts(0, nanoseconds), TimeScale::GST) |
357 | 0 | } |
358 | | |
359 | | #[must_use] |
360 | | /// Initialize an Epoch from the number of seconds since the BDT Time Epoch, |
361 | | /// starting on January 1st 2006 (cf. <https://gssc.esa.int/navipedia/index.php/Time_References_in_GNSS>) |
362 | | #[cfg_attr(kani, kani::ensures(|result| result.time_scale == crate::TimeScale::BDT))] |
363 | | #[cfg_attr(kani, kani::requires(seconds.is_finite()))] |
364 | 0 | pub fn from_bdt_seconds(seconds: f64) -> Self { |
365 | 0 | Self::from_duration(seconds * Unit::Second, TimeScale::BDT) |
366 | 0 | } |
367 | | |
368 | | #[must_use] |
369 | | /// Initialize an Epoch from the number of days since the BDT Time Epoch, |
370 | | /// starting on January 1st 2006 (cf. <https://gssc.esa.int/navipedia/index.php/Time_References_in_GNSS>) |
371 | | #[cfg_attr(kani, kani::ensures(|result| result.time_scale == crate::TimeScale::BDT))] |
372 | | #[cfg_attr(kani, kani::requires(days.is_finite()))] |
373 | 0 | pub fn from_bdt_days(days: f64) -> Self { |
374 | 0 | Self::from_duration(days * Unit::Day, TimeScale::BDT) |
375 | 0 | } |
376 | | |
377 | | #[must_use] |
378 | | /// Initialize an Epoch from the number of nanoseconds since the BDT Time Epoch, |
379 | | /// starting on January 1st 2006 (cf. <https://gssc.esa.int/navipedia/index.php/Time_References_in_GNSS>). |
380 | | /// This may be useful for time keeping devices that use BDT as a time source. |
381 | | #[cfg_attr(kani, kani::ensures(|result| result.time_scale == crate::TimeScale::BDT))] |
382 | 0 | pub fn from_bdt_nanoseconds(nanoseconds: u64) -> Self { |
383 | 0 | Self::from_duration(Duration::from_parts(0, nanoseconds), TimeScale::BDT) |
384 | 0 | } |
385 | | |
386 | | #[must_use] |
387 | | /// Initialize an Epoch from the provided IEEE 1588-2008 (PTPv2) duration since TAI midnight 1970 January 01. |
388 | | /// PTP uses the TAI timescale but with the Unix Epoch for compatibility with unix systems. |
389 | | #[cfg_attr(kani, kani::ensures(|result| result.time_scale == crate::TimeScale::TAI))] |
390 | 0 | pub fn from_ptp_duration(duration: Duration) -> Self { |
391 | 0 | Self::from_duration(UNIX_REF_EPOCH.to_utc_duration() + duration, TimeScale::TAI) |
392 | 0 | } |
393 | | |
394 | | #[must_use] |
395 | | /// Initialize an Epoch from the provided IEEE 1588-2008 (PTPv2) second timestamp since TAI midnight 1970 January 01. |
396 | | /// PTP uses the TAI timescale but with the Unix Epoch for compatibility with unix systems. |
397 | | #[cfg_attr(kani, kani::ensures(|result| result.time_scale == crate::TimeScale::TAI))] |
398 | | #[cfg_attr(kani, kani::requires(seconds.is_finite()))] |
399 | 0 | pub fn from_ptp_seconds(seconds: f64) -> Self { |
400 | 0 | Self::from_ptp_duration(seconds * Unit::Second) |
401 | 0 | } |
402 | | |
403 | | #[must_use] |
404 | | /// Initialize an Epoch from the provided IEEE 1588-2008 (PTPv2) nanoseconds timestamp since TAI midnight 1970 January 01. |
405 | | /// PTP uses the TAI timescale but with the Unix Epoch for compatibility with unix systems. |
406 | | #[cfg_attr(kani, kani::ensures(|result| result.time_scale == crate::TimeScale::TAI))] |
407 | 0 | pub fn from_ptp_nanoseconds(nanoseconds: u64) -> Self { |
408 | 0 | Self::from_ptp_duration(Duration::from_parts(0, nanoseconds)) |
409 | 0 | } |
410 | | |
411 | | #[must_use] |
412 | | /// Initialize an Epoch from the provided duration since UTC midnight 1970 January 01. |
413 | 23.9k | pub fn from_unix_duration(duration: Duration) -> Self { |
414 | 23.9k | Self::from_utc_duration(UNIX_REF_EPOCH.to_utc_duration() + duration) |
415 | 23.9k | } |
416 | | |
417 | | #[must_use] |
418 | | /// Initialize an Epoch from the provided UNIX second timestamp since UTC midnight 1970 January 01. |
419 | | #[cfg_attr(kani, kani::requires(seconds.is_finite()))] |
420 | 0 | pub fn from_unix_seconds(seconds: f64) -> Self { |
421 | 0 | Self::from_utc_duration(UNIX_REF_EPOCH.to_utc_duration() + seconds * Unit::Second) |
422 | 0 | } |
423 | | #[must_use] |
424 | | /// Initialize an Epoch from the provided UNIX millisecond timestamp since UTC midnight 1970 January 01. |
425 | | #[cfg_attr(kani, kani::requires(millisecond.is_finite()))] |
426 | 0 | pub fn from_unix_milliseconds(millisecond: f64) -> Self { |
427 | 0 | Self::from_utc_duration(UNIX_REF_EPOCH.to_utc_duration() + millisecond * Unit::Millisecond) |
428 | 0 | } |
429 | | |
430 | | /// Initializes an Epoch from the provided Format. |
431 | 0 | pub fn from_str_with_format(s_in: &str, format: Format) -> Result<Self, HifitimeError> { |
432 | 0 | format.parse(s_in) |
433 | 0 | } |
434 | | |
435 | | /// Initializes an Epoch from the Format as a string. |
436 | 0 | pub fn from_format_str(s_in: &str, format_str: &str) -> Result<Self, HifitimeError> { |
437 | 0 | Format::from_str(format_str) |
438 | 0 | .with_context(|_| ParseSnafu { |
439 | | details: "when using format string", |
440 | 0 | })? |
441 | 0 | .parse(s_in) |
442 | 0 | } |
443 | | |
444 | | /// Builds an Epoch from given `week`: elapsed weeks counter into the desired Time scale, and the amount of nanoseconds within that week. |
445 | | /// For example, this is how GPS vehicles describe a GPST epoch. |
446 | | /// |
447 | | /// Note that this constructor relies on 128 bit integer math and may be slow on embedded devices. |
448 | | #[must_use] |
449 | | #[cfg_attr(kani, kani::ensures(|result| result.time_scale == time_scale))] |
450 | 0 | pub fn from_time_of_week(week: u32, nanoseconds: u64, time_scale: TimeScale) -> Self { |
451 | 0 | let mut nanos = i128::from(nanoseconds); |
452 | 0 | nanos += i128::from(week) * Weekday::DAYS_PER_WEEK_I128 * i128::from(NANOSECONDS_PER_DAY); |
453 | 0 | let duration = Duration::from_total_nanoseconds(nanos); |
454 | 0 | Self::from_duration(duration, time_scale) |
455 | 0 | } |
456 | | |
457 | | #[must_use] |
458 | | /// Builds a UTC Epoch from given `week`: elapsed weeks counter and "ns" amount of nanoseconds since closest Sunday Midnight. |
459 | | #[cfg_attr(kani, kani::ensures(|result| result.time_scale == crate::TimeScale::UTC))] |
460 | 0 | pub fn from_time_of_week_utc(week: u32, nanoseconds: u64) -> Self { |
461 | 0 | Self::from_time_of_week(week, nanoseconds, TimeScale::UTC) |
462 | 0 | } |
463 | | |
464 | | #[must_use] |
465 | | /// Builds an Epoch from the provided year, days in the year, and a time scale. |
466 | | /// |
467 | | /// # Limitations |
468 | | /// In the TDB or ET time scales, there may be an error of up to 750 nanoseconds when initializing an Epoch this way. |
469 | | /// This is because we first initialize the epoch in Gregorian scale and then apply the TDB/ET offset, but that offset actually depends on the precise time. |
470 | | /// |
471 | | /// # Day couting behavior |
472 | | /// |
473 | | /// The day counter starts at 01, in other words, 01 January is day 1 of the counter, as per the GPS specificiations. |
474 | | /// |
475 | 0 | pub fn from_day_of_year(year: i32, days: f64, time_scale: TimeScale) -> Self { |
476 | 0 | let start_of_year = Self::from_gregorian(year, 1, 1, 0, 0, 0, 0, time_scale); |
477 | 0 | start_of_year + (days - 1.0) * Unit::Day |
478 | 0 | } |
479 | | } |