fix: Change DateTime
to not accept invalid days
This commit is contained in:
parent
83eccdf3e2
commit
2626d02494
1 changed files with 40 additions and 1 deletions
41
src/types.rs
41
src/types.rs
|
@ -235,7 +235,7 @@ impl DateTime {
|
|||
/// The bounds are:
|
||||
/// * year: [1980, 2107]
|
||||
/// * month: [1, 12]
|
||||
/// * day: [1, 31]
|
||||
/// * day: [1, 28..=31]
|
||||
/// * hour: [0, 23]
|
||||
/// * minute: [0, 59]
|
||||
/// * second: [0, 58]
|
||||
|
@ -247,6 +247,10 @@ impl DateTime {
|
|||
minute: u8,
|
||||
second: u8,
|
||||
) -> Result<DateTime, DateTimeRangeError> {
|
||||
fn is_leap_year(year: u16) -> bool {
|
||||
(year % 4 == 0) && ((year % 25 != 0) || (year % 16 == 0))
|
||||
}
|
||||
|
||||
if (1980..=2107).contains(&year)
|
||||
&& (1..=12).contains(&month)
|
||||
&& (1..=31).contains(&day)
|
||||
|
@ -254,6 +258,16 @@ impl DateTime {
|
|||
&& minute <= 59
|
||||
&& second <= 58
|
||||
{
|
||||
let max_day = match month {
|
||||
1 | 3 | 5 | 7 | 8 | 10 | 12 => 31,
|
||||
4 | 6 | 9 | 11 => 30,
|
||||
2 if is_leap_year(year) => 29,
|
||||
2 => 28,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
if day > max_day {
|
||||
return Err(DateTimeRangeError);
|
||||
}
|
||||
Ok(DateTime {
|
||||
year,
|
||||
month,
|
||||
|
@ -1179,6 +1193,31 @@ mod test {
|
|||
assert!(DateTime::from_date_and_time(2108, 12, 31, 0, 0, 0).is_err());
|
||||
assert!(DateTime::from_date_and_time(2107, 13, 31, 0, 0, 0).is_err());
|
||||
assert!(DateTime::from_date_and_time(2107, 12, 32, 0, 0, 0).is_err());
|
||||
|
||||
assert!(DateTime::from_date_and_time(2018, 1, 31, 0, 0, 0).is_ok());
|
||||
assert!(DateTime::from_date_and_time(2018, 2, 28, 0, 0, 0).is_ok());
|
||||
assert!(DateTime::from_date_and_time(2018, 2, 29, 0, 0, 0).is_err());
|
||||
assert!(DateTime::from_date_and_time(2018, 3, 31, 0, 0, 0).is_ok());
|
||||
assert!(DateTime::from_date_and_time(2018, 4, 30, 0, 0, 0).is_ok());
|
||||
assert!(DateTime::from_date_and_time(2018, 4, 31, 0, 0, 0).is_err());
|
||||
assert!(DateTime::from_date_and_time(2018, 5, 31, 0, 0, 0).is_ok());
|
||||
assert!(DateTime::from_date_and_time(2018, 6, 30, 0, 0, 0).is_ok());
|
||||
assert!(DateTime::from_date_and_time(2018, 6, 31, 0, 0, 0).is_err());
|
||||
assert!(DateTime::from_date_and_time(2018, 7, 31, 0, 0, 0).is_ok());
|
||||
assert!(DateTime::from_date_and_time(2018, 8, 31, 0, 0, 0).is_ok());
|
||||
assert!(DateTime::from_date_and_time(2018, 9, 30, 0, 0, 0).is_ok());
|
||||
assert!(DateTime::from_date_and_time(2018, 9, 31, 0, 0, 0).is_err());
|
||||
assert!(DateTime::from_date_and_time(2018, 10, 31, 0, 0, 0).is_ok());
|
||||
assert!(DateTime::from_date_and_time(2018, 11, 30, 0, 0, 0).is_ok());
|
||||
assert!(DateTime::from_date_and_time(2018, 11, 31, 0, 0, 0).is_err());
|
||||
assert!(DateTime::from_date_and_time(2018, 12, 31, 0, 0, 0).is_ok());
|
||||
|
||||
// leap year: divisible by 4
|
||||
assert!(DateTime::from_date_and_time(2024, 2, 29, 0, 0, 0).is_ok());
|
||||
// leap year: divisible by 100 and by 400
|
||||
assert!(DateTime::from_date_and_time(2000, 2, 29, 0, 0, 0).is_ok());
|
||||
// common year: divisible by 100 but not by 400
|
||||
assert!(DateTime::from_date_and_time(2100, 2, 29, 0, 0, 0).is_err());
|
||||
}
|
||||
|
||||
#[cfg(feature = "time")]
|
||||
|
|
Loading…
Add table
Reference in a new issue