1use std::time::{SystemTime, UNIX_EPOCH};
15
16use chrono_lite::{time_t, Tm, gmtime, timegm, time};
17
18const WEEKDAYS: &[&str] = &["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
19const MONTHS: &[&str] = &["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
20
21fn httpdate(tm: Tm) -> String {
22 let Tm { tm_wday, tm_mday, tm_mon, tm_year, tm_hour, tm_min, tm_sec, .. } = tm;
23 let weekday = WEEKDAYS[tm_wday as usize];
24 let month = MONTHS[tm_mon as usize];
25 let year = tm_year + 1900;
26 format!("{weekday}, {tm_mday} {month} {year} {tm_hour:02}:{tm_min:02}:{tm_sec:02} GMT")
28}
29
30pub fn from_systime(systime: SystemTime) -> Option<String> {
34 let time = systime.duration_since(UNIX_EPOCH).ok()?.as_secs();
35 let tm = gmtime(time as time_t)?;
36
37 Some(httpdate(tm))
38}
39
40pub fn now() -> Option<String> {
44 let tm = gmtime(time())?;
45 Some(httpdate(tm))
46}
47
48pub fn parse(mut date: &str) -> Option<time_t> {
50 date = date.get(5..)?; let mdaylen = if date.chars().nth(1)? == ' ' { 1 } else { 2 };
55 let tm_mday = date.get(0..mdaylen)?.parse().ok()?; date = date.get(mdaylen+1..)?; let month = date.get(0..3)?; let month = MONTHS.iter().position(|&i| i == month)?;
60 date = date.get(4..)?; let year: i32 = date.get(0..4)?.parse().ok()?; date = date.get(5..)?; let tm_hour = date.get(0..2)?.parse().ok()?; date = date.get(3..)?; let tm_min = date.get(0..2)?.parse().ok()?; date = date.get(3..)?; let tm_sec = date.get(0..2)?.parse().ok()?; date = date.get(3..)?; if date != "GMT" { return None; } let tm = Tm {
72 tm_year: year - 1900,
73 tm_mon: month as i32,
74 tm_mday,
75 tm_hour,
76 tm_min,
77 tm_sec,
78 ..Default::default()
79 };
80 timegm(tm)
81}
82
83#[cfg(test)]
84mod test {
85 use super::*;
86
87 #[test]
88 fn test_httpdate() {
89 assert_eq!("Wed, 26 Feb 2025 22:10:59 GMT", &httpdate(gmtime(1740607859).unwrap()));
90 }
91
92 #[test]
93 fn test_parse() {
94 assert_eq!(1767462569, parse("Sat, 03 Jan 2026 17:49:29 GMT").unwrap());
95 assert_eq!(1767484771, parse("Sat, 3 Jan 2026 23:59:31 GMT").unwrap());
96 }
97
98 #[test]
99 fn test_panic() {
100 assert_eq!(None, parse("🐉🐉🐉🐉🐉"));
101 }
102}