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 0000000..711f152 Binary files /dev/null and b/xlsx/tests/calc_tests/DATE.xlsx differ