use chrono::offset::TimeZone; use chrono::Local; use chrono::{Datelike, NaiveDate, NaiveDateTime, Timelike}; use std::{path, process}; #[cfg(unix)] fn verify_against_date_command_local(path: &'static str, dt: NaiveDateTime) { let output = process::Command::new(path) .arg("-d") .arg(format!("{}-{:02}-{:02} {:02}:05:01", dt.year(), dt.month(), dt.day(), dt.hour())) .arg("+%Y-%m-%d %H:%M:%S %:z") .output() .unwrap(); let date_command_str = String::from_utf8(output.stdout).unwrap(); // The below would be preferred. At this stage neither earliest() or latest() // seems to be consistent with the output of the `date` command, so we simply // compare both. // let local = Local // .from_local_datetime(&NaiveDate::from_ymd(year, month, day).and_hms(hour, 5, 1)) // // looks like the "date" command always returns a given time when it is ambiguous // .earliest(); // if let Some(local) = local { // assert_eq!(format!("{}\n", local), date_command_str); // } else { // // we are in a "Spring forward gap" due to DST, and so date also returns "" // assert_eq!("", date_command_str); // } // This is used while a decision is made wheter the `date` output needs to // be exactly matched, or whether LocalResult::Ambigious should be handled // differently match Local.from_local_datetime(&NaiveDate::from_ymd(dt.year(), dt.month(), dt.day()).and_hms( dt.hour(), 5, 1, )) { chrono::LocalResult::Ambiguous(a, b) => assert!( format!("{}\n", a) == date_command_str || format!("{}\n", b) == date_command_str ), chrono::LocalResult::Single(a) => { assert_eq!(format!("{}\n", a), date_command_str); } chrono::LocalResult::None => { assert_eq!("", date_command_str); } } } #[test] #[cfg(unix)] fn try_verify_against_date_command() { let date_path = "/usr/bin/date"; if !path::Path::new(date_path).exists() { // date command not found, skipping // avoid running this on macOS, which has path /bin/date // as the required CLI arguments are not present in the // macOS build. return; } let mut date = NaiveDate::from_ymd(1975, 1, 1).and_hms(0, 0, 0); while date.year() < 2078 { if (1975..=1977).contains(&date.year()) || (2020..=2022).contains(&date.year()) || (2073..=2077).contains(&date.year()) { verify_against_date_command_local(date_path, date); } date += chrono::TimeDelta::hours(1); } }