// This file is part of ICU4X. For terms of use, please see the file
// called LICENSE at the top level of the ICU4X source tree
// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
use std::convert::Infallible;
use icu_calendar::{
cal::Hebrew,
options::{DateAddOptions, DateDifferenceOptions, Overflow},
types::{DateDuration, DateDurationUnit, MonthCode},
AsCalendar, Calendar, Date, Iso,
};
#[ rustfmt::skip]
#[ allow(clippy::type_complexity)]
const ISO_DATE_PAIRS: &[(&str, &str, u64, (u32, u64), (u32, u64), (u32, u32, u64))] = &[
// d0, d1, D, (W, D), (M, D), (Y, M, D)
(
"2020-01-03" ,
"2020-02-15" ,
43 , (
6 ,
1 ), (
1 ,
12 ), (
0 ,
1 ,
12 )),
(
"2020-01-31" ,
"2020-06-30" ,
151 , (
21 ,
4 ), (
4 ,
30 ), (
0 ,
4 ,
30 )),
(
"2020-03-31" ,
"2020-07-30" ,
121 , (
17 ,
2 ), (
3 ,
30 ), (
0 ,
3 ,
30 )),
(
"2020-03-31" ,
"2020-07-31" ,
122 , (
17 ,
3 ), (
4 ,
0 ), (
0 ,
4 ,
0 )),
(
"2016-03-20" ,
"2020-03-05" ,
1446 , (
206 ,
4 ), (
47 ,
14 ), (
3 ,
11 ,
14 )),
(
"2020-02-29" ,
"2022-03-01" ,
731 , (
104 ,
3 ), (
24 ,
1 ), (
2 ,
0 ,
1 )),
// Negative direction:
(
"2020-02-15" ,
"2020-01-03" ,
43 , (
6 ,
1 ), (
1 ,
12 ), (
0 ,
1 ,
12 )),
(
"2020-06-30" ,
"2020-01-31" ,
151 , (
21 ,
4 ), (
4 ,
29 ), (
0 ,
4 ,
29 )),
// DIFF +/-
(
"2020-07-30" ,
"2020-03-31" ,
121 , (
17 ,
2 ), (
3 ,
30 ), (
0 ,
3 ,
30 )),
(
"2020-07-31" ,
"2020-03-31" ,
122 , (
17 ,
3 ), (
4 ,
0 ), (
0 ,
4 ,
0 )),
(
"2020-03-05" ,
"2016-03-20" ,
1446 , (
206 ,
4 ), (
47 ,
16 ), (
3 ,
11 ,
16 )),
// DIFF +/-
(
"2022-03-01" ,
"2020-02-29" ,
731 , (
104 ,
3 ), (
24 ,
1 ), (
2 ,
0 ,
1 )),
];
fn check<A>(
d0: &Date<A>,
d1: &Date<A>,
exp0: &u64,
exp1: &(u32, u64),
exp2: &(u32, u64),
exp3: &(u32, u32, u64),
)
where
A: AsCalendar + Copy,
<A
as AsCalendar>::Calendar: Calendar<DifferenceError = Infallible>,
<<A
as AsCalendar>::Calendar
as Calendar>::DateInner: PartialOrd,
{
let is_negative = d0 > d1;
let mut add_options = DateAddOptions::default();
add_options.overflow = Some(Overflow::Constrain);
let mut until_options0 = DateDifferenceOptions::default();
until_options0.largest_unit = Some(DateDurationUnit::Days);
let mut until_options1 = DateDifferenceOptions::default();
until_options1.largest_unit = Some(DateDurationUnit::Weeks);
let mut until_options2 = DateDifferenceOptions::default();
until_options2.largest_unit = Some(DateDurationUnit::Months);
let mut until_options3 = DateDifferenceOptions::default();
until_options3.largest_unit = Some(DateDurationUnit::Years);
let Ok(p0) = d0.try_until_with_options(d1, until_options0);
assert_eq!(
p0,
DateDuration {
is_negative,
days: *exp0,
..Default::default()
},
"{d0:?}/{d1:?}"
);
assert_eq!(
d0.try_added_with_options(p0, add_options).unwrap(),
*d1,
"{d0:?}/{d1:?}"
);
let Ok(p1) = d0.try_until_with_options(d1, until_options1);
assert_eq!(
p1,
DateDuration {
is_negative,
weeks: exp1.
0 ,
days: exp1.
1 ,
..Default::default()
},
"{d0:?}/{d1:?}"
);
assert_eq!(
d0.try_added_with_options(p1, add_options).unwrap(),
*d1,
"{d0:?}/{d1:?}"
);
let Ok(p2) = d0.try_until_with_options(d1, until_options2);
assert_eq!(
p2,
DateDuration {
is_negative,
months: exp2.
0 ,
days: exp2.
1 ,
..Default::default()
},
"{d0:?}/{d1:?}"
);
assert_eq!(
d0.try_added_with_options(p2, add_options).unwrap(),
*d1,
"{d0:?}/{d1:?}"
);
let Ok(p3) = d0.try_until_with_options(d1, until_options3);
assert_eq!(
p3,
DateDuration {
is_negative,
years: exp3.
0 ,
months: exp3.
1 ,
days: exp3.
2 ,
..Default::default()
},
"{d0:?}/{d1:?}"
);
assert_eq!(
d0.try_added_with_options(p3, add_options).unwrap(),
*d1,
"{d0:?}/{d1:?}"
);
// RataDie addition should be equivalent for largest unit Days and Weeks
let rd_diff = d1.to_rata_die() - d0.to_rata_die();
if is_negative {
assert!(rd_diff.is_negative());
}
assert_eq!(p0.days, rd_diff.unsigned_abs());
assert_eq!(p1.days + u64::from(p1.weeks) *
7 , rd_diff.unsigned_abs());
}
#[ test]
fn test_arithmetic_cases() {
for (d0, d1, exp0, exp1, exp2, exp3)
in ISO_DATE_PAIRS {
let d0 = Date::try_from_str(d0, Iso).unwrap();
let d1 = Date::try_from_str(d1, Iso).unwrap();
check(&d0, &d1, exp0, exp1, exp2, exp3);
}
}
#[ test]
fn test_hebrew() {
let m06z_20 =
Date::try_new_from_codes(None,
5783 , MonthCode::new_normal(
6 ).unwrap(),
20 , Hebrew)
.unwrap();
let m05l_15 =
Date::try_new_from_codes(None,
5784 , MonthCode::new_leap(
5 ).unwrap(),
15 , Hebrew).un
wrap();
let m05l_30 =
Date::try_new_from_codes(None, 5784 , MonthCode::new_leap(5 ).unwrap(), 30 , Hebrew).unwrap();
let m06a_29 =
Date::try_new_from_codes(None, 5784 , MonthCode::new_normal(6 ).unwrap(), 29 , Hebrew)
.unwrap();
let m07a_10 =
Date::try_new_from_codes(None, 5784 , MonthCode::new_normal(7 ).unwrap(), 10 , Hebrew)
.unwrap();
let m06b_15 =
Date::try_new_from_codes(None, 5785 , MonthCode::new_normal(6 ).unwrap(), 15 , Hebrew)
.unwrap();
let m07b_20 =
Date::try_new_from_codes(None, 5785 , MonthCode::new_normal(7 ).unwrap(), 20 , Hebrew)
.unwrap();
#[ rustfmt::skip]
#[ allow(clippy::type_complexity)]
let cases: &[(&Date<Hebrew>, &Date<Hebrew>, u64, (u32, u64), (u32, u64), (u32, u32, u64))] = &[
(&m06z_20, &m05l_15, 348 , (49 , 5 ), (11 , 25 ), (0 , 11 , 25 )),
(&m06z_20, &m05l_30, 363 , (51 , 6 ), (12 , 10 ), (0 , 12 , 10 )),
(&m06z_20, &m06a_29, 392 , (56 , 0 ), (13 , 9 ), (1 , 0 , 9 )),
(&m06z_20, &m07a_10, 402 , (57 , 3 ), (13 , 19 ), (1 , 0 , 19 )),
(&m06z_20, &m06b_15, 733 , (104 ,5 ), (24 , 25 ), (1 , 11 , 25 )),
(&m06z_20, &m07b_20, 767 , (109 ,4 ), (26 , 0 ), (2 , 1 , 0 )),
(&m05l_15, &m05l_30, 15 , (2 , 1 ), (0 , 15 ), (0 , 0 , 15 )),
(&m05l_15, &m06a_29, 44 , (6 , 2 ), (1 , 14 ), (0 , 1 , 14 )),
(&m05l_15, &m07a_10, 54 , (7 , 5 ), (1 , 24 ), (0 , 1 , 24 )),
(&m05l_15, &m06b_15, 385 , (55 , 0 ), (13 , 0 ), (1 , 0 , 0 )), // M05L to M06 common year
(&m05l_15, &m07b_20, 419 , (59 , 6 ), (14 , 5 ), (1 , 1 , 5 )), // M05L to M07 common year
(&m05l_30, &m06a_29, 29 , (4 , 1 ), (0 , 29 ), (0 , 0 , 29 )),
(&m05l_30, &m07a_10, 39 , (5 , 4 ), (1 , 10 ), (0 , 1 , 10 )),
(&m05l_30, &m06b_15, 370 , (52 , 6 ), (12 , 15 ), (0 , 12 , 15 )), // M05L to M06 common year
(&m05l_30, &m07b_20, 404 , (57 , 5 ), (13 , 20 ), (1 , 0 , 20 )), // M05L to M07 common year
(&m06a_29, &m07a_10, 10 , (1 , 3 ), (0 , 10 ), (0 , 0 , 10 )),
(&m06a_29, &m06b_15, 341 , (48 , 5 ), (11 , 16 ), (0 , 11 , 16 )), // M06 leap year to M06 common year
(&m06a_29, &m07b_20, 375 , (53 , 4 ), (12 , 20 ), (1 , 0 , 20 )), // M06 leap year to M07 common year
(&m07a_10, &m06b_15, 331 , (47 , 2 ), (11 , 5 ), (0 , 11 , 5 )), // M07 leap year to M06 common year
(&m07a_10, &m07b_20, 365 , (52 , 1 ), (12 , 10 ), (1 , 0 , 10 )), // M07 leap year to M06 common year
(&m06b_15, &m07b_20, 34 , (4 , 6 ), (1 , 5 ), (0 , 1 , 5 )),
];
for (d0, d1, exp0, exp1, exp2, exp3) in cases {
check(d0, d1, exp0, exp1, exp2, exp3);
}
}
#[ test]
fn test_tricky_leap_months() {
let mut add_options = DateAddOptions::default();
add_options.overflow = Some(Overflow::Constrain);
let mut until_options = DateDifferenceOptions::default();
until_options.largest_unit = Some(DateDurationUnit::Years);
fn hebrew_date(year: i32, month: &str, day: u8) -> Date<Hebrew> {
Date::try_new_from_codes(None, year, MonthCode(month.parse().unwrap()), day, Hebrew)
.unwrap()
}
// M06 + 1yr = M06 (common to leap)
let date0 = hebrew_date(5783 , "M06" , 20 );
let duration0 = DateDuration::for_years(1 );
let date1 = date0
.try_added_with_options(duration0, add_options)
.unwrap();
assert_eq!(date1, hebrew_date(5784 , "M06" , 20 ));
let duration0_actual = date0.try_until_with_options(&date1, until_options).unwrap();
assert_eq!(duration0_actual, duration0);
// M06 - 1mo = M05L (leap to leap)
let duration1 = DateDuration::for_months(-1 );
let date2 = date1
.try_added_with_options(duration1, add_options)
.unwrap();
assert_eq!(date2, hebrew_date(5784 , "M05L" , 20 ));
let duration1_actual = date1.try_until_with_options(&date2, until_options).unwrap();
assert_eq!(duration1_actual, duration1);
// M05L + 1yr1mo = M07 (leap to common)
let duration2 = DateDuration {
years: 1 ,
months: 1 ,
..Default::default()
};
let date3 = date2
.try_added_with_options(duration2, add_options)
.unwrap();
assert_eq!(date3, hebrew_date(5785 , "M07" , 20 ));
let duration2_actual = date2.try_until_with_options(&date3, until_options).unwrap();
assert_eq!(duration2_actual, duration2);
// M06 + 1yr1mo = M07 (leap to common)
let date4 = date1
.try_added_with_options(duration2, add_options)
.unwrap();
assert_eq!(date4, hebrew_date(5785 , "M07" , 20 ));
let duration2_actual = date1.try_until_with_options(&date4, until_options).unwrap();
assert_eq!(duration2_actual, duration2);
}
Messung V0.5 in Prozent C=95 H=98 G=96
¤ Dauer der Verarbeitung: 0.4 Sekunden
¤
*© Formatika GbR, Deutschland