deep_time/dt/to_gps.rs
1use crate::{ATTOS_PER_SEC_I128, ATTOS_PER_WEEK, Dt, Real, SEC_PER_DAYI64, SEC_PER_WEEK, TSpan};
2
3impl Dt {
4 /// Returns the GPS week number and exact Time of Week (TOW) for this instant
5 /// when expressed in GPS Time (GPS).
6 ///
7 /// This is the format used by virtually all GNSS receivers, RINEX observation
8 /// files, NMEA sentences, and raw satellite navigation messages.
9 ///
10 /// - **GPS week number**: Full (untruncated) count of 7-day weeks since the
11 /// traditional GPS reference epoch **1980-01-06 00:00:00 GPS**.
12 /// Returned as `i64` (effectively unlimited range).
13 /// - **Time of Week (TOW)**: Exact elapsed time since the start of that GPS
14 /// week, returned as a [`TSpan`] in the range `[0, 604800)` seconds.
15 ///
16 /// GPS weeks always begin on **Sunday 00:00:00 GPS**.
17 ///
18 /// # Correctness notes
19 ///
20 /// - The calculation is performed entirely on the **GPS** scale.
21 /// - GPS has **no leap seconds** (it is a continuous time scale).
22 /// - Leap seconds are automatically handled when converting from UTC or
23 /// other scales via `to_type(Scale::GPS)`.
24 /// - The result is **exact** (attosecond precision) and independent of any
25 /// calendar or timezone rules.
26 pub const fn to_gps_wk_and_tow(&self) -> (i64, TSpan) {
27 let elapsed = self.to_tai_since(Self::GPS_EPOCH);
28 let total_attos = elapsed.to_attos();
29 let wk = (total_attos / ATTOS_PER_WEEK) as i64;
30 let tow_attos = total_attos % ATTOS_PER_WEEK;
31 (wk, TSpan::from_attos(tow_attos))
32 }
33
34 /// Returns the day of the GPS week (0 = Sunday, 1 = Monday, …, 6 = Saturday).
35 ///
36 /// This is computed directly from GPS Time and is independent of the
37 /// Gregorian calendar.
38 pub const fn to_gps_day_of_wk(&self) -> u8 {
39 let elapsed = self.to_tai_since(Self::GPS_EPOCH);
40 let total_sec = elapsed.to_attos() / ATTOS_PER_SEC_I128;
41 let secs_into_wk = total_sec.rem_euclid(SEC_PER_WEEK as i128);
42 (secs_into_wk / SEC_PER_DAYI64 as i128) as u8
43 }
44
45 /// Returns the Time of Week (TOW) as a floating-point value in seconds.
46 ///
47 /// This is a convenience method for code that prefers `f64` / `Real`.
48 /// For full attosecond precision use [`Self::to_gps_wk_and_tow`].
49 #[inline]
50 pub const fn to_gps_tow_f(&self) -> Real {
51 let (_, tow) = self.to_gps_wk_and_tow();
52 tow.to_sec_f()
53 }
54
55 /// Returns only the GPS week number (full, untruncated).
56 #[inline]
57 pub const fn to_gps_week_number(&self) -> i64 {
58 self.to_gps_wk_and_tow().0
59 }
60}