doris_rs/
epoch.rs

1use crate::prelude::{Epoch, ParsingError, TimeScale};
2
3/// Parses [Epoch] from string, interprated in [TimeScale]
4pub(crate) fn parse_in_timescale(content: &str, ts: TimeScale) -> Result<Epoch, ParsingError> {
5    let mut y = 0_i32;
6    let mut m = 0_u8;
7    let mut d = 0_u8;
8    let mut hh = 0_u8;
9    let mut mm = 0_u8;
10    let mut ss = 0_u8;
11    let mut ns = 0_u64;
12
13    if content.split_ascii_whitespace().count() < 6 {
14        return Err(ParsingError::EpochFormat);
15    }
16
17    for (field_index, item) in content.split_ascii_whitespace().enumerate() {
18        match field_index {
19            0 => {
20                y = item.parse::<i32>().map_err(|_| ParsingError::EpochFormat)?;
21
22                /* old RINEX problem: YY sometimes encoded on two digits */
23                if y > 79 && y <= 99 {
24                    y += 1900;
25                } else if y < 79 {
26                    y += 2000;
27                }
28            },
29            1 => {
30                m = item.parse::<u8>().map_err(|_| ParsingError::EpochFormat)?;
31            },
32            2 => {
33                d = item.parse::<u8>().map_err(|_| ParsingError::EpochFormat)?;
34            },
35            3 => {
36                hh = item.parse::<u8>().map_err(|_| ParsingError::EpochFormat)?;
37            },
38            4 => {
39                mm = item.parse::<u8>().map_err(|_| ParsingError::EpochFormat)?;
40            },
41            5 => {
42                if let Some(dot) = item.find('.') {
43                    let is_nav = item.trim().len() < 7;
44
45                    ss = item[..dot]
46                        .trim()
47                        .parse::<u8>()
48                        .map_err(|_| ParsingError::EpochFormat)?;
49
50                    let nanos = item[dot + 1..].trim();
51
52                    ns = nanos
53                        .parse::<u64>()
54                        .map_err(|_| ParsingError::EpochFormat)?;
55
56                    if is_nav {
57                        // NAV RINEX : 100ms precision
58                        ns *= 100_000_000;
59                    } else if nanos.len() != 9 {
60                        // OBS RINEX : 100ns precision
61                        ns *= 100;
62                    }
63                } else {
64                    ss = item
65                        .trim()
66                        .parse::<u8>()
67                        .map_err(|_| ParsingError::EpochFormat)?;
68                }
69            },
70            _ => {},
71        }
72    }
73
74    //println!("content \"{}\"", content); // DEBUG
75    //println!("Y {} M {} D {} HH {} MM {} SS {} NS {}", y, m, d, hh, mm, ss, ns); // DEBUG
76    match ts {
77        TimeScale::UTC => {
78            // Catch possible Hifitime panic on bad string content
79            if y == 0 {
80                return Err(ParsingError::EpochFormat);
81            }
82
83            Ok(Epoch::from_gregorian_utc(y, m, d, hh, mm, ss, ns as u32))
84        },
85        TimeScale::TAI => {
86            // Catch possible Hifitime panic on bad string content
87            if y == 0 {
88                return Err(ParsingError::EpochFormat);
89            }
90            let epoch = Epoch::from_gregorian_tai(y, m, d, hh, mm, ss, ns as u32);
91            Ok(epoch)
92        },
93        ts => {
94            // Catch possible Hifitime panic on bad string content
95            if y == 0 {
96                return Err(ParsingError::EpochFormat);
97            }
98
99            let epoch = Epoch::from_gregorian_str(&format!(
100                "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}.{:06} {}",
101                y, m, d, hh, mm, ss, ns, ts
102            ))?;
103            Ok(epoch)
104        },
105    }
106}
107
108pub(crate) fn parse_utc(s: &str) -> Result<Epoch, ParsingError> {
109    parse_in_timescale(s, TimeScale::UTC)
110}
111
112#[cfg(test)]
113mod test {
114    use super::*;
115    use crate::prelude::{Epoch, TimeScale};
116
117    use std::str::FromStr;
118
119    #[test]
120    fn epoch_parsing() {
121        for (epoch, expected) in [
122            (
123                "2018 06 13 00 00 33.179947800",
124                "2018-06-13T00:00:33.179947800 TAI",
125            ),
126            (
127                "2018 06 13 00 05 13.179947800",
128                "2018-06-13T00:05:13.179947800 TAI",
129            ),
130        ] {
131            let parsed = parse_in_timescale(epoch, TimeScale::TAI).unwrap();
132
133            let expected = Epoch::from_str(expected).unwrap();
134            assert_eq!(parsed, expected);
135        }
136    }
137}