ad_time/protocols/
common.rs1use crate::time_src::TimeSourceError;
2use std::time::{Duration, SystemTime, UNIX_EPOCH};
3
4pub fn parse_generalized_time(s: &str) -> Result<SystemTime, TimeSourceError> {
6 if !s.is_ascii() {
8 return Err(TimeSourceError::Parse("GeneralizedTime not ASCII".into()));
9 }
10 let s = s.trim_end_matches('Z');
11
12 let (s, _fraction) = if let Some(dot_idx) = s.find('.') {
14 (&s[0..dot_idx], &s[dot_idx + 1..])
15 } else {
16 (s, "")
17 };
18
19 if s.len() < 14 {
20 return Err(TimeSourceError::Parse(format!(
21 "GeneralizedTime too short: {:?}",
22 s
23 )));
24 }
25
26 let year: i64 = s[0..4]
27 .parse()
28 .map_err(|_| TimeSourceError::Parse("invalid year".into()))?;
29 let month: i64 = s[4..6]
30 .parse()
31 .map_err(|_| TimeSourceError::Parse("invalid month".into()))?;
32 let day: i64 = s[6..8]
33 .parse()
34 .map_err(|_| TimeSourceError::Parse("invalid day".into()))?;
35 let hour: i64 = s[8..10]
36 .parse()
37 .map_err(|_| TimeSourceError::Parse("invalid hour".into()))?;
38 let min: i64 = s[10..12]
39 .parse()
40 .map_err(|_| TimeSourceError::Parse("invalid min".into()))?;
41 let sec: i64 = s[12..14]
42 .parse()
43 .map_err(|_| TimeSourceError::Parse("invalid sec".into()))?;
44
45 let days = civil_to_days(year, month, day)?;
46 let unix_secs = days * 86400 + hour * 3600 + min * 60 + sec;
47
48 if unix_secs < 0 {
49 return Err(TimeSourceError::Parse(
50 "GeneralizedTime predates Unix epoch".into(),
51 ));
52 }
53 Ok(UNIX_EPOCH + Duration::from_secs(unix_secs as u64))
54}
55
56pub fn civil_to_days(y: i64, m: i64, d: i64) -> Result<i64, TimeSourceError> {
58 if y < 1970 || !(1..=12).contains(&m) || !(1..=31).contains(&d) {
59 return Err(TimeSourceError::Parse(format!(
60 "invalid date {}-{:02}-{:02}",
61 y, m, d
62 )));
63 }
64 let y = if m <= 2 { y - 1 } else { y };
66 let era = y / 400;
67 let yoe = y - era * 400;
68 let doy = (153 * (if m > 2 { m - 3 } else { m + 9 }) + 2) / 5 + d - 1;
69 let doe = yoe * 365 + yoe / 4 - yoe / 100 + doy;
70 Ok(era * 146097 + doe - 719468)
71}
72
73pub fn system_time_to_us(t: SystemTime) -> Result<i64, TimeSourceError> {
75 t.duration_since(UNIX_EPOCH)
76 .map(|d| d.as_micros() as i64)
77 .map_err(|_| TimeSourceError::Parse("time before unix epoch".into()))
78}
79
80pub fn filetime_to_system_time(filetime: u64) -> Result<SystemTime, TimeSourceError> {
81 const FILETIME_TO_UNIX_SECS: u64 = 11_644_473_600;
82 const EPOCH_OFFSET_100NS: u64 = FILETIME_TO_UNIX_SECS * 10_000_000;
83 if filetime < EPOCH_OFFSET_100NS {
84 return Err(TimeSourceError::Parse(format!(
85 "FILETIME {} predates Unix epoch",
86 filetime
87 )));
88 }
89 let unix_100ns = filetime - EPOCH_OFFSET_100NS;
90 let secs = unix_100ns / 10_000_000;
91 let nanos = ((unix_100ns % 10_000_000) * 100) as u32;
92 Ok(UNIX_EPOCH + Duration::new(secs, nanos))
93}