FIX: Dates are only valid up to the last day of 9999
This commit is contained in:
committed by
Nicolás Hatcher Andrés
parent
d04691b790
commit
c6adf8449b
@@ -21,7 +21,8 @@ pub(crate) const EXCEL_DATE_BASE: i32 = 693_594;
|
||||
// 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;
|
||||
pub(crate) const MINIMUM_DATE_SERIAL_NUMBER: i32 = 2;
|
||||
|
||||
// Excel can handle dates until the year 9999-12-31
|
||||
pub(crate) const EXCEL_DATE_MAX: i32 = 2_958_465;
|
||||
// 2958465 is the number of days from 1900-01-01 to 9999-12-31
|
||||
pub(crate) const MAXIMUM_DATE_SERIAL_NUMBER: i32 = 2_958_465;
|
||||
|
||||
@@ -5,8 +5,8 @@ use chrono::Months;
|
||||
use chrono::NaiveDate;
|
||||
|
||||
use crate::constants::EXCEL_DATE_BASE;
|
||||
use crate::constants::EXCEL_DATE_MAX;
|
||||
use crate::constants::EXCEL_DATE_MIN;
|
||||
use crate::constants::MAXIMUM_DATE_SERIAL_NUMBER;
|
||||
use crate::constants::MINIMUM_DATE_SERIAL_NUMBER;
|
||||
|
||||
#[inline]
|
||||
fn convert_to_serial_number(date: NaiveDate) -> i32 {
|
||||
@@ -14,8 +14,8 @@ fn convert_to_serial_number(date: NaiveDate) -> i32 {
|
||||
}
|
||||
|
||||
fn is_date_within_range(date: NaiveDate) -> bool {
|
||||
convert_to_serial_number(date) >= EXCEL_DATE_MIN
|
||||
&& convert_to_serial_number(date) <= EXCEL_DATE_MAX
|
||||
convert_to_serial_number(date) >= MINIMUM_DATE_SERIAL_NUMBER
|
||||
&& convert_to_serial_number(date) <= MAXIMUM_DATE_SERIAL_NUMBER
|
||||
}
|
||||
|
||||
pub fn from_excel_date(days: i64) -> NaiveDate {
|
||||
@@ -132,11 +132,11 @@ mod tests {
|
||||
fn test_max_and_min_dates() {
|
||||
assert_eq!(
|
||||
permissive_date_to_serial_number(31, 12, 9999),
|
||||
Ok(EXCEL_DATE_MAX),
|
||||
Ok(MAXIMUM_DATE_SERIAL_NUMBER),
|
||||
);
|
||||
assert_eq!(
|
||||
permissive_date_to_serial_number(1, 1, 1900),
|
||||
Ok(EXCEL_DATE_MIN),
|
||||
Ok(MINIMUM_DATE_SERIAL_NUMBER),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ use chrono::Datelike;
|
||||
use chrono::Months;
|
||||
use chrono::Timelike;
|
||||
|
||||
use crate::constants::MAXIMUM_DATE_SERIAL_NUMBER;
|
||||
use crate::expressions::types::CellReferenceIndex;
|
||||
use crate::formatter::dates::date_to_serial_number;
|
||||
use crate::formatter::dates::permissive_date_to_serial_number;
|
||||
@@ -32,6 +33,13 @@ impl Model {
|
||||
}
|
||||
Err(s) => return s,
|
||||
};
|
||||
if serial_number > MAXIMUM_DATE_SERIAL_NUMBER as i64 {
|
||||
return CalcResult::Error {
|
||||
error: Error::NUM,
|
||||
origin: cell,
|
||||
message: "Function DAY parameter 1 value is too large.".to_string(),
|
||||
};
|
||||
}
|
||||
let date = from_excel_date(serial_number);
|
||||
let day = date.day() as f64;
|
||||
CalcResult::Number(day)
|
||||
@@ -56,6 +64,13 @@ impl Model {
|
||||
}
|
||||
Err(s) => return s,
|
||||
};
|
||||
if serial_number > MAXIMUM_DATE_SERIAL_NUMBER as i64 {
|
||||
return CalcResult::Error {
|
||||
error: Error::NUM,
|
||||
origin: cell,
|
||||
message: "Function DAY parameter 1 value is too large.".to_string(),
|
||||
};
|
||||
}
|
||||
let date = from_excel_date(serial_number);
|
||||
let month = date.month() as f64;
|
||||
CalcResult::Number(month)
|
||||
@@ -80,6 +95,13 @@ impl Model {
|
||||
}
|
||||
Err(s) => return s,
|
||||
};
|
||||
if serial_number > MAXIMUM_DATE_SERIAL_NUMBER as i64 {
|
||||
return CalcResult::Error {
|
||||
error: Error::NUM,
|
||||
origin: cell,
|
||||
message: "Function DAY parameter 1 value is too large.".to_string(),
|
||||
};
|
||||
}
|
||||
|
||||
let months = match self.get_number_no_bools(&args[1], cell) {
|
||||
Ok(c) => {
|
||||
@@ -178,6 +200,13 @@ impl Model {
|
||||
}
|
||||
Err(s) => return s,
|
||||
};
|
||||
if serial_number > MAXIMUM_DATE_SERIAL_NUMBER as i64 {
|
||||
return CalcResult::Error {
|
||||
error: Error::NUM,
|
||||
origin: cell,
|
||||
message: "Function DAY parameter 1 value is too large.".to_string(),
|
||||
};
|
||||
}
|
||||
let date = from_excel_date(serial_number);
|
||||
let year = date.year() as f64;
|
||||
CalcResult::Number(year)
|
||||
|
||||
@@ -13,6 +13,7 @@ mod test_fn_averageifs;
|
||||
mod test_fn_choose;
|
||||
mod test_fn_concatenate;
|
||||
mod test_fn_count;
|
||||
mod test_fn_day;
|
||||
mod test_fn_exact;
|
||||
mod test_fn_financial;
|
||||
mod test_fn_formulatext;
|
||||
|
||||
15
base/src/test/test_fn_day.rs
Normal file
15
base/src/test/test_fn_day.rs
Normal file
@@ -0,0 +1,15 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn test_fn_date_arguments() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
model._set("A1", "=DAY(95051806)");
|
||||
model._set("A2", "=DAY(2958465)");
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"#NUM!");
|
||||
assert_eq!(model._get_text("A2"), *"31");
|
||||
}
|
||||
Binary file not shown.
Reference in New Issue
Block a user