use crate::epoch::SECONDS_PER_DAY;
pub const TAI_GPS_OFFSET: f64 = 19.0;
pub const GPS_EPOCH_TAI_TJT: f64 = 4244.0 + 19.0 / SECONDS_PER_DAY;
pub fn tai_to_gps(tai_seconds: f64) -> f64 {
tai_seconds - TAI_GPS_OFFSET
}
pub fn gps_to_tai(gps_seconds: f64) -> f64 {
gps_seconds + TAI_GPS_OFFSET
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct GpsTimeComponents {
pub seconds_of_day: f64,
pub seconds_of_week: f64,
pub day_of_week: i32,
pub rollover_count: i32,
pub week: i32,
pub rollover_count_13_bit: i32,
pub week_13_bit: i32,
}
pub fn gps_components(gps_days: f64) -> GpsTimeComponents {
let gps_time_int = gps_days.floor() as i32;
let seconds_of_day = (gps_days - gps_time_int as f64) * SECONDS_PER_DAY;
let rollover_count = gps_time_int.div_euclid(7168);
let gps_in_rollover = gps_time_int.rem_euclid(7168);
let rollover_count_13_bit = gps_time_int.div_euclid(57344);
let gps_in_13_bit_rollover = gps_time_int.rem_euclid(57344);
let week_13_bit = gps_in_13_bit_rollover / 7;
let week = gps_in_rollover / 7;
let day_of_week = gps_in_rollover % 7;
let seconds_of_week = day_of_week as f64 * SECONDS_PER_DAY + seconds_of_day;
GpsTimeComponents {
seconds_of_day,
seconds_of_week,
day_of_week,
rollover_count,
week,
rollover_count_13_bit,
week_13_bit,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn tai_gps_offset() {
assert_eq!(tai_to_gps(0.0), -19.0);
assert_eq!(tai_to_gps(100.0), 81.0);
assert_eq!(gps_to_tai(-19.0), 0.0);
}
#[test]
fn tai_gps_round_trip() {
let tai = 123456.789;
let gps = tai_to_gps(tai);
let back = gps_to_tai(gps);
assert!((back - tai).abs() < 1e-15);
}
#[test]
fn gps_components_basic() {
let c = gps_components(0.0);
assert_eq!(c.day_of_week, 0);
assert_eq!(c.week, 0);
assert_eq!(c.rollover_count, 0);
let c = gps_components(7.0);
assert_eq!(c.week, 1);
assert_eq!(c.day_of_week, 0);
let c = gps_components(7168.0);
assert_eq!(c.rollover_count, 1);
assert_eq!(c.week, 0);
assert_eq!(c.day_of_week, 0);
}
#[test]
fn gps_components_mid_week() {
let c = gps_components(3.5);
assert_eq!(c.day_of_week, 3);
assert!((c.seconds_of_day - 43200.0).abs() < 1e-6);
assert!(
(c.seconds_of_week - (3.0 * 86400.0 + 43200.0)).abs() < 1e-6,
"seconds_of_week: {}",
c.seconds_of_week
);
}
}