From a9b1ec412a6224020a2e9664a45974dcf71fdace Mon Sep 17 00:00:00 2001 From: raphaelroosz <121112446+raphaelroosz@users.noreply.github.com> Date: Tue, 20 Dec 2022 16:31:56 +0100 Subject: [PATCH] fix ordinal week calculation * math is 0 based while ordinal is 1 based => fix as 1 based logic * add extensive testing against the "date" command format * format: test sample instead of every day * 2007 starts with saturday * Last day of the year is thus the 52 on Monday weekly calendar, 53 on Sunday weekly calendar. * update %U expected value in test * Was the goal was to have a different value than with %W at next line ? another date to pick ? * update cfg("unix") into cfg(target_os = "linux") * format tests/dateutils.rs --- src/format/mod.rs | 4 +-- src/format/strftime.rs | 2 +- src/naive/date.rs | 2 +- tests/dateutils.rs | 55 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 59 insertions(+), 4 deletions(-) diff --git a/src/format/mod.rs b/src/format/mod.rs index d5c4212a40..e3b9b51344 100644 --- a/src/format/mod.rs +++ b/src/format/mod.rs @@ -521,10 +521,10 @@ fn format_inner( use self::Numeric::*; let week_from_sun = |d: &NaiveDate| { - (d.ordinal() as i32 - d.weekday().num_days_from_sunday() as i32 + 7) / 7 + (d.ordinal() as i32 - d.weekday().num_days_from_sunday() as i32 + 6) / 7 }; let week_from_mon = |d: &NaiveDate| { - (d.ordinal() as i32 - d.weekday().num_days_from_monday() as i32 + 7) / 7 + (d.ordinal() as i32 - d.weekday().num_days_from_monday() as i32 + 6) / 7 }; let (width, v) = match *spec { diff --git a/src/format/strftime.rs b/src/format/strftime.rs index aafe01f736..dcaabe49f2 100644 --- a/src/format/strftime.rs +++ b/src/format/strftime.rs @@ -584,7 +584,7 @@ fn test_strftime_docs() { assert_eq!(dt.format("%A").to_string(), "Sunday"); assert_eq!(dt.format("%w").to_string(), "0"); assert_eq!(dt.format("%u").to_string(), "7"); - assert_eq!(dt.format("%U").to_string(), "28"); + assert_eq!(dt.format("%U").to_string(), "27"); assert_eq!(dt.format("%W").to_string(), "27"); assert_eq!(dt.format("%G").to_string(), "2001"); assert_eq!(dt.format("%g").to_string(), "01"); diff --git a/src/naive/date.rs b/src/naive/date.rs index 79d0a98baa..e3cc9b6c6a 100644 --- a/src/naive/date.rs +++ b/src/naive/date.rs @@ -2869,7 +2869,7 @@ mod tests { // corner cases assert_eq!( NaiveDate::from_ymd_opt(2007, 12, 31).unwrap().format("%G,%g,%U,%W,%V").to_string(), - "2008,08,53,53,01" + "2008,08,52,53,01" ); assert_eq!( NaiveDate::from_ymd_opt(2010, 1, 3).unwrap().format("%G,%g,%U,%W,%V").to_string(), diff --git a/tests/dateutils.rs b/tests/dateutils.rs index 130649a71f..dec6bfe117 100644 --- a/tests/dateutils.rs +++ b/tests/dateutils.rs @@ -74,3 +74,58 @@ fn try_verify_against_date_command() { date += chrono::Duration::hours(1); } } + +#[cfg(target_os = "linux")] +fn verify_against_date_command_format_local(path: &'static str, dt: NaiveDateTime) { + let required_format = + "d%d D%D F%F H%H I%I j%j k%k l%l m%m M%M S%S T%T u%u U%U w%w W%W X%X y%y Y%Y z%:z"; + // a%a - depends from localization + // A%A - depends from localization + // b%b - depends from localization + // B%B - depends from localization + // h%h - depends from localization + // c%c - depends from localization + // p%p - depends from localization + // r%r - depends from localization + // x%x - fails, date is dd/mm/yyyy, chrono is dd/mm/yy, same as %D + // Z%Z - too many ways to represent it, will most likely fail + + let output = process::Command::new(path) + .arg("-d") + .arg(format!( + "{}-{:02}-{:02} {:02}:{:02}:{:02}", + dt.year(), + dt.month(), + dt.day(), + dt.hour(), + dt.minute(), + dt.second() + )) + .arg(format!("+{}", required_format)) + .output() + .unwrap(); + + let date_command_str = String::from_utf8(output.stdout).unwrap(); + let date = NaiveDate::from_ymd_opt(dt.year(), dt.month(), dt.day()).unwrap(); + let ldt = Local + .from_local_datetime(&date.and_hms_opt(dt.hour(), dt.minute(), dt.second()).unwrap()) + .unwrap(); + let formated_date = format!("{}\n", ldt.format(required_format)); + assert_eq!(date_command_str, formated_date); +} + +#[test] +#[cfg(target_os = "linux")] +fn try_verify_against_date_command_format() { + let date_path = "/usr/bin/date"; + + if !path::Path::new(date_path).exists() { + // date command not found, skipping + return; + } + let mut date = NaiveDate::from_ymd_opt(1970, 1, 1).unwrap().and_hms_opt(12, 11, 13).unwrap(); + while date.year() < 2008 { + verify_against_date_command_format_local(date_path, date); + date += chrono::Duration::days(55); + } +}