1use crate::prelude::{Epoch, ParsingError, TimeScale};
4
5pub(crate) fn format(epoch: Epoch) -> String {
7 let (y, m, d, hh, mm, ss, nanos) = epoch_decompose(epoch);
8
9 format!(
10 "{:04} {:02} {:02} {:02} {:02} {:>2}.{:07}",
11 y,
12 m,
13 d,
14 hh,
15 mm,
16 ss,
17 nanos / 100,
18 )
19}
20
21pub(crate) fn parse_in_timescale(content: &str, ts: TimeScale) -> Result<Epoch, ParsingError> {
23 let mut y = 0_i32;
24 let mut m = 0_u8;
25 let mut d = 0_u8;
26 let mut hh = 0_u8;
27 let mut mm = 0_u8;
28 let mut ss = 0_u8;
29 let mut ns = 0_u64;
30
31 if content.split_ascii_whitespace().count() < 6 {
32 return Err(ParsingError::EpochFormat);
33 }
34
35 for (field_index, item) in content.split_ascii_whitespace().enumerate() {
36 match field_index {
37 0 => {
38 y = item.parse::<i32>().map_err(|_| ParsingError::EpochFormat)?;
39
40 if y > 79 && y <= 99 {
42 y += 1900;
43 } else if y < 79 {
44 y += 2000;
45 }
46 },
47 1 => {
48 m = item.parse::<u8>().map_err(|_| ParsingError::EpochFormat)?;
49 },
50 2 => {
51 d = item.parse::<u8>().map_err(|_| ParsingError::EpochFormat)?;
52 },
53 3 => {
54 hh = item.parse::<u8>().map_err(|_| ParsingError::EpochFormat)?;
55 },
56 4 => {
57 mm = item.parse::<u8>().map_err(|_| ParsingError::EpochFormat)?;
58 },
59 5 => {
60 if let Some(dot) = item.find('.') {
61 let is_nav = item.trim().len() < 7;
62
63 ss = item[..dot]
64 .trim()
65 .parse::<u8>()
66 .map_err(|_| ParsingError::EpochFormat)?;
67
68 let nanos = item[dot + 1..].trim();
69
70 ns = nanos
71 .parse::<u64>()
72 .map_err(|_| ParsingError::EpochFormat)?;
73
74 if is_nav {
75 ns *= 100_000_000;
77 } else if nanos.len() != 9 {
78 ns *= 100;
80 }
81 } else {
82 ss = item
83 .trim()
84 .parse::<u8>()
85 .map_err(|_| ParsingError::EpochFormat)?;
86 }
87 },
88 _ => {},
89 }
90 }
91
92 match ts {
95 TimeScale::UTC => {
96 if y == 0 {
98 return Err(ParsingError::EpochFormat);
99 }
100
101 Ok(Epoch::from_gregorian_utc(y, m, d, hh, mm, ss, ns as u32))
102 },
103 TimeScale::TAI => {
104 if y == 0 {
106 return Err(ParsingError::EpochFormat);
107 }
108 let epoch = Epoch::from_gregorian_tai(y, m, d, hh, mm, ss, ns as u32);
109 Ok(epoch)
110 },
111 ts => {
112 if y == 0 {
114 return Err(ParsingError::EpochFormat);
115 }
116
117 let epoch = Epoch::from_gregorian_str(&format!(
118 "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}.{:06} {}",
119 y, m, d, hh, mm, ss, ns, ts
120 ))?;
121 Ok(epoch)
122 },
123 }
124}
125
126pub(crate) fn parse_utc(s: &str) -> Result<Epoch, ParsingError> {
127 parse_in_timescale(s, TimeScale::UTC)
128}
129
130pub(crate) fn epoch_decompose(epoch: Epoch) -> (i32, u8, u8, u8, u8, u8, u32) {
131 epoch.to_gregorian(epoch.time_scale)
132}
133
134#[cfg(test)]
135mod test {
136 use super::*;
137
138 use crate::prelude::{Epoch, TimeScale};
139
140 use std::str::FromStr;
141}