fn is_leap_year(year: u64) -> bool {
year.is_multiple_of(4) && (!year.is_multiple_of(100) || year.is_multiple_of(400))
}
pub fn parse_http_date(date_str: &str) -> Option<u64> {
let mut parts = date_str.split_whitespace();
let _day_name = parts.next()?; let day: u64 = parts.next()?.parse().ok()?; let month_str = parts.next()?; let year: u64 = parts.next()?.parse().ok()?; let time_str = parts.next()?;
let month: u64 = match month_str {
"Jan" => 1,
"Feb" => 2,
"Mar" => 3,
"Apr" => 4,
"May" => 5,
"Jun" => 6,
"Jul" => 7,
"Aug" => 8,
"Sep" => 9,
"Oct" => 10,
"Nov" => 11,
"Dec" => 12,
_ => return None,
};
let mut t = time_str.split(':');
let hour: u64 = t.next()?.parse().ok()?;
let minute: u64 = t.next()?.parse().ok()?;
let second: u64 = t.next()?.parse().ok()?;
let mut days: u64 = (1970..year)
.map(|y| if is_leap_year(y) { 366 } else { 365 })
.sum();
let month_days = if is_leap_year(year) {
[0u64, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
} else {
[0u64, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
};
days += month_days[1..month as usize].iter().sum::<u64>();
days += day - 1;
Some(days * 86400 + hour * 3600 + minute * 60 + second)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_http_date() {
assert_eq!(parse_http_date("Thu, 01 Jan 1970 00:00:00 GMT"), Some(0));
assert!(parse_http_date("Mon, 01 Jun 2026 12:41:36 GMT").is_some());
assert!(parse_http_date("not a date").is_none());
}
#[test]
fn test_leap_year() {
assert!(is_leap_year(2000));
assert!(is_leap_year(2024));
assert!(!is_leap_year(1900));
assert!(!is_leap_year(2023));
}
}