1use regex::Regex;
2
3use super::*;
4
5pub const JD_UNIX : f64 = 2440587.5;
6
7pub struct TimestampParser {
8 re:Regex,
9}
10
11pub trait ToUnix {
12 fn to_unix(&self)->f64;
13}
14
15impl ToUnix for GregorianDateHMS {
16 fn to_unix(&self)->f64 {
17 let (jd1,jd2) = self.to_julian();
18 ((jd1 - JD_UNIX) + jd2)*86400.0
19 }
20}
21
22pub fn julian_to_unix(jd1:R,jd2:R)->f64 {
23 ((jd1 - JD_UNIX) + jd2)*86400.0
24}
25
26pub fn unix_to_julian(t:f64)->(R,R) {
27 let t0 = t.floor();
28 (t0/86400.0 + JD_UNIX,(t - t0)/86400.0)
29}
30
31pub fn now()->(R,R) {
32 let dt = std::time::SystemTime::now()
33 .duration_since(std::time::UNIX_EPOCH)
34 .expect("Can't get timestamp");
35 unix_to_julian(dt.as_secs_f64())
36}
37
38impl TimestampParser {
39 pub fn new()->Result<Self> {
40 let re = Regex::new(
41 r"^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2}|\d{5})Z$")?;
42 Ok(Self { re })
43 }
44
45 pub fn parse(&self,u:&str)->Result<GregorianDateHMS> {
46 let caps = self.re.captures(u)
47 .ok_or_else(|| anyhow!("Cannot parse timestamp from {:?}",u))?;
48 Self::parse_caps(&caps,1)
49 }
50
51 fn parse_caps_gd(caps:®ex::Captures<'_>,i:usize)->
52 Result<GregorianDate>
53 {
54 let year : i32 = caps.get(i ).unwrap().as_str().parse()?;
55 let month : i32 = caps.get(i + 1).unwrap().as_str().parse()?;
56 let day : i32 = caps.get(i + 2).unwrap().as_str().parse()?;
57 let gd = GregorianDate::new(year,month,day)?;
58 Ok(gd)
59 }
60
61 fn parse_caps(caps:®ex::Captures<'_>,i:usize)->
62 Result<GregorianDateHMS>
63 {
64 let date = Self::parse_caps_gd(caps,i)?;
65 let hour : u8 = caps.get(i + 3).unwrap().as_str().parse()?;
66 let minute : u8 = caps.get(i + 4).unwrap().as_str().parse()?;
67 let second_s = caps.get(i + 5).unwrap().as_str();
68 let second : u32 = second_s.parse()?;
69 let second =
70 if second_s.len() == 2 {
71 second as f64
72 } else {
73 second as f64 / 1000.0
74 };
75 let hms = HMS { hour,minute,second };
76 Ok(Timestamp { date,hms })
77 }
78}
79
80#[test]
81fn test_timestamps() {
82 let ts_unix =
83 GregorianDateHMS {
84 date:GregorianDate::new(1970,1,1).unwrap(),
85 hms:HMS::new(0,0,0.0)
86 };
87 let (jd0_unix,jd1_unix) = ts_unix.to_julian();
88 println!("UNIX epoch: JD {}",jd0_unix + jd1_unix);
89 let ts_bill =
90 GregorianDateHMS {
91 date:GregorianDate::new(2001,9,9).unwrap(),
92 hms:HMS::new(1,46,40.0)
93 };
94 let (jd0_bill,jd1_bill) = ts_bill.to_julian();
95 println!("bill: JD {}",jd0_bill + jd1_bill);
96
97 let t_bill = 86400.0*((jd0_bill - jd0_unix) + (jd1_bill - jd1_unix));
98 println!("bill: Unix {:14.3}",t_bill);
99 assert!((t_bill - 1e9).abs() < 1e-6);
100}