aws_sigv4/
date_time.rs
1#![allow(dead_code)]
8
9use std::time::SystemTime;
10use time::{OffsetDateTime, Time};
11
12pub(crate) fn truncate_subsecs(time: SystemTime) -> SystemTime {
14 let date_time = OffsetDateTime::from(time);
15 let time = date_time.time();
16 date_time
17 .replace_time(
18 Time::from_hms(time.hour(), time.minute(), time.second()).expect("was already a time"),
19 )
20 .into()
21}
22
23pub(crate) fn format_date(time: SystemTime) -> String {
25 let time = OffsetDateTime::from(time);
26 format!(
27 "{:04}{:02}{:02}",
28 time.year(),
29 u8::from(time.month()),
30 time.day()
31 )
32}
33
34pub(crate) fn format_date_time(time: SystemTime) -> String {
36 let time = OffsetDateTime::from(time);
37 format!(
38 "{:04}{:02}{:02}T{:02}{:02}{:02}Z",
39 time.year(),
40 u8::from(time.month()),
41 time.day(),
42 time.hour(),
43 time.minute(),
44 time.second()
45 )
46}
47
48#[cfg(test)]
50pub(crate) mod test_parsers {
51 use std::{borrow::Cow, error::Error, fmt, time::SystemTime};
52 use time::format_description;
53 use time::{Date, PrimitiveDateTime, Time};
54
55 const DATE_TIME_FORMAT: &str = "[year][month][day]T[hour][minute][second]Z";
56 const DATE_FORMAT: &str = "[year][month][day]";
57
58 pub(crate) fn parse_date_time(date_time_str: &str) -> Result<SystemTime, ParseError> {
60 let date_time = PrimitiveDateTime::parse(
61 date_time_str,
62 &format_description::parse(DATE_TIME_FORMAT).unwrap(),
63 )
64 .map_err(|err| ParseError(err.to_string().into()))?
65 .assume_utc();
66 Ok(date_time.into())
67 }
68
69 pub(crate) fn parse_date(date_str: &str) -> Result<SystemTime, ParseError> {
71 let date_time = PrimitiveDateTime::new(
72 Date::parse(date_str, &format_description::parse(DATE_FORMAT).unwrap())
73 .map_err(|err| ParseError(err.to_string().into()))?,
74 Time::from_hms(0, 0, 0).unwrap(),
75 )
76 .assume_utc();
77 Ok(date_time.into())
78 }
79
80 #[derive(Debug)]
81 pub(crate) struct ParseError(Cow<'static, str>);
82
83 impl fmt::Display for ParseError {
84 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85 write!(f, "failed to parse time: {}", self.0)
86 }
87 }
88
89 impl Error for ParseError {}
90}
91
92#[cfg(test)]
93mod tests {
94 use super::*;
95 use crate::date_time::test_parsers::{parse_date, parse_date_time};
96 use time::format_description::well_known::Rfc3339;
97
98 #[cfg(not(any(target_arch = "powerpc", target_arch = "x86")))]
100 #[test]
101 fn date_format() {
102 let time: SystemTime = OffsetDateTime::parse("2039-02-04T23:01:09.104Z", &Rfc3339)
103 .unwrap()
104 .into();
105 assert_eq!("20390204", format_date(time));
106 let time: SystemTime = OffsetDateTime::parse("0100-01-02T00:00:00.000Z", &Rfc3339)
107 .unwrap()
108 .into();
109 assert_eq!("01000102", format_date(time));
110 }
111
112 #[cfg(not(any(target_arch = "powerpc", target_arch = "x86")))]
114 #[test]
115 fn date_time_format() {
116 let time: SystemTime = OffsetDateTime::parse("2039-02-04T23:01:09.104Z", &Rfc3339)
117 .unwrap()
118 .into();
119 assert_eq!("20390204T230109Z", format_date_time(time));
120 let time: SystemTime = OffsetDateTime::parse("0100-01-02T00:00:00.000Z", &Rfc3339)
121 .unwrap()
122 .into();
123 assert_eq!("01000102T000000Z", format_date_time(time));
124 }
125
126 #[test]
127 fn date_time_roundtrip() {
128 let time = parse_date_time("20150830T123600Z").unwrap();
129 assert_eq!("20150830T123600Z", format_date_time(time));
130 }
131
132 #[test]
133 fn date_roundtrip() {
134 let time = parse_date("20150830").unwrap();
135 assert_eq!("20150830", format_date(time));
136 }
137
138 #[cfg(not(any(target_arch = "powerpc", target_arch = "x86")))]
140 #[test]
141 fn test_truncate_subsecs() {
142 let time: SystemTime = OffsetDateTime::parse("2039-02-04T23:01:09.104Z", &Rfc3339)
143 .unwrap()
144 .into();
145 let expected: SystemTime = OffsetDateTime::parse("2039-02-04T23:01:09.000Z", &Rfc3339)
146 .unwrap()
147 .into();
148 assert_eq!(expected, truncate_subsecs(time));
149 }
150}