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
use crate::{ATTOS_PER_SEC_I128, ATTOS_PER_WEEK, Dt, Real, SEC_PER_DAYI64, SEC_PER_WEEK, TSpan};
impl Dt {
/// Returns the GPS week number and exact Time of Week (TOW) for this instant
/// when expressed in GPS Time (GPS).
///
/// This is the format used by virtually all GNSS receivers, RINEX observation
/// files, NMEA sentences, and raw satellite navigation messages.
///
/// - **GPS week number**: Full (untruncated) count of 7-day weeks since the
/// traditional GPS reference epoch **1980-01-06 00:00:00 GPS**.
/// Returned as `i64` (effectively unlimited range).
/// - **Time of Week (TOW)**: Exact elapsed time since the start of that GPS
/// week, returned as a [`TSpan`] in the range `[0, 604800)` seconds.
///
/// GPS weeks always begin on **Sunday 00:00:00 GPS**.
///
/// # Correctness notes
///
/// - The calculation is performed entirely on the **GPS** scale.
/// - GPS has **no leap seconds** (it is a continuous time scale).
/// - Leap seconds are automatically handled when converting from UTC or
/// other scales via `to_type(Scale::GPS)`.
/// - The result is **exact** (attosecond precision) and independent of any
/// calendar or timezone rules.
pub const fn to_gps_wk_and_tow(&self) -> (i64, TSpan) {
let elapsed = self.to_tai_since(Self::GPS_EPOCH);
let total_attos = elapsed.to_attos();
let wk = (total_attos / ATTOS_PER_WEEK) as i64;
let tow_attos = total_attos % ATTOS_PER_WEEK;
(wk, TSpan::from_attos(tow_attos))
}
/// Returns the day of the GPS week (0 = Sunday, 1 = Monday, …, 6 = Saturday).
///
/// This is computed directly from GPS Time and is independent of the
/// Gregorian calendar.
pub const fn to_gps_day_of_wk(&self) -> u8 {
let elapsed = self.to_tai_since(Self::GPS_EPOCH);
let total_sec = elapsed.to_attos() / ATTOS_PER_SEC_I128;
let secs_into_wk = total_sec.rem_euclid(SEC_PER_WEEK as i128);
(secs_into_wk / SEC_PER_DAYI64 as i128) as u8
}
/// Returns the Time of Week (TOW) as a floating-point value in seconds.
///
/// This is a convenience method for code that prefers `f64` / `Real`.
/// For full attosecond precision use [`Self::to_gps_wk_and_tow`].
#[inline]
pub const fn to_gps_tow_f(&self) -> Real {
let (_, tow) = self.to_gps_wk_and_tow();
tow.to_sec_f()
}
/// Returns only the GPS week number (full, untruncated).
#[inline]
pub const fn to_gps_week_number(&self) -> i64 {
self.to_gps_wk_and_tow().0
}
}