From d04691b790699776956e7f960f8dea3ccb61fa8b Mon Sep 17 00:00:00 2001 From: Shalom Yiblet Date: Wed, 18 Dec 2024 10:18:01 -0800 Subject: [PATCH] refactor(dates): adjust date handling logic for improved accuracy Updated the logic for handling months and days to improve date calculations. Also modified the constants for Excel date ranges to align with supported dates. --- base/src/constants.rs | 8 ++++++-- base/src/formatter/dates.rs | 24 +++++++++++++++--------- base/src/test/test_date_and_time.rs | 2 +- xlsx/tests/calc_tests/DATE.xlsx | Bin 0 -> 9838 bytes 4 files changed, 22 insertions(+), 12 deletions(-) create mode 100644 xlsx/tests/calc_tests/DATE.xlsx diff --git a/base/src/constants.rs b/base/src/constants.rs index 0da0afd..53b13f2 100644 --- a/base/src/constants.rs +++ b/base/src/constants.rs @@ -18,6 +18,10 @@ pub(crate) const LAST_ROW: i32 = 1_048_576; pub(crate) const EXCEL_DATE_BASE: i32 = 693_594; // Excel can handle dates until the year 0000-01-01 -pub(crate) const EXCEL_DATE_MIN: i32 = -693_959; +// However, it uses a different numbering scheme for dates +// that are before 1900-01-01. +// So for now we will simply not support dates before 1900-01-01. +pub(crate) const EXCEL_DATE_MIN: i32 = 2; + // Excel can handle dates until the year 9999-12-31 -pub(crate) const EXCEL_DATE_MAX: i32 = 2958465; +pub(crate) const EXCEL_DATE_MAX: i32 = 2_958_465; diff --git a/base/src/formatter/dates.rs b/base/src/formatter/dates.rs index 0705ce0..f4595c1 100644 --- a/base/src/formatter/dates.rs +++ b/base/src/formatter/dates.rs @@ -58,11 +58,12 @@ pub fn permissive_date_to_serial_number(day: i32, month: i32, year: i32) -> Resu } date = { - let abs_month = month.unsigned_abs(); - if month <= 0 { - date = date - Months::new(abs_month + 1); + let month_diff = month - 1; + let abs_month = month_diff.unsigned_abs(); + if month_diff <= 0 { + date = date - Months::new(abs_month); } else { - date = date + Months::new(abs_month - 1); + date = date + Months::new(abs_month); } if !is_date_within_range(date) { return Err("Out of range parameters for date".to_string()); @@ -71,11 +72,12 @@ pub fn permissive_date_to_serial_number(day: i32, month: i32, year: i32) -> Resu }; date = { - let abs_day = day.unsigned_abs() as u64; - if day <= 0 { - date = date - Days::new(abs_day + 1); + let day_diff = day - 1; + let abs_day = day_diff.unsigned_abs() as u64; + if day_diff <= 0 { + date = date - Days::new(abs_day); } else { - date = date + Days::new(abs_day - 1); + date = date + Days::new(abs_day); } if !is_date_within_range(date) { return Err("Out of range parameters for date".to_string()); @@ -108,6 +110,10 @@ mod tests { permissive_date_to_serial_number(1, 49, 2000), date_to_serial_number(1, 1, 2004) ); + assert_eq!( + permissive_date_to_serial_number(1, 49, 2000), + date_to_serial_number(1, 1, 2004) + ); assert_eq!( permissive_date_to_serial_number(31, 49, 2000), date_to_serial_number(31, 1, 2004) @@ -129,7 +135,7 @@ mod tests { Ok(EXCEL_DATE_MAX), ); assert_eq!( - permissive_date_to_serial_number(1, 1, 0), + permissive_date_to_serial_number(1, 1, 1900), Ok(EXCEL_DATE_MIN), ); } diff --git a/base/src/test/test_date_and_time.rs b/base/src/test/test_date_and_time.rs index 9fe8fc1..7e6ba03 100644 --- a/base/src/test/test_date_and_time.rs +++ b/base/src/test/test_date_and_time.rs @@ -209,7 +209,7 @@ fn test_date_early_dates() { ); // This does not agree with Excel, instead of mistakenly allowing - // for Feb 29, it will auto-wrap to the next day after Feb 28. + // for Feb 29, it will auto-wrap to the next day after Feb 28. assert_eq!(model._get_text("B2"), *"01/03/1900"); // This agrees with Excel from he onward diff --git a/xlsx/tests/calc_tests/DATE.xlsx b/xlsx/tests/calc_tests/DATE.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..711f15228999ac0845d1d104c7f0349b485397ef GIT binary patch literal 9838 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 literal 0 HcmV?d00001