1use crate::prelude::{Epoch, ParsingError, TimeScale};
2
3pub(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 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 ns *= 100_000_000;
59 } else if nanos.len() != 9 {
60 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 match ts {
77 TimeScale::UTC => {
78 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 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 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}