From ae4c1623e2f718b75282d5e7f261399b1b71cce6 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Tue, 19 Dec 2023 09:34:40 -0800 Subject: [PATCH] Add data loading for chinese precomputed caches (#4468) --- Cargo.lock | 1 + components/calendar/benches/convert.rs | 9 +- components/calendar/benches/date.rs | 33 +- components/calendar/benches/datetime.rs | 22 +- components/calendar/src/any_calendar.rs | 40 +- components/calendar/src/chinese.rs | 346 +- components/calendar/src/chinese_based.rs | 238 +- components/calendar/src/dangi.rs | 175 +- components/calendar/src/provider.rs | 7 + .../calendar/src/provider/chinese_based.rs | 323 ++ components/datetime/src/any/date.rs | 6 +- components/datetime/src/any/datetime.rs | 7 +- components/datetime/src/any/zoned_datetime.rs | 7 +- components/datetime/tests/datetime.rs | 4 +- provider/baked/calendar/data/macros.rs | 10 + .../macros/calendar_chinesecache_v1.rs.data | 27 + .../macros/calendar_dangicache_v1.rs.data | 27 + provider/datagen/Cargo.toml | 1 + provider/datagen/src/registry.rs | 2 + .../transform/cldr/calendar/chinese_based.rs | 51 + .../src/transform/cldr/calendar/mod.rs | 3 + .../json/calendar/chinesecache@1/und.json | 4755 +++++++++++++++++ .../data/json/calendar/dangicache@1/und.json | 4755 +++++++++++++++++ .../tests/data/postcard/fingerprints.csv | 2 + 24 files changed, 10538 insertions(+), 313 deletions(-) create mode 100644 components/calendar/src/provider/chinese_based.rs create mode 100644 provider/baked/calendar/data/macros/calendar_chinesecache_v1.rs.data create mode 100644 provider/baked/calendar/data/macros/calendar_dangicache_v1.rs.data create mode 100644 provider/datagen/src/transform/cldr/calendar/chinese_based.rs create mode 100644 provider/datagen/tests/data/json/calendar/chinesecache@1/und.json create mode 100644 provider/datagen/tests/data/json/calendar/dangicache@1/und.json diff --git a/Cargo.lock b/Cargo.lock index 6ef5c4f24a7..74db0ea4d7f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1521,6 +1521,7 @@ version = "1.4.0" name = "icu_datagen" version = "1.4.0" dependencies = [ + "calendrical_calculations", "clap 4.2.1", "crlify", "databake", diff --git a/components/calendar/benches/convert.rs b/components/calendar/benches/convert.rs index 20c7978e401..29d233866d7 100644 --- a/components/calendar/benches/convert.rs +++ b/components/calendar/benches/convert.rs @@ -57,10 +57,17 @@ fn convert_benches(c: &mut Criterion) { #[cfg(feature = "bench")] bench_calendar( &mut group, - "calendar/chinese", + "calendar/chinese_calculating", icu::calendar::chinese::Chinese::new_always_calculating(), ); + #[cfg(feature = "bench")] + bench_calendar( + &mut group, + "calendar/chinese_cached", + icu::calendar::chinese::Chinese::new(), + ); + #[cfg(feature = "bench")] bench_calendar( &mut group, diff --git a/components/calendar/benches/date.rs b/components/calendar/benches/date.rs index 123834575a0..75aba74ceed 100644 --- a/components/calendar/benches/date.rs +++ b/components/calendar/benches/date.rs @@ -139,7 +139,7 @@ fn date_benches(c: &mut Criterion) { #[cfg(feature = "bench")] bench_calendar( &mut group, - "calendar/chinese", + "calendar/chinese_calculating", &fxs, icu::calendar::chinese::Chinese::new_always_calculating(), |y, m, d| { @@ -156,7 +156,24 @@ fn date_benches(c: &mut Criterion) { #[cfg(feature = "bench")] bench_calendar( &mut group, - "calendar/dangi", + "calendar/chinese_cached", + &fxs, + icu::calendar::chinese::Chinese::new(), + |y, m, d| { + Date::try_new_chinese_date_with_calendar( + y, + m, + d, + icu::calendar::chinese::Chinese::new(), + ) + .unwrap() + }, + ); + + #[cfg(feature = "bench")] + bench_calendar( + &mut group, + "calendar/dangi_calculating", &fxs, icu::calendar::dangi::Dangi::new_always_calculating(), |y, m, d| { @@ -170,6 +187,18 @@ fn date_benches(c: &mut Criterion) { }, ); + #[cfg(feature = "bench")] + bench_calendar( + &mut group, + "calendar/dangi_cached", + &fxs, + icu::calendar::dangi::Dangi::new(), + |y, m, d| { + Date::try_new_dangi_date_with_calendar(y, m, d, icu::calendar::dangi::Dangi::new()) + .unwrap() + }, + ); + #[cfg(feature = "bench")] bench_calendar( &mut group, diff --git a/components/calendar/benches/datetime.rs b/components/calendar/benches/datetime.rs index 99f6cc4ed44..bc1ef631baa 100644 --- a/components/calendar/benches/datetime.rs +++ b/components/calendar/benches/datetime.rs @@ -117,7 +117,7 @@ fn datetime_benches(c: &mut Criterion) { #[cfg(feature = "bench")] bench_calendar( &mut group, - "calendar/chinese", + "calendar/chinese_calculating", &fxs, icu::calendar::chinese::Chinese::new_always_calculating(), |y, m, d, h, min, s| { @@ -134,6 +134,26 @@ fn datetime_benches(c: &mut Criterion) { }, ); + #[cfg(feature = "bench")] + bench_calendar( + &mut group, + "calendar/chinese_cached", + &fxs, + icu::calendar::chinese::Chinese::new(), + |y, m, d, h, min, s| { + DateTime::try_new_chinese_datetime_with_calendar( + y, + m, + d, + h, + min, + s, + icu::calendar::chinese::Chinese::new(), + ) + .unwrap() + }, + ); + #[cfg(feature = "bench")] bench_calendar( &mut group, diff --git a/components/calendar/src/any_calendar.rs b/components/calendar/src/any_calendar.rs index 10a0c569e1e..03030cf182b 100644 --- a/components/calendar/src/any_calendar.rs +++ b/components/calendar/src/any_calendar.rs @@ -575,9 +575,9 @@ impl AnyCalendar { pub const fn new(kind: AnyCalendarKind) -> Self { match kind { AnyCalendarKind::Buddhist => AnyCalendar::Buddhist(Buddhist), - AnyCalendarKind::Chinese => AnyCalendar::Chinese(Chinese), + AnyCalendarKind::Chinese => AnyCalendar::Chinese(Chinese::new()), AnyCalendarKind::Coptic => AnyCalendar::Coptic(Coptic), - AnyCalendarKind::Dangi => AnyCalendar::Dangi(Dangi), + AnyCalendarKind::Dangi => AnyCalendar::Dangi(Dangi::new()), AnyCalendarKind::Ethiopian => AnyCalendar::Ethiopian(Ethiopian::new_with_era_style( EthiopianEraStyle::AmeteMihret, )), @@ -613,9 +613,13 @@ impl AnyCalendar { { Ok(match kind { AnyCalendarKind::Buddhist => AnyCalendar::Buddhist(Buddhist), - AnyCalendarKind::Chinese => AnyCalendar::Chinese(Chinese), + AnyCalendarKind::Chinese => { + AnyCalendar::Chinese(Chinese::try_new_with_any_provider(provider)?) + } AnyCalendarKind::Coptic => AnyCalendar::Coptic(Coptic), - AnyCalendarKind::Dangi => AnyCalendar::Dangi(Dangi), + AnyCalendarKind::Dangi => { + AnyCalendar::Dangi(Dangi::try_new_with_any_provider(provider)?) + } AnyCalendarKind::Ethiopian => AnyCalendar::Ethiopian(Ethiopian::new_with_era_style( EthiopianEraStyle::AmeteMihret, )), @@ -654,9 +658,13 @@ impl AnyCalendar { { Ok(match kind { AnyCalendarKind::Buddhist => AnyCalendar::Buddhist(Buddhist), - AnyCalendarKind::Chinese => AnyCalendar::Chinese(Chinese), + AnyCalendarKind::Chinese => { + AnyCalendar::Chinese(Chinese::try_new_with_buffer_provider(provider)?) + } AnyCalendarKind::Coptic => AnyCalendar::Coptic(Coptic), - AnyCalendarKind::Dangi => AnyCalendar::Dangi(Dangi), + AnyCalendarKind::Dangi => { + AnyCalendar::Dangi(Dangi::try_new_with_buffer_provider(provider)?) + } AnyCalendarKind::Ethiopian => AnyCalendar::Ethiopian(Ethiopian::new_with_era_style( EthiopianEraStyle::AmeteMihret, )), @@ -689,13 +697,15 @@ impl AnyCalendar { where P: DataProvider + DataProvider + + DataProvider + + DataProvider + ?Sized, { Ok(match kind { AnyCalendarKind::Buddhist => AnyCalendar::Buddhist(Buddhist), - AnyCalendarKind::Chinese => AnyCalendar::Chinese(Chinese), + AnyCalendarKind::Chinese => AnyCalendar::Chinese(Chinese::try_new_unstable(provider)?), AnyCalendarKind::Coptic => AnyCalendar::Coptic(Coptic), - AnyCalendarKind::Dangi => AnyCalendar::Dangi(Dangi), + AnyCalendarKind::Dangi => AnyCalendar::Dangi(Dangi::try_new_unstable(provider)?), AnyCalendarKind::Ethiopian => AnyCalendar::Ethiopian(Ethiopian::new_with_era_style( EthiopianEraStyle::AmeteMihret, )), @@ -759,6 +769,8 @@ impl AnyCalendar { where P: DataProvider + DataProvider + + DataProvider + + DataProvider + ?Sized, { let kind = AnyCalendarKind::from_data_locale_with_fallback(locale); @@ -1026,9 +1038,9 @@ impl AnyCalendarKind { fn debug_name(self) -> &'static str { match self { AnyCalendarKind::Buddhist => Buddhist.debug_name(), - AnyCalendarKind::Chinese => Chinese.debug_name(), + AnyCalendarKind::Chinese => Chinese::DEBUG_NAME, AnyCalendarKind::Coptic => Coptic.debug_name(), - AnyCalendarKind::Dangi => Dangi.debug_name(), + AnyCalendarKind::Dangi => Dangi::DEBUG_NAME, AnyCalendarKind::Ethiopian => Ethiopian(false).debug_name(), AnyCalendarKind::EthiopianAmeteAlem => Ethiopian(true).debug_name(), AnyCalendarKind::Gregorian => Gregorian.debug_name(), @@ -1131,10 +1143,10 @@ impl IntoAnyCalendar for Buddhist { impl IntoAnyCalendar for Chinese { fn to_any(self) -> AnyCalendar { - AnyCalendar::Chinese(Chinese) + AnyCalendar::Chinese(self) } fn to_any_cloned(&self) -> AnyCalendar { - AnyCalendar::Chinese(Chinese) + AnyCalendar::Chinese(self.clone()) } fn date_to_any(&self, d: &Self::DateInner) -> AnyDateInner { AnyDateInner::Chinese(*d) @@ -1155,10 +1167,10 @@ impl IntoAnyCalendar for Coptic { impl IntoAnyCalendar for Dangi { fn to_any(self) -> AnyCalendar { - AnyCalendar::Dangi(Dangi) + AnyCalendar::Dangi(self) } fn to_any_cloned(&self) -> AnyCalendar { - AnyCalendar::Dangi(Dangi) + AnyCalendar::Dangi(self.clone()) } fn date_to_any(&self, d: &Self::DateInner) -> AnyDateInner { AnyDateInner::Dangi(*d) diff --git a/components/calendar/src/chinese.rs b/components/calendar/src/chinese.rs index df14c248304..1d4bd904bf0 100644 --- a/components/calendar/src/chinese.rs +++ b/components/calendar/src/chinese.rs @@ -7,7 +7,7 @@ //! ```rust //! use icu::calendar::{chinese::Chinese, Date, DateTime, Ref}; //! -//! let chinese = Chinese::new_always_calculating(); +//! let chinese = Chinese::new(); //! let chinese = Ref(&chinese); // to avoid cloning //! //! // `Date` type @@ -47,10 +47,13 @@ use crate::chinese_based::{ ChineseBasedPrecomputedData, ChineseBasedWithDataLoading, ChineseBasedYearInfo, }; use crate::iso::Iso; +use crate::provider::chinese_based::ChineseCacheV1Marker; use crate::types::{Era, FormattableYear}; use crate::AsCalendar; use crate::{types, Calendar, CalendarError, Date, DateDuration, DateDurationUnit, DateTime}; +use core::cmp::Ordering; use core::num::NonZeroU8; +use icu_provider::prelude::*; use tinystr::tinystr; /// The Chinese Calendar @@ -101,9 +104,10 @@ use tinystr::tinystr; /// /// This calendar is currently in a preview state: formatting for this calendar is not /// going to be perfect. -#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[non_exhaustive] // we'll be adding precompiled data to this -pub struct Chinese; +#[derive(Clone, Debug, Default)] +pub struct Chinese { + data: Option>, +} /// The inner date type used for representing [`Date`]s of [`Chinese`]. See [`Date`] and [`Chinese`] for more details. #[derive(Debug, Eq, PartialEq, PartialOrd, Ord)] @@ -119,14 +123,67 @@ impl Clone for ChineseDateInner { } } +// These impls just make custom derives on types containing C +// work. They're basically no-ops +impl PartialEq for Chinese { + fn eq(&self, _: &Self) -> bool { + true + } +} +impl Eq for Chinese {} +#[allow(clippy::non_canonical_partial_ord_impl)] // this is intentional +impl PartialOrd for Chinese { + fn partial_cmp(&self, _: &Self) -> Option { + Some(Ordering::Equal) + } +} + +impl Ord for Chinese { + fn cmp(&self, _: &Self) -> Ordering { + Ordering::Equal + } +} + impl Chinese { - /// Construct a new [`Chinese`] without any precomputed calendrical calculations. + /// Creates a new [`Chinese`] with some precomputed calendrical calculations. + /// + /// ✨ *Enabled with the `compiled_data` Cargo feature.* /// - /// This is the only mode currently possible, but once precomputing is available (#3933) - /// there will be additional constructors that load from data providers. + /// [📚 Help choosing a constructor](icu_provider::constructors) + #[cfg(feature = "compiled_data")] + pub const fn new() -> Self { + Self { + data: Some(DataPayload::from_static_ref( + crate::provider::Baked::SINGLETON_CALENDAR_CHINESECACHE_V1, + )), + } + } + + icu_provider::gen_any_buffer_data_constructors!(locale: skip, options: skip, error: CalendarError, + #[cfg(skip)] + functions: [ + new, + try_new_with_any_provider, + try_new_with_buffer_provider, + try_new_unstable, + Self, + ]); + + #[doc = icu_provider::gen_any_buffer_unstable_docs!(UNSTABLE, Self::new)] + pub fn try_new_unstable + ?Sized>( + provider: &D, + ) -> Result { + Ok(Self { + data: Some(provider.load(Default::default())?.take_payload()?), + }) + } + + /// Construct a new [`Chinese`] without any precomputed calendrical calculations. pub fn new_always_calculating() -> Self { - Chinese + Chinese { data: None } } + + pub(crate) const DEBUG_NAME: &'static str = "Chinese"; } impl Calendar for Chinese { @@ -167,7 +224,7 @@ impl Calendar for Chinese { ChineseDateInner(Inner::chinese_based_date_from_fixed( self, fixed, - iso.year().number, + iso.inner.0, )) } @@ -211,7 +268,7 @@ impl Calendar for Chinese { /// Obtain a name for the calendar for debug printing fn debug_name(&self) -> &'static str { - "Chinese" + Self::DEBUG_NAME } /// The calendar-specific year represented by `date` @@ -347,7 +404,7 @@ type ChineseCB = calendrical_calculations::chinese_based::Chinese; impl ChineseBasedWithDataLoading for Chinese { type CB = ChineseCB; fn get_precomputed_data(&self) -> ChineseBasedPrecomputedData { - Default::default() + ChineseBasedPrecomputedData::new(self.data.as_ref().map(|d| d.get())) } } @@ -389,6 +446,15 @@ mod test { use super::*; use crate::types::MonthCode; use calendrical_calculations::rata_die::RataDie; + /// Run a test twice, with two calendars + fn do_twice( + chinese_calculating: &Chinese, + chinese_cached: &Chinese, + test: impl Fn(crate::Ref, &'static str), + ) { + test(crate::Ref(chinese_calculating), "calculating"); + test(crate::Ref(chinese_cached), "cached"); + } #[test] fn test_chinese_from_fixed() { @@ -475,23 +541,31 @@ mod test { }, ]; - let chinese = Chinese; + let chinese_calculating = Chinese::new_always_calculating(); + let chinese_cached = Chinese::new(); for case in cases { let rata_die = RataDie::new(case.fixed); let iso = Iso::iso_from_fixed(rata_die); - let chinese = - Inner::chinese_based_date_from_fixed(&chinese, rata_die, iso.year().number); - assert_eq!( - case.expected_year, chinese.0.year, - "Chinese from fixed failed for case: {case:?}" - ); - assert_eq!( - case.expected_month, chinese.0.month, - "Chinese from fixed failed for case: {case:?}" - ); - assert_eq!( - case.expected_day, chinese.0.day, - "Chinese from fixed failed for case: {case:?}" + + do_twice( + &chinese_calculating, + &chinese_cached, + |chinese, calendar_type| { + let chinese = + Inner::chinese_based_date_from_fixed(chinese.0, rata_die, iso.inner.0); + assert_eq!( + case.expected_year, chinese.0.year, + "[{calendar_type}] Chinese from fixed failed, case: {case:?}" + ); + assert_eq!( + case.expected_month, chinese.0.month, + "[{calendar_type}] Chinese from fixed failed, case: {case:?}" + ); + assert_eq!( + case.expected_day, chinese.0.day, + "[{calendar_type}] Chinese from fixed failed, case: {case:?}" + ); + }, ); } } @@ -522,15 +596,23 @@ mod test { }, ]; - let chinese = Chinese::new_always_calculating(); - let chinese = crate::Ref(&chinese); + let chinese_calculating = Chinese::new_always_calculating(); + let chinese_cached = Chinese::new(); for case in cases { - let date = - Date::try_new_chinese_date_with_calendar(case.year, case.month, case.day, chinese) + do_twice( + &chinese_calculating, + &chinese_cached, + |chinese, calendar_type| { + let date = Date::try_new_chinese_date_with_calendar( + case.year, case.month, case.day, chinese, + ) .unwrap(); - let fixed = Inner::fixed_from_chinese_based_date_inner(date.inner.0).to_i64_date(); - let expected = case.expected; - assert_eq!(fixed, expected, "Fixed from Chinese failed with expected: {fixed} and calculated: {expected}, for test case: {case:?}"); + let fixed = + Inner::fixed_from_chinese_based_date_inner(date.inner.0).to_i64_date(); + let expected = case.expected; + assert_eq!(fixed, expected, "[{calendar_type}] Fixed from Chinese failed, with expected: {fixed} and calculated: {expected}, for test case: {case:?}"); + }, + ); } } @@ -540,15 +622,23 @@ mod test { let max_fixed = 1963020; let mut iters = 0; let max_iters = 560; - let chinese = Chinese; + let chinese_calculating = Chinese::new_always_calculating(); + let chinese_cached = Chinese::new(); while fixed < max_fixed && iters < max_iters { let rata_die = RataDie::new(fixed); let iso = Iso::iso_from_fixed(rata_die); - let chinese = - Inner::chinese_based_date_from_fixed(&chinese, rata_die, iso.year().number); - let result = Inner::fixed_from_chinese_based_date_inner(chinese); - let result_debug = result.to_i64_date(); - assert_eq!(result, rata_die, "Failed roundtrip fixed -> Chinese -> fixed for fixed: {fixed}, with calculated: {result_debug} from Chinese date:\n{chinese:?}"); + + do_twice( + &chinese_calculating, + &chinese_cached, + |chinese, calendar_type| { + let chinese = + Inner::chinese_based_date_from_fixed(&chinese, rata_die, iso.inner.0); + let result = Inner::fixed_from_chinese_based_date_inner(chinese); + let result_debug = result.to_i64_date(); + assert_eq!(result, rata_die, "[{calendar_type}] Failed roundtrip fixed -> Chinese -> fixed for fixed: {fixed}, with calculated: {result_debug} from Chinese date:\n{chinese:?}"); + }, + ); fixed += 7043; iters += 1; } @@ -557,13 +647,21 @@ mod test { #[test] fn test_chinese_epoch() { let iso = Date::try_new_iso_date(-2636, 2, 15).unwrap(); - let chinese = iso.to_calendar(Chinese); - assert_eq!(chinese.year().number, 1); - assert_eq!(chinese.month().ordinal, 1); - assert_eq!(chinese.month().code.0, "M01"); - assert_eq!(chinese.day_of_month().0, 1); - assert_eq!(chinese.year().cyclic.unwrap().get(), 1); - assert_eq!(chinese.year().related_iso, Some(-2636)); + + do_twice( + &Chinese::new_always_calculating(), + &Chinese::new(), + |chinese, _calendar_type| { + let chinese = iso.to_calendar(chinese); + + assert_eq!(chinese.year().number, 1); + assert_eq!(chinese.month().ordinal, 1); + assert_eq!(chinese.month().code.0, "M01"); + assert_eq!(chinese.day_of_month().0, 1); + assert_eq!(chinese.year().cyclic.unwrap().get(), 1); + assert_eq!(chinese.year().related_iso, Some(-2636)); + }, + ) } #[test] @@ -597,23 +695,32 @@ mod test { }, ]; + let chinese_calculating = Chinese::new_always_calculating(); + let chinese_cached = Chinese::new(); + for case in cases { let iso = Date::try_new_iso_date(case.iso_year, case.iso_month, case.iso_day).unwrap(); - let chinese = iso.to_calendar(Chinese); - assert_eq!( - case.expected_year, - chinese.year().number, - "ISO to Chinese failed for case: {case:?}" - ); - assert_eq!( - case.expected_month, - chinese.month().ordinal, - "ISO to Chinese failed for case: {case:?}" - ); - assert_eq!( - case.expected_day, - chinese.day_of_month().0, - "ISO to Chinese failed for case: {case:?}" + do_twice( + &chinese_calculating, + &chinese_cached, + |chinese, calendar_type| { + let chinese = iso.to_calendar(chinese); + assert_eq!( + case.expected_year, + chinese.year().number, + "[{calendar_type}] ISO to Chinese failed for case: {case:?}" + ); + assert_eq!( + case.expected_month, + chinese.month().ordinal, + "[{calendar_type}] ISO to Chinese failed for case: {case:?}" + ); + assert_eq!( + case.expected_day, + chinese.day_of_month().0, + "[{calendar_type}] ISO to Chinese failed for case: {case:?}" + ); + }, ); } } @@ -628,18 +735,31 @@ mod test { (2017, 7), (2028, 6), ]; + let chinese_calculating = Chinese::new_always_calculating(); + let chinese_cached = Chinese::new(); + for case in expected { let year = case.0; let expected_month = case.1; let iso = Date::try_new_iso_date(year, 6, 1).unwrap(); - let chinese_date = iso.to_calendar(Chinese); - assert!(chinese_date.is_in_leap_year()); - let new_year = chinese_date.inner.0.new_year(); - assert_eq!( - expected_month, - calendrical_calculations::chinese_based::get_leap_month_from_new_year::< - calendrical_calculations::chinese_based::Chinese, - >(new_year) + do_twice( + &chinese_calculating, + &chinese_cached, + |chinese, calendar_type| { + let chinese_date = iso.to_calendar(chinese); + assert!( + chinese_date.is_in_leap_year(), + "[{calendar_type}] {year} should be a leap year" + ); + let new_year = chinese_date.inner.0.new_year(); + assert_eq!( + expected_month, + calendrical_calculations::chinese_based::get_leap_month_from_new_year::< + calendrical_calculations::chinese_based::Chinese, + >(new_year), + "[{calendar_type}] {year} have leap month {expected_month}" + ); + }, ); } } @@ -777,14 +897,23 @@ mod test { }, ]; + let chinese_calculating = Chinese::new_always_calculating(); + let chinese_cached = Chinese::new(); + for case in cases { let iso = Date::try_new_iso_date(case.year, case.month, case.day).unwrap(); - let chinese = iso.to_calendar(Chinese); - let result_code = chinese.month().code.0; - let expected_code = case.expected_code.to_string(); - assert_eq!( - expected_code, result_code, - "Month codes did not match for test case: {case:?}" + do_twice( + &chinese_calculating, + &chinese_cached, + |chinese, calendar_type| { + let chinese = iso.to_calendar(chinese); + let result_code = chinese.month().code.0; + let expected_code = case.expected_code.to_string(); + assert_eq!( + expected_code, result_code, + "[{calendar_type}] Month codes did not match for test case: {case:?}" + ); + }, ); } } @@ -854,14 +983,23 @@ mod test { #[test] fn test_iso_chinese_roundtrip() { + let chinese_calculating = Chinese::new_always_calculating(); + let chinese_cached = Chinese::new(); + for i in -1000..=1000 { let year = i; let month = i as u8 % 12 + 1; let day = i as u8 % 28 + 1; let iso = Date::try_new_iso_date(year, month, day).unwrap(); - let chinese = iso.to_calendar(Chinese); - let result = chinese.to_calendar(Iso); - assert_eq!(iso, result, "ISO to Chinese roundtrip failed!\nIso: {iso:?}\nChinese: {chinese:?}\nResult: {result:?}"); + do_twice( + &chinese_calculating, + &chinese_cached, + |chinese, calendar_type| { + let chinese = iso.to_calendar(chinese); + let result = chinese.to_calendar(Iso); + assert_eq!(iso, result, "[{calendar_type}] ISO to Chinese roundtrip failed!\nIso: {iso:?}\nChinese: {chinese:?}\nResult: {result:?}"); + }, + ); } } @@ -956,31 +1094,41 @@ mod test { }, ]; + let chinese_calculating = Chinese::new_always_calculating(); + let chinese_cached = Chinese::new(); + for case in cases { let iso = Date::try_new_iso_date(case.iso_year, case.iso_month, case.iso_day).unwrap(); - let chinese = iso.to_calendar(Chinese); - let chinese_rel_iso = chinese.year().related_iso; - let chinese_cyclic = chinese.year().cyclic; - let chinese_month = chinese.month().ordinal; - let chinese_day = chinese.day_of_month().0; - assert_eq!( - chinese_rel_iso, - Some(case.expected_rel_iso), - "Related ISO failed for test case: {case:?}" - ); - assert_eq!( - chinese_cyclic.unwrap().get(), - case.expected_cyclic, - "Cyclic year failed for test case: {case:?}" - ); - assert_eq!( - chinese_month, case.expected_month, - "Month failed for test case: {case:?}" - ); - assert_eq!( - chinese_day, case.expected_day, - "Day failed for test case: {case:?}" + do_twice( + &chinese_calculating, + &chinese_cached, + |chinese, calendar_type| { + let chinese = iso.to_calendar(chinese); + let chinese_rel_iso = chinese.year().related_iso; + let chinese_cyclic = chinese.year().cyclic; + let chinese_month = chinese.month().ordinal; + let chinese_day = chinese.day_of_month().0; + + assert_eq!( + chinese_rel_iso, + Some(case.expected_rel_iso), + "[{calendar_type}] Related ISO failed for test case: {case:?}" + ); + assert_eq!( + chinese_cyclic.unwrap().get(), + case.expected_cyclic, + "[{calendar_type}] Cyclic year failed for test case: {case:?}" + ); + assert_eq!( + chinese_month, case.expected_month, + "[{calendar_type}] Month failed for test case: {case:?}" + ); + assert_eq!( + chinese_day, case.expected_day, + "[{calendar_type}] Day failed for test case: {case:?}" + ); + }, ); } } diff --git a/components/calendar/src/chinese_based.rs b/components/calendar/src/chinese_based.rs index 9c94519333a..ea0ee759ec4 100644 --- a/components/calendar/src/chinese_based.rs +++ b/components/calendar/src/chinese_based.rs @@ -10,7 +10,7 @@ //! //! let iso_date = Date::try_new_iso_date(2023, 6, 23).unwrap(); //! let chinese_date = -//! Date::new_from_iso(iso_date, Chinese::new_always_calculating()); +//! Date::new_from_iso(iso_date, Chinese::new()); //! //! assert_eq!(chinese_date.year().number, 4660); //! assert_eq!(chinese_date.year().related_iso, Some(2023)); @@ -21,12 +21,14 @@ use crate::{ calendar_arithmetic::{ArithmeticDate, CalendarArithmetic, PrecomputedDataSource}, + provider::chinese_based::{ChineseBasedCacheV1, PackedChineseBasedYearInfo}, types::{FormattableMonth, MonthCode}, Calendar, CalendarError, Iso, }; use calendrical_calculations::chinese_based::{self, ChineseBased, YearBounds}; use calendrical_calculations::rata_die::RataDie; +use core::marker::PhantomData; use core::num::NonZeroU8; use tinystr::tinystr; @@ -37,7 +39,7 @@ pub(crate) trait ChineseBasedWithDataLoading: Calendar { type CB: ChineseBased; /// Get the compiled const data for a ChineseBased calendar; can return `None` if the given year /// does not correspond to any compiled data. - fn get_precomputed_data(&self) -> ChineseBasedPrecomputedData; + fn get_precomputed_data(&self) -> ChineseBasedPrecomputedData<'_, Self::CB>; } /// Chinese-based calendars define DateInner as a calendar-specific struct wrapping ChineseBasedDateInner. @@ -55,22 +57,39 @@ impl Clone for ChineseBasedDateInner { /// Contains any loaded precomputed data. If constructed with Default, will /// *not* contain any extra data and will always compute stuff from scratch #[derive(Default)] -pub(crate) struct ChineseBasedPrecomputedData { - // TODO(#3933) - // this should have the ability to be empty - _cb: CB, // this is zero-sized +pub(crate) struct ChineseBasedPrecomputedData<'a, CB: ChineseBased> { + data: Option<&'a ChineseBasedCacheV1<'a>>, + _cb: PhantomData, } -/// The first day of the ISO year on which Chinese New Year may occur -/// -/// According to Reingold & Dershowitz, ch 19.6, Chinese New Year occurs on Jan 21 - Feb 21 inclusive. -/// -/// Chinese New Year in the year 30 AD is January 20 (30-01-20) -const FIRST_NY: u8 = 20; - +/// Compute ChineseBasedYearInfo for a given extended year fn compute_cache(extended_year: i32) -> ChineseBasedYearInfo { let mid_year = chinese_based::fixed_mid_year_from_year::(extended_year); let year_bounds = YearBounds::compute::(mid_year); + compute_cache_with_yb::(extended_year, year_bounds) +} + +/// Compute ChineseBasedYearInfo for a given extended year, for which you have already computed the YearBounds +fn compute_cache_with_yb( + extended_year: i32, + year_bounds: YearBounds, +) -> ChineseBasedYearInfo { + let YearBounds { new_year, .. } = year_bounds; + + let days_in_prev_year = chinese_based::days_in_prev_year::(new_year); + + let packed_data = compute_packed_with_yb::(extended_year, year_bounds); + + ChineseBasedYearInfo { + days_in_prev_year, + packed_data, + } +} + +fn compute_packed_with_yb( + extended_year: i32, + year_bounds: YearBounds, +) -> PackedChineseBasedYearInfo { let YearBounds { new_year, next_new_year, @@ -83,125 +102,75 @@ fn compute_cache(extended_year: i32) -> ChineseBasedYearInfo { let iso_ny = calendrical_calculations::iso::fixed_from_iso(related_iso, 1, 1); // +1 because `new_year - iso_ny` is zero-indexed, but `FIRST_NY` is 1-indexed - let ny_offset = new_year - iso_ny - i64::from(FIRST_NY) + 1; + let ny_offset = new_year - iso_ny - i64::from(PackedChineseBasedYearInfo::FIRST_NY) + 1; let ny_offset = if let Ok(ny_offset) = u8::try_from(ny_offset) { ny_offset } else { debug_assert!(false, "Expected small new years offset, got {ny_offset}"); 0 }; - let days_in_prev_year = chinese_based::days_in_prev_year::(new_year); - - let packed_data = PackedChineseBasedYearInfo::new(month_lengths, leap_month, ny_offset); + PackedChineseBasedYearInfo::new(month_lengths, leap_month, ny_offset) +} - ChineseBasedYearInfo { - days_in_prev_year, - packed_data, - } +#[cfg(feature = "datagen")] +pub(crate) fn compute_many_packed( + extended_years: core::ops::Range, +) -> alloc::vec::Vec { + extended_years + .map(|extended_year| { + let mid_year = chinese_based::fixed_mid_year_from_year::(extended_year); + let year_bounds = YearBounds::compute::(mid_year); + + compute_packed_with_yb::(extended_year, year_bounds) + }) + .collect() } -impl PrecomputedDataSource - for ChineseBasedPrecomputedData +impl<'b, CB: ChineseBased> PrecomputedDataSource + for ChineseBasedPrecomputedData<'b, CB> { fn load_or_compute_info(&self, extended_year: i32) -> ChineseBasedYearInfo { - // TODO(#3933): load based on year - - compute_cache::(extended_year) + self.data + .and_then(|d| d.get_for_extended_year(extended_year)) + .unwrap_or_else(|| compute_cache::(extended_year)) } } -/// The struct containing compiled ChineseData -/// -/// Bit structure (little endian: note that shifts go in the opposite direction!) -/// -/// ```text -/// Bit: 0 1 2 3 4 5 6 7 -/// Byte 0: [ month lengths ............. -/// Byte 1: .. month lengths ] | [ leap month index .. -/// Byte 2: ] | [ NY offset ] | unused -/// ``` -/// -/// Where the New Year Offset is the offset from ISO Jan 21 of that year for Chinese New Year, -/// the month lengths are stored as 1 = 30, 0 = 29 for each month including the leap month. -/// -/// Should not -#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] -pub(crate) struct PackedChineseBasedYearInfo(pub(crate) u8, pub(crate) u8, pub(crate) u8); - -impl PackedChineseBasedYearInfo { - fn new(month_lengths: [bool; 13], leap_month_idx: Option, ny_offset: u8) -> Self { - debug_assert!( - !month_lengths[12] || leap_month_idx.is_some(), - "Last month length should not be set for non-leap years" - ); - debug_assert!(ny_offset < 32, "Year offset too big to store"); - debug_assert!( - leap_month_idx.map(|l| l.get() <= 13).unwrap_or(true), - "Leap month indices must be 1 <= i <= 13" - ); - let mut all = 0u32; // last byte unused - - for (month, length_30) in month_lengths.iter().enumerate() { - #[allow(clippy::indexing_slicing)] - if *length_30 { - all |= 1 << month as u32; - } +impl<'b, CB: ChineseBased> ChineseBasedPrecomputedData<'b, CB> { + pub(crate) fn new(data: Option<&'b ChineseBasedCacheV1<'b>>) -> Self { + Self { + data, + _cb: PhantomData, } - let leap_month_idx = leap_month_idx.map(|x| x.get()).unwrap_or(0); - all |= (leap_month_idx as u32) << (8 + 5); - all |= (ny_offset as u32) << (16 + 1); - let le = all.to_le_bytes(); - Self(le[0], le[1], le[2]) - } - - // Get the new year offset from January 21 - fn ny_offset(self) -> u8 { - self.2 >> 1 - } - - fn ny_rd(self, related_iso: i32) -> RataDie { - let ny_offset = self.ny_offset(); - let iso_ny = calendrical_calculations::iso::fixed_from_iso(related_iso, 1, 1); - // -1 because `iso_ny` is itself in the year, and `FIRST_NY` is 1-indexed - iso_ny + i64::from(FIRST_NY) + i64::from(ny_offset) - 1 - } - - fn leap_month_idx(self) -> Option { - let low_bits = self.1 >> 5; - let high_bits = (self.2 & 0b1) << 3; - - NonZeroU8::new(low_bits + high_bits) - } - - // Whether a particular month has 30 days (month is 1-indexed) - #[cfg(test)] - fn month_has_30_days(self, month: u8) -> bool { - let months = u16::from_le_bytes([self.0, self.1]); - months & (1 << (month - 1) as u16) != 0 - } - - // Which day of year is the last day of a month (month is 1-indexed) - fn last_day_of_month(self, month: u8) -> u16 { - let months = u16::from_le_bytes([self.0, self.1]); - // month is 1-indexed, so `29 * month` includes the current month - let mut prev_month_lengths = 29 * month as u16; - // month is 1-indexed, so `1 << month` is a mask with all zeroes except - // for a 1 at the bit index at the next month. Subtracting 1 from it gets us - // a bitmask for all months up to now - let long_month_bits = months & ((1 << month as u16) - 1); - prev_month_lengths += long_month_bits.count_ones().try_into().unwrap_or(0); - prev_month_lengths } - - fn days_in_year(self) -> u16 { - if self.leap_month_idx().is_some() { - self.last_day_of_month(13) + /// Given an ISO date (in both ArithmeticDate and R.D. format), returns the ChineseBasedYearInfo and extended year for that date, loading + /// from cache or computing. + fn load_or_compute_info_for_iso( + &self, + fixed: RataDie, + iso: ArithmeticDate, + ) -> (ChineseBasedYearInfo, i32) { + let cached = self.data.and_then(|d| d.get_for_iso::(iso)); + if let Some(cached) = cached { + return cached; + }; + // compute + + let extended_year = CB::extended_from_iso(iso.year); + let mid_year = chinese_based::fixed_mid_year_from_year::(extended_year); + let year_bounds = YearBounds::compute::(mid_year); + let YearBounds { new_year, .. } = year_bounds; + if fixed >= new_year { + ( + compute_cache_with_yb::(extended_year, year_bounds), + extended_year, + ) } else { - self.last_day_of_month(12) + let extended_year = extended_year - 1; + (compute_cache::(extended_year), extended_year) } } } - /// A data struct used to load and use information for a set of ChineseBasedDates #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] // TODO(#3933): potentially make this smaller @@ -215,6 +184,13 @@ pub(crate) struct ChineseBasedYearInfo { } impl ChineseBasedYearInfo { + pub(crate) fn new(days_in_prev_year: u16, packed_data: PackedChineseBasedYearInfo) -> Self { + Self { + days_in_prev_year, + packed_data, + } + } + /// Get the new year R.D. given the extended year that this yearinfo is for pub(crate) fn new_year(self, extended_year: i32) -> RataDie { self.packed_data.ny_rd(CB::iso_from_extended(extended_year)) @@ -281,28 +257,6 @@ impl ChineseBasedYearInfo { impl> ChineseBasedDateInner { - /// Given a 1-indexed chinese extended year, fetch its data from the cache. - /// - /// If the actual year data that was fetched is for a different year, update the getter year - fn get_precomputed_data_for_year_helper( - cal: &C, - date: RataDie, - getter_year: &mut i32, - ) -> ChineseBasedYearInfo { - let data = cal.get_precomputed_data(); - let year_info = data.load_or_compute_info(*getter_year); - if date < year_info.new_year::(*getter_year) { - *getter_year -= 1; - data.load_or_compute_info(*getter_year) - // FIXME (manishearth) try collapsing these new year calculations into one - } else if date >= year_info.next_new_year::(*getter_year) { - *getter_year += 1; - data.load_or_compute_info(*getter_year) - } else { - year_info - } - } - /// Get a ChineseBasedDateInner from a fixed date and the cache/extended year associated with it fn chinese_based_date_from_info( date: RataDie, @@ -350,18 +304,18 @@ impl, ) -> ChineseBasedDateInner { - // Get the 1-indexed Chinese extended year, used for fetching data from the cache - let epoch_as_iso = Iso::iso_from_fixed(C::CB::EPOCH); - let mut getter_year = iso_year - epoch_as_iso.year().number + 1; + let data = cal.get_precomputed_data(); + + let (year_info, extended_year) = data.load_or_compute_info_for_iso(fixed, iso); - let year_info = Self::get_precomputed_data_for_year_helper(cal, date, &mut getter_year); - Self::chinese_based_date_from_info(date, year_info, getter_year) + Self::chinese_based_date_from_info(fixed, year_info, extended_year) } pub(crate) fn new_year(self) -> RataDie { diff --git a/components/calendar/src/dangi.rs b/components/calendar/src/dangi.rs index 2eeee247200..32eb8c2022d 100644 --- a/components/calendar/src/dangi.rs +++ b/components/calendar/src/dangi.rs @@ -8,7 +8,7 @@ //! use icu::calendar::dangi::Dangi; //! use icu::calendar::{Date, DateTime, Ref}; //! -//! let dangi = Dangi::new_always_calculating(); +//! let dangi = Dangi::new(); //! let dangi = Ref(&dangi); // to avoid cloning //! //! // `Date` type @@ -45,13 +45,16 @@ use crate::chinese_based::{ chinese_based_ordinal_lunar_month_from_code, ChineseBasedPrecomputedData, ChineseBasedWithDataLoading, ChineseBasedYearInfo, }; +use crate::provider::chinese_based::DangiCacheV1Marker; use crate::AsCalendar; use crate::{ chinese_based::ChineseBasedDateInner, types::{self, Era, FormattableYear}, AnyCalendarKind, Calendar, CalendarError, Date, DateTime, Iso, }; +use core::cmp::Ordering; use core::num::NonZeroU8; +use icu_provider::prelude::*; use tinystr::tinystr; /// The Dangi Calendar @@ -71,15 +74,15 @@ use tinystr::tinystr; /// use tinystr::tinystr; /// /// let iso_a = Date::try_new_iso_date(2012, 4, 23).unwrap(); -/// let dangi_a = iso_a.to_calendar(Dangi::new_always_calculating()); -/// let chinese_a = iso_a.to_calendar(Chinese::new_always_calculating()); +/// let dangi_a = iso_a.to_calendar(Dangi::new()); +/// let chinese_a = iso_a.to_calendar(Chinese::new()); /// /// assert_eq!(dangi_a.month().code.0, tinystr!(4, "M03L")); /// assert_eq!(chinese_a.month().code.0, tinystr!(4, "M04")); /// /// let iso_b = Date::try_new_iso_date(2012, 5, 23).unwrap(); -/// let dangi_b = iso_b.to_calendar(Dangi::new_always_calculating()); -/// let chinese_b = iso_b.to_calendar(Chinese::new_always_calculating()); +/// let dangi_b = iso_b.to_calendar(Dangi::new()); +/// let chinese_b = iso_b.to_calendar(Chinese::new()); /// /// assert_eq!(dangi_b.month().code.0, tinystr!(4, "M04")); /// assert_eq!(chinese_b.month().code.0, tinystr!(4, "M04L")); @@ -93,9 +96,10 @@ use tinystr::tinystr; /// /// This calendar is a lunisolar calendar. It supports regular month codes `"M01" - "M12"` as well /// as leap month codes `"M01L" - "M12L"`. -#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[non_exhaustive] // we'll be adding precompiled data to this -pub struct Dangi; +#[derive(Clone, Debug, Default)] +pub struct Dangi { + data: Option>, +} /// The inner date type used for representing [`Date`]s of [`Dangi`]. See [`Date`] and [`Dangi`] for more detail. #[derive(Debug, Eq, PartialEq, PartialOrd, Ord)] @@ -111,14 +115,67 @@ impl Clone for DangiDateInner { } } +// These impls just make custom derives on types containing C +// work. They're basically no-ops +impl PartialEq for Dangi { + fn eq(&self, _: &Self) -> bool { + true + } +} +impl Eq for Dangi {} +#[allow(clippy::non_canonical_partial_ord_impl)] // this is intentional +impl PartialOrd for Dangi { + fn partial_cmp(&self, _: &Self) -> Option { + Some(Ordering::Equal) + } +} + +impl Ord for Dangi { + fn cmp(&self, _: &Self) -> Ordering { + Ordering::Equal + } +} + impl Dangi { - /// Construct a new [`Dangi`] without any precomputed calendrical calculations. + /// Creates a new [`Dangi`] with some precomputed calendrical calculations. /// - /// This is the only mode currently possible, but once precomputing is available (#3933) - /// there will be additional constructors that load from data providers. + /// ✨ *Enabled with the `compiled_data` Cargo feature.* + /// + /// [📚 Help choosing a constructor](icu_provider::constructors) + #[cfg(feature = "compiled_data")] + pub const fn new() -> Self { + Self { + data: Some(DataPayload::from_static_ref( + crate::provider::Baked::SINGLETON_CALENDAR_DANGICACHE_V1, + )), + } + } + + icu_provider::gen_any_buffer_data_constructors!(locale: skip, options: skip, error: CalendarError, + #[cfg(skip)] + functions: [ + new, + try_new_with_any_provider, + try_new_with_buffer_provider, + try_new_unstable, + Self, + ]); + + #[doc = icu_provider::gen_any_buffer_unstable_docs!(UNSTABLE, Self::new)] + pub fn try_new_unstable + ?Sized>( + provider: &D, + ) -> Result { + Ok(Self { + data: Some(provider.load(Default::default())?.take_payload()?), + }) + } + + /// Construct a new [`Dangi`] without any precomputed calendrical calculations. pub fn new_always_calculating() -> Self { - Dangi + Dangi { data: None } } + + pub(crate) const DEBUG_NAME: &'static str = "Dangi"; } impl Calendar for Dangi { @@ -157,7 +214,7 @@ impl Calendar for Dangi { DangiDateInner(Inner::chinese_based_date_from_fixed( self, fixed, - iso.year().number, + iso.inner.0, )) } @@ -194,7 +251,7 @@ impl Calendar for Dangi { } fn debug_name(&self) -> &'static str { - "Dangi" + Self::DEBUG_NAME } fn year(&self, date: &Self::DateInner) -> crate::types::FormattableYear { @@ -247,7 +304,7 @@ impl> Date { /// use icu::calendar::dangi::Dangi; /// use icu::calendar::Date; /// - /// let dangi = Dangi::new_always_calculating(); + /// let dangi = Dangi::new(); /// /// let date_dangi = Date::try_new_dangi_date_with_calendar(4356, 6, 18, dangi) /// .expect("Failed to initialize Dangi Date instance."); @@ -286,7 +343,7 @@ impl> DateTime { /// use icu::calendar::dangi::Dangi; /// use icu::calendar::DateTime; /// - /// let dangi = Dangi::new_always_calculating(); + /// let dangi = Dangi::new(); /// /// let dangi_datetime = DateTime::try_new_dangi_datetime_with_calendar( /// 4356, 6, 6, 13, 1, 0, dangi, @@ -322,7 +379,7 @@ type DangiCB = calendrical_calculations::chinese_based::Dangi; impl ChineseBasedWithDataLoading for Dangi { type CB = DangiCB; fn get_precomputed_data(&self) -> ChineseBasedPrecomputedData { - Default::default() + ChineseBasedPrecomputedData::new(self.data.as_ref().map(|d| d.get())) } } @@ -361,10 +418,20 @@ mod test { use crate::chinese::Chinese; use calendrical_calculations::rata_die::RataDie; + /// Run a test twice, with two calendars + fn do_twice( + dangi_calculating: &Dangi, + dangi_cached: &Dangi, + test: impl Fn(crate::Ref, &'static str), + ) { + test(crate::Ref(dangi_calculating), "calculating"); + test(crate::Ref(dangi_cached), "cached"); + } + fn check_cyclic_and_rel_iso(year: i32) { let iso = Date::try_new_iso_date(year, 6, 6).unwrap(); - let chinese = iso.to_calendar(Chinese); - let dangi = iso.to_calendar(Dangi); + let chinese = iso.to_calendar(Chinese::new_always_calculating()); + let dangi = iso.to_calendar(Dangi::new_always_calculating()); let chinese_year = chinese.year().cyclic; let korean_year = dangi.year().cyclic; assert_eq!( @@ -400,15 +467,20 @@ mod test { let max_fixed = 1963020; let mut iters = 0; let max_iters = 560; + let dangi_calculating = Dangi::new_always_calculating(); + let dangi_cached = Dangi::new(); while fixed < max_fixed && iters < max_iters { let rata_die = RataDie::new(fixed); let iso = Iso::iso_from_fixed(rata_die); - let korean = iso.to_calendar(Dangi); - let result = korean.to_calendar(Iso); - assert_eq!( - iso, result, - "Failed roundtrip ISO -> Dangi -> ISO for fixed: {fixed}" - ); + do_twice(&dangi_calculating, &dangi_cached, |dangi, calendar_type| { + let korean = iso.to_calendar(dangi); + let result = korean.to_calendar(Iso); + assert_eq!( + iso, result, + "[{calendar_type}] Failed roundtrip ISO -> Dangi -> ISO for fixed: {fixed}" + ); + }); + fixed += 7043; iters += 1; } @@ -921,32 +993,37 @@ mod test { }, ]; + let dangi_calculating = Dangi::new_always_calculating(); + let dangi_cached = Dangi::new(); + for case in cases { let iso = Date::try_new_iso_date(case.iso_year, case.iso_month, case.iso_day).unwrap(); - let dangi = iso.to_calendar(Dangi); - let dangi_rel_iso = dangi.year().related_iso; - let dangi_cyclic = dangi.year().cyclic; - let dangi_month = dangi.month().ordinal; - let dangi_day = dangi.day_of_month().0; - - assert_eq!( - dangi_rel_iso, - Some(case.expected_rel_iso), - "Related ISO failed for test case: {case:?}" - ); - assert_eq!( - dangi_cyclic.unwrap().get(), - case.expected_cyclic, - "Cyclic year failed for test case: {case:?}" - ); - assert_eq!( - dangi_month, case.expected_month, - "Month failed for test case: {case:?}" - ); - assert_eq!( - dangi_day, case.expected_day, - "Day failed for test case: {case:?}" - ); + do_twice(&dangi_calculating, &dangi_cached, |dangi, calendar_type| { + let dangi = iso.to_calendar(dangi); + let dangi_rel_iso = dangi.year().related_iso; + let dangi_cyclic = dangi.year().cyclic; + let dangi_month = dangi.month().ordinal; + let dangi_day = dangi.day_of_month().0; + + assert_eq!( + dangi_rel_iso, + Some(case.expected_rel_iso), + "[{calendar_type}] Related ISO failed for test case: {case:?}" + ); + assert_eq!( + dangi_cyclic.unwrap().get(), + case.expected_cyclic, + "[{calendar_type}] Cyclic year failed for test case: {case:?}" + ); + assert_eq!( + dangi_month, case.expected_month, + "[{calendar_type}] Month failed for test case: {case:?}" + ); + assert_eq!( + dangi_day, case.expected_day, + "[{calendar_type}] Day failed for test case: {case:?}" + ); + }); } } } diff --git a/components/calendar/src/provider.rs b/components/calendar/src/provider.rs index 2db29c77090..fc381002fdb 100644 --- a/components/calendar/src/provider.rs +++ b/components/calendar/src/provider.rs @@ -15,6 +15,9 @@ // Provider structs must be stable #![allow(clippy::exhaustive_structs, clippy::exhaustive_enums)] +pub mod chinese_based; +pub use chinese_based::{ChineseCacheV1Marker, DangiCacheV1Marker}; + use crate::types::IsoWeekday; use core::str::FromStr; use icu_provider::prelude::*; @@ -39,6 +42,8 @@ const _: () = { pub use icu_locid_transform as locid_transform; } icu_calendar_data::make_provider!(Baked); + icu_calendar_data::impl_calendar_chinesecache_v1!(Baked); + icu_calendar_data::impl_calendar_dangicache_v1!(Baked); icu_calendar_data::impl_calendar_japanese_v1!(Baked); icu_calendar_data::impl_calendar_japanext_v1!(Baked); icu_calendar_data::impl_datetime_week_data_v1!(Baked); @@ -47,6 +52,8 @@ const _: () = { #[cfg(feature = "datagen")] /// The latest minimum set of keys required by this component. pub const KEYS: &[DataKey] = &[ + ChineseCacheV1Marker::KEY, + DangiCacheV1Marker::KEY, JapaneseErasV1Marker::KEY, JapaneseExtendedErasV1Marker::KEY, WeekDataV1Marker::KEY, diff --git a/components/calendar/src/provider/chinese_based.rs b/components/calendar/src/provider/chinese_based.rs new file mode 100644 index 00000000000..916f3036818 --- /dev/null +++ b/components/calendar/src/provider/chinese_based.rs @@ -0,0 +1,323 @@ +// 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 ). + +//! 🚧 \[Unstable\] Data provider struct definitions for chinese-based calendars. +//! +//!
+//! 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways, +//! including in SemVer minor releases. While the serde representation of data structs is guaranteed +//! to be stable, their Rust representation might not be. Use with caution. +//!
+//! +//! Read more about data providers: [`icu_provider`] + +use crate::calendar_arithmetic::ArithmeticDate; +use crate::chinese_based::ChineseBasedYearInfo; +use crate::Iso; +use calendrical_calculations::chinese_based::ChineseBased; +use calendrical_calculations::rata_die::RataDie; +use core::num::NonZeroU8; +use icu_provider::prelude::*; +use zerovec::ule::{AsULE, ULE}; +use zerovec::ZeroVec; + +/// Cached/precompiled data for a certain range of years for a chinese-based +/// calendar. Avoids the need to perform lunar calendar arithmetic for most calendrical +/// operations. +#[icu_provider::data_struct( + marker(ChineseCacheV1Marker, "calendar/chinesecache@1", singleton), + marker(DangiCacheV1Marker, "calendar/dangicache@1", singleton) +)] +#[derive(Debug, PartialEq, Clone, Default)] +#[cfg_attr( + feature = "datagen", + derive(serde::Serialize, databake::Bake), + databake(path = icu_calendar::provider::chinese_based), +)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize))] +pub struct ChineseBasedCacheV1<'data> { + /// The extended year corresponding to the first data entry for this year + pub first_extended_year: i32, + /// A list of precomputed data for each year beginning with first_extended_year + #[cfg_attr(feature = "serde", serde(borrow))] + pub data: ZeroVec<'data, PackedChineseBasedYearInfo>, +} + +impl<'data> ChineseBasedCacheV1<'data> { + /// Compute this data for a range of years + #[cfg(feature = "datagen")] + pub fn compute_for(extended_years: core::ops::Range) -> Self { + let data = crate::chinese_based::compute_many_packed::(extended_years.clone()); + ChineseBasedCacheV1 { + first_extended_year: extended_years.start, + data: data.into(), + } + } + + /// Get the cached data for a given extended year + pub(crate) fn get_for_extended_year(&self, extended_year: i32) -> Option { + let delta = extended_year - self.first_extended_year; + let delta = usize::try_from(delta).ok()?; + + if delta == 0 { + return None; + } + + let (Some(this_packed), Some(prev_packed)) = + (self.data.get(delta), self.data.get(delta - 1)) + else { + return None; + }; + + let days_in_prev_year = prev_packed.days_in_year(); + + Some(ChineseBasedYearInfo::new(days_in_prev_year, this_packed)) + } + /// Get the cached data for the Chinese Year corresponding to a given day. + /// + /// Also returns the corresponding extended year. + pub(crate) fn get_for_iso( + &self, + iso: ArithmeticDate, + ) -> Option<(ChineseBasedYearInfo, i32)> { + let extended_year = CB::extended_from_iso(iso.year); + let delta = extended_year - self.first_extended_year; + let delta = usize::try_from(delta).ok()?; + if delta <= 1 { + return None; + } + + let Some(this_packed) = self.data.get(delta) else { + return None; + }; + let Some(prev_packed) = self.data.get(delta - 1) else { + return None; + }; + + let iso_in_year = iso.day_of_year(); + let fetched_data_ny_in_iso = u16::from(this_packed.ny_day_of_iso_year()); + + if iso_in_year >= fetched_data_ny_in_iso { + Some(( + ChineseBasedYearInfo::new(prev_packed.days_in_year(), this_packed), + extended_year, + )) + } else { + // We're dealing with an ISO day in the beginning of the year, before Chinese New Year. + // Return data for the previous Chinese year instead. + if delta <= 2 { + return None; + } + let Some(prev2_packed) = self.data.get(delta - 2) else { + return None; + }; + + let days_in_prev_year = prev2_packed.days_in_year(); + + Some(( + ChineseBasedYearInfo::new(days_in_prev_year, prev_packed), + extended_year - 1, + )) + } + } +} + +/// The struct containing compiled ChineseData +/// +/// Bit structure (little endian: note that shifts go in the opposite direction!) +/// +/// ```text +/// Bit: 0 1 2 3 4 5 6 7 +/// Byte 0: [ month lengths ............. +/// Byte 1: .. month lengths ] | [ leap month index .. +/// Byte 2: ] | [ NY offset ] | unused +/// ``` +/// +/// Where the New Year Offset is the offset from ISO Jan 21 of that year for Chinese New Year, +/// the month lengths are stored as 1 = 30, 0 = 29 for each month including the leap month. +/// +///
+/// 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways, +/// including in SemVer minor releases. While the serde representation of data structs is guaranteed +/// to be stable, their Rust representation might not be. Use with caution. +///
+#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ULE)] +#[cfg_attr( + feature = "datagen", + derive(databake::Bake), + databake(path = icu_calendar::provider), +)] +#[repr(packed)] +pub struct PackedChineseBasedYearInfo(pub u8, pub u8, pub u8); + +impl PackedChineseBasedYearInfo { + /// The first day of the ISO year on which Chinese New Year may occur + /// + /// According to Reingold & Dershowitz, ch 19.6, Chinese New Year occurs on Jan 21 - Feb 21 inclusive. + /// + /// Chinese New Year in the year 30 AD is January 20 (30-01-20) + pub(crate) const FIRST_NY: u8 = 20; + + pub(crate) fn new( + month_lengths: [bool; 13], + leap_month_idx: Option, + ny_offset: u8, + ) -> Self { + debug_assert!( + !month_lengths[12] || leap_month_idx.is_some(), + "Last month length should not be set for non-leap years" + ); + debug_assert!(ny_offset < 32, "Year offset too big to store"); + debug_assert!( + leap_month_idx.map(|l| l.get() <= 13).unwrap_or(true), + "Leap month indices must be 1 <= i <= 13" + ); + let mut all = 0u32; // last byte unused + + for (month, length_30) in month_lengths.iter().enumerate() { + #[allow(clippy::indexing_slicing)] + if *length_30 { + all |= 1 << month as u32; + } + } + let leap_month_idx = leap_month_idx.map(|x| x.get()).unwrap_or(0); + all |= (leap_month_idx as u32) << (8 + 5); + all |= (ny_offset as u32) << (16 + 1); + let le = all.to_le_bytes(); + Self(le[0], le[1], le[2]) + } + + // Get the new year offset from January 21 + pub(crate) fn ny_offset(self) -> u8 { + self.2 >> 1 + } + + /// The day of the year (1-indexed) that this is in the ISO year + fn ny_day_of_iso_year(self) -> u8 { + let ny_offset = self.ny_offset(); + // FIRST_NY is one-indexed, offset is an offset, we can just add + Self::FIRST_NY + ny_offset + } + + pub(crate) fn ny_rd(self, related_iso: i32) -> RataDie { + let iso_ny = calendrical_calculations::iso::fixed_from_iso(related_iso, 1, 1); + // -1 because `iso_ny` is itself in the year, and ny_day_of_iso_year + iso_ny + i64::from(self.ny_day_of_iso_year()) - 1 + } + + pub(crate) fn leap_month_idx(self) -> Option { + let low_bits = self.1 >> 5; + let high_bits = (self.2 & 0b1) << 3; + + NonZeroU8::new(low_bits + high_bits) + } + + // Whether a particular month has 30 days (month is 1-indexed) + #[cfg(any(test, feature = "datagen"))] + pub(crate) fn month_has_30_days(self, month: u8) -> bool { + let months = u16::from_le_bytes([self.0, self.1]); + months & (1 << (month - 1) as u16) != 0 + } + + // Which day of year is the last day of a month (month is 1-indexed) + pub(crate) fn last_day_of_month(self, month: u8) -> u16 { + let months = u16::from_le_bytes([self.0, self.1]); + // month is 1-indexed, so `29 * month` includes the current month + let mut prev_month_lengths = 29 * month as u16; + // month is 1-indexed, so `1 << month` is a mask with all zeroes except + // for a 1 at the bit index at the next month. Subtracting 1 from it gets us + // a bitmask for all months up to now + let long_month_bits = months & ((1 << month as u16) - 1); + prev_month_lengths += long_month_bits.count_ones().try_into().unwrap_or(0); + prev_month_lengths + } + + pub(crate) fn days_in_year(self) -> u16 { + if self.leap_month_idx().is_some() { + self.last_day_of_month(13) + } else { + self.last_day_of_month(12) + } + } +} + +impl AsULE for PackedChineseBasedYearInfo { + type ULE = Self; + fn to_unaligned(self) -> Self { + self + } + fn from_unaligned(other: Self) -> Self { + other + } +} + +#[cfg(feature = "serde")] +mod serialization { + use super::*; + + #[cfg(feature = "datagen")] + use serde::{ser, Serialize}; + use serde::{Deserialize, Deserializer}; + + #[derive(Deserialize)] + #[cfg_attr(feature = "datagen", derive(Serialize))] + struct SerdePackedChineseBasedYearInfo { + ny_offset: u8, + month_has_30_days: [bool; 13], + leap_month_idx: Option, + } + + impl<'de> Deserialize<'de> for PackedChineseBasedYearInfo { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + if deserializer.is_human_readable() { + SerdePackedChineseBasedYearInfo::deserialize(deserializer).map(Into::into) + } else { + let data = <(u8, u8, u8)>::deserialize(deserializer)?; + Ok(PackedChineseBasedYearInfo(data.0, data.1, data.2)) + } + } + } + + #[cfg(feature = "datagen")] + impl Serialize for PackedChineseBasedYearInfo { + fn serialize(&self, serializer: S) -> Result + where + S: ser::Serializer, + { + if serializer.is_human_readable() { + SerdePackedChineseBasedYearInfo::from(*self).serialize(serializer) + } else { + (self.0, self.1, self.2).serialize(serializer) + } + } + } + + #[cfg(feature = "datagen")] + impl From for SerdePackedChineseBasedYearInfo { + fn from(other: PackedChineseBasedYearInfo) -> Self { + let mut month_has_30_days = [false; 13]; + for (i, month) in month_has_30_days.iter_mut().enumerate() { + *month = other.month_has_30_days(i as u8 + 1) + } + Self { + ny_offset: other.ny_offset(), + month_has_30_days, + leap_month_idx: other.leap_month_idx(), + } + } + } + + impl From for PackedChineseBasedYearInfo { + fn from(other: SerdePackedChineseBasedYearInfo) -> Self { + Self::new( + other.month_has_30_days, + other.leap_month_idx, + other.ny_offset, + ) + } + } +} diff --git a/components/datetime/src/any/date.rs b/components/datetime/src/any/date.rs index c57081deef8..4aab37e52c5 100644 --- a/components/datetime/src/any/date.rs +++ b/components/datetime/src/any/date.rs @@ -8,7 +8,8 @@ use crate::{input::DateInput, DateTimeError, FormattedDateTime}; use alloc::string::String; use icu_calendar::any_calendar::{AnyCalendar, AnyCalendarKind}; use icu_calendar::provider::{ - JapaneseErasV1Marker, JapaneseExtendedErasV1Marker, WeekDataV1Marker, + ChineseCacheV1Marker, DangiCacheV1Marker, JapaneseErasV1Marker, JapaneseExtendedErasV1Marker, + WeekDataV1Marker, }; use icu_calendar::Date; use icu_decimal::provider::DecimalSymbolsV1Marker; @@ -165,10 +166,13 @@ impl DateFormatter { + DataProvider + DataProvider + DataProvider + + DataProvider + DataProvider + DataProvider + DataProvider + DataProvider + + DataProvider + + DataProvider + DataProvider + DataProvider + DataProvider diff --git a/components/datetime/src/any/datetime.rs b/components/datetime/src/any/datetime.rs index 83709198fee..ff4d540bc6c 100644 --- a/components/datetime/src/any/datetime.rs +++ b/components/datetime/src/any/datetime.rs @@ -8,7 +8,8 @@ use crate::{input::DateTimeInput, DateTimeError, FormattedDateTime}; use alloc::string::String; use icu_calendar::any_calendar::{AnyCalendar, AnyCalendarKind}; use icu_calendar::provider::{ - JapaneseErasV1Marker, JapaneseExtendedErasV1Marker, WeekDataV1Marker, + ChineseCacheV1Marker, DangiCacheV1Marker, JapaneseErasV1Marker, JapaneseExtendedErasV1Marker, + WeekDataV1Marker, }; use icu_calendar::{types::Time, DateTime}; use icu_decimal::provider::DecimalSymbolsV1Marker; @@ -223,10 +224,12 @@ impl DateTimeFormatter { + DataProvider + DataProvider + DataProvider + + DataProvider + DataProvider + DataProvider + DataProvider + DataProvider + + DataProvider + DataProvider + DataProvider + DataProvider @@ -365,10 +368,12 @@ impl DateTimeFormatter { + DataProvider + DataProvider + DataProvider + + DataProvider + DataProvider + DataProvider + DataProvider + DataProvider + + DataProvider + DataProvider + DataProvider + DataProvider diff --git a/components/datetime/src/any/zoned_datetime.rs b/components/datetime/src/any/zoned_datetime.rs index ab4b7911c7e..7e153c3bc6c 100644 --- a/components/datetime/src/any/zoned_datetime.rs +++ b/components/datetime/src/any/zoned_datetime.rs @@ -13,7 +13,8 @@ use crate::time_zone::TimeZoneFormatterOptions; use crate::{DateTimeError, FormattedZonedDateTime}; use icu_calendar::any_calendar::{AnyCalendar, AnyCalendarKind}; use icu_calendar::provider::{ - JapaneseErasV1Marker, JapaneseExtendedErasV1Marker, WeekDataV1Marker, + ChineseCacheV1Marker, DangiCacheV1Marker, JapaneseErasV1Marker, JapaneseExtendedErasV1Marker, + WeekDataV1Marker, }; use icu_calendar::{types::Time, DateTime}; use icu_decimal::provider::DecimalSymbolsV1Marker; @@ -234,10 +235,12 @@ impl ZonedDateTimeFormatter { + DataProvider + DataProvider + DataProvider + + DataProvider + DataProvider + DataProvider + DataProvider + DataProvider + + DataProvider + DataProvider + DataProvider + DataProvider @@ -386,10 +389,12 @@ impl ZonedDateTimeFormatter { + DataProvider + DataProvider + DataProvider + + DataProvider + DataProvider + DataProvider + DataProvider + DataProvider + + DataProvider + DataProvider + DataProvider + DataProvider diff --git a/components/datetime/tests/datetime.rs b/components/datetime/tests/datetime.rs index 96b12de9d72..3b31269265a 100644 --- a/components/datetime/tests/datetime.rs +++ b/components/datetime/tests/datetime.rs @@ -71,9 +71,9 @@ fn test_fixture(fixture_name: &str, file: &str) { }; let input_value = mock::parse_gregorian_from_str(&fx.input.value).unwrap(); let input_buddhist = input_value.to_calendar(Buddhist); - let input_chinese = input_value.to_calendar(Chinese::new_always_calculating()); + let input_chinese = input_value.to_calendar(Chinese::new()); let input_coptic = input_value.to_calendar(Coptic); - let input_dangi = input_value.to_calendar(Dangi::new_always_calculating()); + let input_dangi = input_value.to_calendar(Dangi::new()); let input_ethiopian = input_value.to_calendar(Ethiopian::new()); let input_ethioaa = input_value.to_calendar(Ethiopian::new_with_era_style(EthiopianEraStyle::AmeteAlem)); diff --git a/provider/baked/calendar/data/macros.rs b/provider/baked/calendar/data/macros.rs index 684f118c201..bb7f8fe9d59 100644 --- a/provider/baked/calendar/data/macros.rs +++ b/provider/baked/calendar/data/macros.rs @@ -25,6 +25,16 @@ macro_rules! __make_provider { #[doc(inline)] pub use __make_provider as make_provider; #[macro_use] +#[path = "macros/calendar_chinesecache_v1.rs.data"] +mod calendar_chinesecache_v1; +#[doc(inline)] +pub use __impl_calendar_chinesecache_v1 as impl_calendar_chinesecache_v1; +#[macro_use] +#[path = "macros/calendar_dangicache_v1.rs.data"] +mod calendar_dangicache_v1; +#[doc(inline)] +pub use __impl_calendar_dangicache_v1 as impl_calendar_dangicache_v1; +#[macro_use] #[path = "macros/calendar_japanese_v1.rs.data"] mod calendar_japanese_v1; #[doc(inline)] diff --git a/provider/baked/calendar/data/macros/calendar_chinesecache_v1.rs.data b/provider/baked/calendar/data/macros/calendar_chinesecache_v1.rs.data new file mode 100644 index 00000000000..dc72c1e2e10 --- /dev/null +++ b/provider/baked/calendar/data/macros/calendar_chinesecache_v1.rs.data @@ -0,0 +1,27 @@ +// @generated +/// Implement `DataProvider` on the given struct using the data +/// hardcoded in this file. This allows the struct to be used with +/// `icu`'s `_unstable` constructors. +#[doc(hidden)] +#[macro_export] +macro_rules! __impl_calendar_chinesecache_v1 { + ($ provider : ty) => { + #[clippy::msrv = "1.67"] + const _: () = <$provider>::MUST_USE_MAKE_PROVIDER_MACRO; + #[clippy::msrv = "1.67"] + impl $provider { + #[doc(hidden)] + pub const SINGLETON_CALENDAR_CHINESECACHE_V1: &'static ::Yokeable = &icu::calendar::provider::chinese_based::ChineseBasedCacheV1 { first_extended_year: 4537i32, data: unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xD26\x17R\x07<\xA5\x0E&J\xD6\x12K\x066\x9B\n\x1EZ\xB5\nj\x050Y\x0B\x1ARw\x04R\x07*%\xFB\x14%\x0B:K\n\"\xAB\xD4\x0C\xAD\x022k\x05\x1Cik\x06\xA9\r,\x92\x1D\x19\x92\x0E>%\r&M\xDA\x10V\n6\xB6\x02 \xB5\xB5\x08\xD4\x060\xA9\x0E\x1A\x92~\x06\x92\x0E*&\xED\x14+\x058W\n\"\xB6\xD2\x0CZ\x0B2\xD4\x06\x1E\xC9\x8E\x08I\x07,\x93\x16\x17\x93\n<+\x05&[\xEA\x0E\xAD\n4j\x05 U\xBB\n\xA4\x0B0I\x0B\x1A\x93z\x04\x95\n*-\x15\x136\x058\xAD\n\"\xAA\xD5\x0E\xB2\x052\xA5\r\x1CJ\x9D\x08J\r.\x95*\x17\x97\n:V\x05&\xB5\xEA\x10\xD5\n4\xD2\x06 \xA5\xAE\n\xA5\x0E0J\x06\x1A\x97\x8C\x02\x9B\n(Z\x15\x15j\x058i\x0B\"R\xD7\x0ER\x0B4%\x0B\x1CK\xB6\x06K\n,\xAB4\x17\xAD\x02:m\x05$i\xEB\x10\xA9\r6\x92\r %\xBD\n%\r0Mz\x1BV\n>\xB6\x02(\xB5\xE5\x12\xD5\x068\xA9\x0E\"\x92\xDE\x0E\x92\x0E4&\r\x1EV\x8A\x06W\n*\xD64\x17Z\x03<\xD5\x06$\xC9\xD6\x10I\x076\x93\x06 +\xB5\x08+\x05.[\n\x18Zu\x04j\x05(U\x1B\x13\xA4\x0B:I\x0B$\x93\xDA\x0C\x95\n2-\x05\x1C\xAD\xAA\x06\xB5\n*\xAAU\x17\xD2\x05<\xA5\r&J\xFD\x10J\r6\x95\x0C .\xB5\nV\x05.\xB5\n\x18\xB2u\x04\xD2\x06*\xA5\xEE\x12%\x078K\x06\"\x97\xCC\x0C\xAB\x0C0Z\x05\x1C\xD6\x8A\x06i\x0B,R\x97\x17R\x0B<%\x0B&K\xFA\x10K\n4\xAB\x04\x1E[\xC5\x08\xAD\x05.j\x0B\x18R{\x04\x92\r*%\x1D\x15%\r8U\n\"\xAD\xD4\x0C\xB6\x042\xB5\x05\x1A\xAA\x8D\x06\xC9\x0E,\x92>\x19\x92\x0E<&\r&V\xEA\x10W\n4V\x05\x1E\xD5\xA6\x08U\x07.I\x07\x1A\x93\x8E\x02\x93\x06(+\x15\x13+\x058[\n Z\xD5\x0Cj\x052e\x0B\x1CJ\xB7\x06J\x0B,\x95:\x17\x95\n<-\x05$\xAD\xEA\x0E\xB5\n4\xAA\x05 \xA5\xAB\x08\xA5\r.J\r\x1A\x95\x9C\x04\x96\x0C(N\x19\x13V\x058\xB5\n\"\xB2\xD5\x0C\xD2\x062\xA5\x0E\x1CJ\xAE\x08\x8B\x06*\x97,\x15\xAB\x04:[\x05$\xD6\xEA\x0Ej\x0B4R\x07 %\xB7\nE\x0B.\x8B\n\x18\x9Bt\x02\xAB\x04([\t\x13\xAD\x058\xAA\x0B$R\xDB\x10\x92\r4%\r\x1EK\xBA\x08U\n.\xADT\x17\xB6\x04<\xB5\x06&\xAA\xED\x12\xC9\x0E6\x92\x0E\"&\xBD\x0C*\r2V\n\x1A\xB6\x94\x04V\x05*\xD5\n\x15U\x0B8J\x07$\x93\xCE\x0E\x95\x064+\x05\x1CW\xAA\x06\x9B\n,Z\x95\x19j\x05\xA5\x0E&") } }; + } + #[clippy::msrv = "1.67"] + impl icu_provider::DataProvider for $provider { + fn load(&self, req: icu_provider::DataRequest) -> Result, icu_provider::DataError> { + if req.locale.is_empty() { + Ok(icu_provider::DataResponse { payload: Some(icu_provider::DataPayload::from_static_ref(Self::SINGLETON_CALENDAR_CHINESECACHE_V1)), metadata: Default::default() }) + } else { + Err(icu_provider::DataErrorKind::ExtraneousLocale.with_req(::KEY, req)) + } + } + } + }; +} diff --git a/provider/baked/calendar/data/macros/calendar_dangicache_v1.rs.data b/provider/baked/calendar/data/macros/calendar_dangicache_v1.rs.data new file mode 100644 index 00000000000..92f3ce83b49 --- /dev/null +++ b/provider/baked/calendar/data/macros/calendar_dangicache_v1.rs.data @@ -0,0 +1,27 @@ +// @generated +/// Implement `DataProvider` on the given struct using the data +/// hardcoded in this file. This allows the struct to be used with +/// `icu`'s `_unstable` constructors. +#[doc(hidden)] +#[macro_export] +macro_rules! __impl_calendar_dangicache_v1 { + ($ provider : ty) => { + #[clippy::msrv = "1.67"] + const _: () = <$provider>::MUST_USE_MAKE_PROVIDER_MACRO; + #[clippy::msrv = "1.67"] + impl $provider { + #[doc(hidden)] + pub const SINGLETON_CALENDAR_DANGICACHE_V1: &'static ::Yokeable = &icu::calendar::provider::chinese_based::ChineseBasedCacheV1 { first_extended_year: 4233i32, data: unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xD26\x17R\x07<\xA5\x0E&J\xCE\x12K\x056\x97\n\x1EV\xB5\nj\x050U\x0B\x1ARw\x04R\x07*%\xF7\x14%\x0B:K\n\"\x9B\xD2\x0C\xAD\n2j\x05\x1Eik\x06\xA9\x0B,R\x1B\x19\x92\r>%\r&M\xDA\x10V\t6\xB5\x02 \xAD\xB5\x08\xD4\x060\xA9\r\x1A\x92}\x06\x92\x0E*&\xED\x14'\x058W\n\"\xB6\xD2\x0C\xDA\n2\xD4\x06\x1E\xA9\x8E\x08I\x07,\x93\x16\x17\x93\n<+\x05&[\xEA\x0Em\t4j\x0B T\xBB\x0C\xA4\x0B0I\x0B\x1A\x93z\x04\x95\n*+\x15\x13-\x058\xAD\n\"j\xD5\x0E\xB2\r2\xA4\r\x1EI\x9D\x08J\r.\x95:\x17\x96\n\xB6\x02(\xAD\xF5\x12\xD4\x06:\xA9\r\"\x92\xDD\x0E\x92\x0E4&\r\x1EV\x8A\x06W\n*\xB62\x17Z\x0B<\xD4\x06&\xC9\xCE\x10I\x076\x93\x06 '\xB5\x08+\x05.[\n\x18Zu\x04j\x03(U\x1B\x13\xA4\x0B:I\x0B$\x93\xDA\x0C\x95\n2-\x05\x1C]\x8A\x06\xAD\n*\xAAU\x17\xD2\x05<\xA5\r&J\xDD\x10J\r6\x95\n -\xB5\nV\x05.\xB5\n\x18\xAAu\x04\xD2\x06*\xA5\xEE\x12\xA5\x0E8J\x0E$\x96\xCC\x0E\x9B\x0C0Z\x05\x1C\xD5\x8A\x06i\x0B,R\x97\x17R\x07<%\x0B&K\xF6\x10K\n4\xAB\x04\x1E[\xC5\x08m\x05.i\x0B\x18R{\x04\x92\r*%\x1D\x15%\r8M\n\"\xAD\xD4\x0C\xB6\x022\xB5\x05\x1A\xA9\x8D\x06\xA9\x0E,\x92=\x19\x92\x0E<&\r&V\xEA\x10W\n4\xD6\x04\x1E\xB5\xA6\x08\xD5\x06.\xC9\x0E\x1A\x92\x8E\x04\x93\x06(+\x15\x13+\x058[\n Z\xD5\x0Cj\x052U\x0B\x1CI\xB7\x06I\x0B,\x93:\x17\x95\n<-\x05$\xAD\xEA\x0E\xB5\n4\xAA\x05 \xA5\xAB\x08\xA5\r.J\r\x1A\x95\x9A\x04\x95\x0C(.\x15\x13V\x058\xB5\n\"\xB2\xD5\x0C\xD2\x062\xA5\x0E\x1CJ\xBE\x08J\x06,\x97,\x15\xAB\x0C:Z\x05&\xD5\xEA\x0Ei\x0B4R\x07 \xA5\xB6\n%\x0B.K\x06\x18\x97\x94\x02\xAB\x04([\x05\x13\xAD\x058i\x0B$R\xDB\x10\x92\r4%\r\x1EK\xBA\x08U\n.\xADT\x17\xB6\x04<\xB5\x05&\xAA\xED\x12\xC9\x0E6\x92\x0E\"%\xBD\x0C&\r2V\n\x1A\xAE\x94\x04\xD6\x04*\xD5\n\x15\xD5\x068\xC9\x06$\x93\xCE\x0E\x93\x064+\x05\x1CW\xAA\x06[\n,ZU\x19j\x05\xA5\x0E&") } }; + } + #[clippy::msrv = "1.67"] + impl icu_provider::DataProvider for $provider { + fn load(&self, req: icu_provider::DataRequest) -> Result, icu_provider::DataError> { + if req.locale.is_empty() { + Ok(icu_provider::DataResponse { payload: Some(icu_provider::DataPayload::from_static_ref(Self::SINGLETON_CALENDAR_DANGICACHE_V1)), metadata: Default::default() }) + } else { + Err(icu_provider::DataErrorKind::ExtraneousLocale.with_req(::KEY, req)) + } + } + } + }; +} diff --git a/provider/datagen/Cargo.toml b/provider/datagen/Cargo.toml index e8514fc84e2..9599311bfd5 100644 --- a/provider/datagen/Cargo.toml +++ b/provider/datagen/Cargo.toml @@ -53,6 +53,7 @@ icu_transliterate = { workspace = true, features = ["datagen"], optional = true icu_unitsconversion = { workspace = true, features = ["datagen"], optional = true } # ICU infrastructure +calendrical_calculations = { workspace = true } icu_codepointtrie_builder = { workspace = true } icu_collections = { workspace = true, features = ["serde"] } icu_locid = { workspace = true, features = ["std", "serde"] } diff --git a/provider/datagen/src/registry.rs b/provider/datagen/src/registry.rs index d352fc6593d..95fb9307479 100644 --- a/provider/datagen/src/registry.rs +++ b/provider/datagen/src/registry.rs @@ -158,6 +158,8 @@ registry!( #[cfg(test)] icu_dimension::provider::CurrencyEssentialsV1Marker = "currency/essentials@1", #[cfg(any(all(), feature = "icu_calendar"))] + icu_calendar::provider::ChineseCacheV1Marker = "calendar/chinesecache@1", + icu_calendar::provider::DangiCacheV1Marker = "calendar/dangicache@1", icu_calendar::provider::JapaneseErasV1Marker = "calendar/japanese@1", icu_calendar::provider::JapaneseExtendedErasV1Marker = "calendar/japanext@1", icu_calendar::provider::WeekDataV1Marker = "datetime/week_data@1", diff --git a/provider/datagen/src/transform/cldr/calendar/chinese_based.rs b/provider/datagen/src/transform/cldr/calendar/chinese_based.rs new file mode 100644 index 00000000000..fe12246c0b4 --- /dev/null +++ b/provider/datagen/src/transform/cldr/calendar/chinese_based.rs @@ -0,0 +1,51 @@ +// 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 calendrical_calculations::chinese_based::{Chinese, ChineseBased, Dangi}; +use icu_calendar::provider::chinese_based::*; +use icu_provider::datagen::IterableDataProvider; +use icu_provider::prelude::*; + +const YEARS: i32 = 250; +const ISO_START: i32 = 1900; + +fn load() -> ChineseBasedCacheV1<'static> { + let extended_start = CB::extended_from_iso(ISO_START); + let extended_end = extended_start + YEARS; + ChineseBasedCacheV1::compute_for::(extended_start..extended_end) +} + +impl DataProvider for crate::DatagenProvider { + fn load(&self, req: DataRequest) -> Result, DataError> { + self.check_req::(req)?; + let cache = load::(); + Ok(DataResponse { + metadata: DataResponseMetadata::default(), + payload: Some(DataPayload::from_owned(cache)), + }) + } +} + +impl DataProvider for crate::DatagenProvider { + fn load(&self, req: DataRequest) -> Result, DataError> { + self.check_req::(req)?; + let cache = load::(); + Ok(DataResponse { + metadata: DataResponseMetadata::default(), + payload: Some(DataPayload::from_owned(cache)), + }) + } +} + +impl IterableDataProvider for crate::DatagenProvider { + fn supported_locales(&self) -> Result, DataError> { + Ok(vec![Default::default()]) + } +} + +impl IterableDataProvider for crate::DatagenProvider { + fn supported_locales(&self) -> Result, DataError> { + Ok(vec![Default::default()]) + } +} diff --git a/provider/datagen/src/transform/cldr/calendar/mod.rs b/provider/datagen/src/transform/cldr/calendar/mod.rs index 5dbb4f0846b..2a6a632762f 100644 --- a/provider/datagen/src/transform/cldr/calendar/mod.rs +++ b/provider/datagen/src/transform/cldr/calendar/mod.rs @@ -4,3 +4,6 @@ /// Data for calendar arithmetic pub mod japanese; + +/// Cached data for chinese-based calendars +pub mod chinese_based; diff --git a/provider/datagen/tests/data/json/calendar/chinesecache@1/und.json b/provider/datagen/tests/data/json/calendar/chinesecache@1/und.json new file mode 100644 index 00000000000..a6bd0e2cfae --- /dev/null +++ b/provider/datagen/tests/data/json/calendar/chinesecache@1/und.json @@ -0,0 +1,4755 @@ +{ + "first_extended_year": 4537, + "data": [ + { + "ny_offset": 11, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + true, + true, + false, + true, + true, + false, + true + ], + "leap_month_idx": 9 + }, + { + "ny_offset": 30, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + true, + false, + true, + true, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 19, + "month_has_30_days": [ + true, + false, + true, + false, + false, + true, + false, + true, + false, + true, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 9, + "month_has_30_days": [ + false, + true, + false, + true, + false, + false, + true, + false, + false, + true, + true, + false, + true + ], + "leap_month_idx": 6 + }, + { + "ny_offset": 27, + "month_has_30_days": [ + true, + true, + false, + true, + false, + false, + true, + false, + false, + true, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 15, + "month_has_30_days": [ + true, + true, + false, + true, + true, + false, + false, + true, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 5, + "month_has_30_days": [ + false, + true, + false, + true, + true, + false, + true, + false, + true, + false, + true, + false, + true + ], + "leap_month_idx": 5 + }, + { + "ny_offset": 24, + "month_has_30_days": [ + false, + true, + false, + true, + false, + true, + true, + false, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 13, + "month_has_30_days": [ + true, + false, + false, + true, + true, + false, + true, + false, + true, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 2, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + true, + false, + true, + true, + true, + false, + true + ], + "leap_month_idx": 3 + }, + { + "ny_offset": 21, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + true, + false, + true, + true, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 10, + "month_has_30_days": [ + true, + false, + true, + false, + false, + true, + false, + false, + true, + true, + false, + true, + true + ], + "leap_month_idx": 7 + }, + { + "ny_offset": 29, + "month_has_30_days": [ + true, + false, + true, + false, + false, + true, + false, + false, + true, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 17, + "month_has_30_days": [ + true, + true, + false, + true, + false, + false, + true, + false, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 6, + "month_has_30_days": [ + true, + true, + false, + true, + false, + true, + false, + true, + false, + false, + true, + false, + true + ], + "leap_month_idx": 6 + }, + { + "ny_offset": 25, + "month_has_30_days": [ + true, + false, + true, + true, + false, + true, + false, + true, + false, + true, + false, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 14, + "month_has_30_days": [ + true, + true, + false, + true, + false, + true, + true, + false, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 3, + "month_has_30_days": [ + true, + false, + false, + true, + false, + true, + true, + false, + true, + true, + false, + true, + false + ], + "leap_month_idx": 3 + }, + { + "ny_offset": 22, + "month_has_30_days": [ + true, + false, + false, + true, + false, + true, + false, + true, + true, + false, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 12, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + false, + true, + true, + false, + true, + true, + true + ], + "leap_month_idx": 8 + }, + { + "ny_offset": 31, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 19, + "month_has_30_days": [ + true, + false, + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 8, + "month_has_30_days": [ + true, + false, + true, + true, + false, + false, + true, + false, + false, + true, + false, + true, + true + ], + "leap_month_idx": 6 + }, + { + "ny_offset": 27, + "month_has_30_days": [ + false, + true, + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 16, + "month_has_30_days": [ + false, + true, + true, + false, + true, + true, + false, + true, + false, + true, + false, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 4, + "month_has_30_days": [ + true, + false, + true, + false, + true, + true, + false, + true, + true, + false, + true, + false, + true + ], + "leap_month_idx": 5 + }, + { + "ny_offset": 24, + "month_has_30_days": [ + false, + false, + true, + false, + true, + false, + true, + true, + false, + true, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 13, + "month_has_30_days": [ + true, + false, + false, + true, + false, + true, + false, + true, + false, + true, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 3, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + true, + true + ], + "leap_month_idx": 3 + }, + { + "ny_offset": 21, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 10, + "month_has_30_days": [ + false, + true, + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + false + ], + "leap_month_idx": 7 + }, + { + "ny_offset": 28, + "month_has_30_days": [ + true, + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 17, + "month_has_30_days": [ + true, + true, + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 6, + "month_has_30_days": [ + false, + true, + true, + false, + true, + true, + false, + true, + false, + true, + false, + false, + true + ], + "leap_month_idx": 6 + }, + { + "ny_offset": 25, + "month_has_30_days": [ + false, + true, + false, + true, + true, + false, + true, + false, + true, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 15, + "month_has_30_days": [ + false, + false, + true, + false, + true, + false, + true, + true, + false, + true, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 4, + "month_has_30_days": [ + true, + false, + false, + true, + false, + false, + true, + true, + false, + true, + true, + true, + false + ], + "leap_month_idx": 4 + }, + { + "ny_offset": 22, + "month_has_30_days": [ + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 11, + "month_has_30_days": [ + true, + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + false, + true + ], + "leap_month_idx": 8 + }, + { + "ny_offset": 30, + "month_has_30_days": [ + true, + true, + false, + false, + true, + false, + false, + true, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 19, + "month_has_30_days": [ + true, + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 7, + "month_has_30_days": [ + true, + true, + false, + true, + true, + false, + true, + false, + false, + true, + false, + true, + false + ], + "leap_month_idx": 7 + }, + { + "ny_offset": 26, + "month_has_30_days": [ + true, + false, + true, + true, + false, + true, + false, + true, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 16, + "month_has_30_days": [ + false, + true, + false, + true, + false, + true, + true, + false, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 5, + "month_has_30_days": [ + true, + false, + true, + false, + true, + false, + true, + false, + true, + true, + false, + true, + true + ], + "leap_month_idx": 5 + }, + { + "ny_offset": 24, + "month_has_30_days": [ + false, + false, + true, + false, + false, + true, + false, + true, + true, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 13, + "month_has_30_days": [ + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 2, + "month_has_30_days": [ + true, + true, + false, + false, + true, + false, + false, + true, + false, + true, + false, + true, + true + ], + "leap_month_idx": 3 + }, + { + "ny_offset": 21, + "month_has_30_days": [ + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 9, + "month_has_30_days": [ + true, + false, + true, + true, + false, + true, + false, + false, + true, + false, + true, + false, + true + ], + "leap_month_idx": 8 + }, + { + "ny_offset": 28, + "month_has_30_days": [ + false, + true, + true, + false, + true, + true, + false, + false, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 17, + "month_has_30_days": [ + true, + false, + true, + true, + false, + true, + false, + true, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 7, + "month_has_30_days": [ + false, + true, + false, + true, + false, + true, + false, + true, + true, + false, + true, + false, + true + ], + "leap_month_idx": 6 + }, + { + "ny_offset": 25, + "month_has_30_days": [ + false, + true, + false, + false, + true, + true, + false, + true, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 14, + "month_has_30_days": [ + true, + false, + true, + false, + false, + true, + false, + true, + true, + false, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 4, + "month_has_30_days": [ + false, + true, + false, + true, + false, + false, + true, + false, + true, + false, + true, + true, + true + ], + "leap_month_idx": 4 + }, + { + "ny_offset": 23, + "month_has_30_days": [ + false, + true, + false, + true, + false, + false, + true, + false, + true, + false, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 11, + "month_has_30_days": [ + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + false, + true, + false + ], + "leap_month_idx": 9 + }, + { + "ny_offset": 29, + "month_has_30_days": [ + true, + true, + true, + false, + true, + false, + false, + true, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 19, + "month_has_30_days": [ + false, + true, + true, + false, + true, + false, + true, + false, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 8, + "month_has_30_days": [ + true, + false, + true, + false, + true, + true, + false, + true, + false, + true, + false, + true, + false + ], + "leap_month_idx": 7 + }, + { + "ny_offset": 26, + "month_has_30_days": [ + true, + false, + true, + false, + true, + false, + true, + true, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 16, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + true, + true, + false, + true, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 5, + "month_has_30_days": [ + true, + false, + true, + false, + false, + true, + false, + true, + false, + true, + true, + true, + false + ], + "leap_month_idx": 5 + }, + { + "ny_offset": 24, + "month_has_30_days": [ + true, + false, + true, + false, + false, + true, + false, + true, + false, + true, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 13, + "month_has_30_days": [ + false, + true, + false, + true, + false, + false, + true, + false, + false, + true, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 1, + "month_has_30_days": [ + true, + true, + true, + false, + true, + false, + false, + true, + false, + false, + true, + true, + false + ], + "leap_month_idx": 4 + }, + { + "ny_offset": 20, + "month_has_30_days": [ + true, + true, + false, + true, + true, + false, + false, + true, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 10, + "month_has_30_days": [ + false, + true, + false, + true, + true, + false, + true, + false, + true, + false, + true, + false, + true + ], + "leap_month_idx": 8 + }, + { + "ny_offset": 28, + "month_has_30_days": [ + false, + true, + false, + true, + false, + true, + true, + false, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 17, + "month_has_30_days": [ + true, + false, + false, + true, + false, + true, + true, + false, + true, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 7, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + true, + false, + true, + true, + true, + false, + true + ], + "leap_month_idx": 6 + }, + { + "ny_offset": 26, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + true, + false, + true, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 14, + "month_has_30_days": [ + true, + false, + true, + false, + false, + true, + false, + false, + true, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 3, + "month_has_30_days": [ + true, + true, + false, + true, + false, + false, + true, + false, + false, + true, + true, + false, + true + ], + "leap_month_idx": 5 + }, + { + "ny_offset": 22, + "month_has_30_days": [ + true, + true, + false, + true, + false, + false, + true, + false, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 11, + "month_has_30_days": [ + true, + true, + false, + true, + false, + true, + false, + true, + false, + false, + true, + false, + true + ], + "leap_month_idx": 9 + }, + { + "ny_offset": 29, + "month_has_30_days": [ + true, + false, + true, + true, + false, + true, + false, + true, + false, + true, + false, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 18, + "month_has_30_days": [ + true, + false, + true, + true, + false, + true, + true, + false, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 8, + "month_has_30_days": [ + true, + false, + false, + true, + false, + true, + true, + false, + true, + true, + false, + true, + false + ], + "leap_month_idx": 7 + }, + { + "ny_offset": 27, + "month_has_30_days": [ + true, + false, + false, + true, + false, + true, + false, + true, + true, + false, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 16, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + false, + true, + true, + false, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 5, + "month_has_30_days": [ + true, + false, + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + true + ], + "leap_month_idx": 5 + }, + { + "ny_offset": 24, + "month_has_30_days": [ + true, + false, + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 13, + "month_has_30_days": [ + true, + false, + true, + true, + false, + false, + true, + false, + false, + true, + false, + true, + true + ], + "leap_month_idx": 11 + }, + { + "ny_offset": 31, + "month_has_30_days": [ + false, + true, + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 20, + "month_has_30_days": [ + false, + true, + true, + false, + true, + true, + false, + true, + false, + true, + false, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 9, + "month_has_30_days": [ + true, + false, + true, + false, + true, + true, + false, + true, + true, + false, + true, + false, + false + ], + "leap_month_idx": 7 + }, + { + "ny_offset": 28, + "month_has_30_days": [ + true, + false, + true, + false, + true, + false, + true, + true, + false, + true, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 17, + "month_has_30_days": [ + true, + false, + false, + true, + false, + true, + false, + true, + false, + true, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 7, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + true, + true + ], + "leap_month_idx": 6 + }, + { + "ny_offset": 26, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 15, + "month_has_30_days": [ + false, + true, + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 3, + "month_has_30_days": [ + false, + true, + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + false + ], + "leap_month_idx": 4 + }, + { + "ny_offset": 21, + "month_has_30_days": [ + true, + true, + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 11, + "month_has_30_days": [ + false, + true, + true, + false, + true, + false, + true, + true, + false, + false, + true, + false, + true + ], + "leap_month_idx": 9 + }, + { + "ny_offset": 30, + "month_has_30_days": [ + false, + true, + false, + true, + true, + false, + true, + false, + true, + true, + false, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 18, + "month_has_30_days": [ + true, + false, + true, + false, + true, + false, + true, + true, + false, + true, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 8, + "month_has_30_days": [ + true, + false, + false, + true, + false, + false, + true, + true, + false, + true, + true, + false, + true + ], + "leap_month_idx": 6 + }, + { + "ny_offset": 27, + "month_has_30_days": [ + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 16, + "month_has_30_days": [ + true, + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 4, + "month_has_30_days": [ + true, + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + false, + true + ], + "leap_month_idx": 5 + }, + { + "ny_offset": 23, + "month_has_30_days": [ + true, + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 12, + "month_has_30_days": [ + true, + true, + false, + true, + true, + false, + true, + false, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 2, + "month_has_30_days": [ + false, + true, + false, + true, + true, + false, + true, + false, + true, + false, + true, + false, + true + ], + "leap_month_idx": 3 + }, + { + "ny_offset": 20, + "month_has_30_days": [ + false, + true, + false, + true, + false, + true, + true, + false, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 9, + "month_has_30_days": [ + true, + false, + true, + false, + true, + false, + true, + false, + true, + true, + false, + true, + true + ], + "leap_month_idx": 8 + }, + { + "ny_offset": 29, + "month_has_30_days": [ + false, + false, + true, + false, + false, + true, + false, + true, + true, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 18, + "month_has_30_days": [ + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 6, + "month_has_30_days": [ + true, + true, + false, + false, + true, + false, + false, + true, + false, + true, + false, + true, + true + ], + "leap_month_idx": 6 + }, + { + "ny_offset": 25, + "month_has_30_days": [ + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 14, + "month_has_30_days": [ + true, + false, + true, + true, + false, + true, + false, + false, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 3, + "month_has_30_days": [ + true, + false, + true, + true, + false, + true, + false, + true, + false, + true, + false, + true, + false + ], + "leap_month_idx": 5 + }, + { + "ny_offset": 21, + "month_has_30_days": [ + true, + false, + true, + false, + true, + true, + false, + true, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 11, + "month_has_30_days": [ + false, + true, + false, + true, + false, + true, + false, + true, + true, + false, + true, + false, + true + ], + "leap_month_idx": 10 + }, + { + "ny_offset": 30, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + true, + true, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 19, + "month_has_30_days": [ + true, + false, + true, + false, + false, + true, + false, + true, + true, + false, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 8, + "month_has_30_days": [ + false, + true, + false, + true, + false, + false, + true, + false, + true, + false, + true, + true, + true + ], + "leap_month_idx": 7 + }, + { + "ny_offset": 27, + "month_has_30_days": [ + false, + true, + false, + true, + false, + false, + true, + false, + true, + false, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 16, + "month_has_30_days": [ + true, + false, + true, + false, + true, + false, + false, + true, + false, + false, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 5, + "month_has_30_days": [ + false, + true, + true, + true, + false, + true, + false, + false, + true, + false, + true, + false, + true + ], + "leap_month_idx": 5 + }, + { + "ny_offset": 23, + "month_has_30_days": [ + false, + true, + true, + false, + true, + false, + true, + false, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 12, + "month_has_30_days": [ + true, + false, + true, + false, + true, + true, + false, + true, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 2, + "month_has_30_days": [ + false, + true, + false, + false, + true, + true, + false, + true, + true, + false, + true, + false, + true + ], + "leap_month_idx": 3 + }, + { + "ny_offset": 21, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + true, + true, + false, + true, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 9, + "month_has_30_days": [ + true, + false, + true, + false, + false, + true, + false, + true, + false, + true, + true, + true, + false + ], + "leap_month_idx": 7 + }, + { + "ny_offset": 28, + "month_has_30_days": [ + true, + false, + true, + false, + false, + true, + false, + false, + true, + true, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 17, + "month_has_30_days": [ + true, + true, + false, + true, + false, + false, + true, + false, + false, + true, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 6, + "month_has_30_days": [ + true, + true, + true, + false, + true, + false, + false, + true, + false, + false, + true, + true, + false + ], + "leap_month_idx": 6 + }, + { + "ny_offset": 24, + "month_has_30_days": [ + true, + true, + false, + true, + false, + true, + false, + true, + false, + false, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 14, + "month_has_30_days": [ + false, + true, + false, + true, + true, + false, + true, + false, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 3, + "month_has_30_days": [ + false, + true, + true, + false, + true, + false, + true, + true, + false, + true, + false, + true, + false + ], + "leap_month_idx": 4 + }, + { + "ny_offset": 22, + "month_has_30_days": [ + true, + false, + false, + true, + false, + true, + true, + false, + true, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 11, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + true, + false, + true, + true, + true, + false, + true + ], + "leap_month_idx": 12 + }, + { + "ny_offset": 30, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + true, + false, + true, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 19, + "month_has_30_days": [ + true, + false, + true, + false, + false, + true, + false, + false, + true, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 8, + "month_has_30_days": [ + true, + true, + false, + true, + false, + false, + true, + false, + false, + true, + false, + true, + true + ], + "leap_month_idx": 7 + }, + { + "ny_offset": 26, + "month_has_30_days": [ + true, + true, + false, + true, + false, + false, + true, + false, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 15, + "month_has_30_days": [ + true, + true, + false, + true, + false, + true, + false, + true, + false, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 4, + "month_has_30_days": [ + true, + true, + false, + true, + true, + false, + true, + false, + true, + false, + true, + false, + false + ], + "leap_month_idx": 6 + }, + { + "ny_offset": 23, + "month_has_30_days": [ + true, + false, + true, + true, + false, + true, + false, + true, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 12, + "month_has_30_days": [ + false, + true, + false, + true, + false, + true, + true, + false, + true, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 2, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + true, + false, + true, + true, + false, + true, + true + ], + "leap_month_idx": 3 + }, + { + "ny_offset": 21, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + false, + true, + true, + false, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 10, + "month_has_30_days": [ + true, + false, + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + true + ], + "leap_month_idx": 8 + }, + { + "ny_offset": 28, + "month_has_30_days": [ + true, + false, + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 17, + "month_has_30_days": [ + true, + false, + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 6, + "month_has_30_days": [ + true, + false, + true, + true, + false, + true, + false, + true, + false, + false, + true, + false, + true + ], + "leap_month_idx": 6 + }, + { + "ny_offset": 25, + "month_has_30_days": [ + false, + true, + true, + false, + true, + true, + false, + true, + false, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 13, + "month_has_30_days": [ + true, + false, + true, + false, + true, + true, + false, + true, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 3, + "month_has_30_days": [ + false, + true, + false, + true, + false, + true, + false, + true, + true, + false, + true, + true, + false + ], + "leap_month_idx": 4 + }, + { + "ny_offset": 22, + "month_has_30_days": [ + true, + false, + false, + true, + false, + false, + true, + true, + false, + true, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 12, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + true, + true + ], + "leap_month_idx": 9 + }, + { + "ny_offset": 30, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 19, + "month_has_30_days": [ + false, + true, + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 8, + "month_has_30_days": [ + false, + true, + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + false + ], + "leap_month_idx": 7 + }, + { + "ny_offset": 26, + "month_has_30_days": [ + true, + true, + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 15, + "month_has_30_days": [ + false, + true, + true, + false, + true, + false, + true, + false, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 4, + "month_has_30_days": [ + true, + false, + true, + false, + true, + false, + true, + true, + false, + true, + true, + false, + false + ], + "leap_month_idx": 5 + }, + { + "ny_offset": 23, + "month_has_30_days": [ + true, + false, + true, + false, + true, + false, + true, + false, + true, + true, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 13, + "month_has_30_days": [ + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 1, + "month_has_30_days": [ + true, + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + true, + false + ], + "leap_month_idx": 4 + }, + { + "ny_offset": 20, + "month_has_30_days": [ + true, + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 9, + "month_has_30_days": [ + true, + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + false, + true + ], + "leap_month_idx": 8 + }, + { + "ny_offset": 28, + "month_has_30_days": [ + true, + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 16, + "month_has_30_days": [ + true, + true, + false, + true, + true, + false, + true, + false, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 6, + "month_has_30_days": [ + false, + true, + false, + true, + true, + false, + true, + false, + true, + false, + true, + false, + true + ], + "leap_month_idx": 6 + }, + { + "ny_offset": 25, + "month_has_30_days": [ + false, + true, + false, + true, + false, + true, + true, + false, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 14, + "month_has_30_days": [ + true, + false, + true, + false, + false, + true, + true, + false, + true, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 3, + "month_has_30_days": [ + false, + true, + false, + true, + false, + false, + true, + false, + true, + true, + true, + false, + true + ], + "leap_month_idx": 5 + }, + { + "ny_offset": 22, + "month_has_30_days": [ + false, + true, + false, + true, + false, + false, + true, + false, + true, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 11, + "month_has_30_days": [ + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + false, + true, + true + ], + "leap_month_idx": 9 + }, + { + "ny_offset": 30, + "month_has_30_days": [ + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 18, + "month_has_30_days": [ + true, + false, + true, + true, + false, + true, + false, + false, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 7, + "month_has_30_days": [ + true, + false, + true, + true, + false, + true, + false, + true, + false, + true, + false, + true, + false + ], + "leap_month_idx": 7 + }, + { + "ny_offset": 26, + "month_has_30_days": [ + true, + false, + true, + false, + true, + true, + false, + true, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 16, + "month_has_30_days": [ + false, + true, + false, + true, + false, + true, + false, + true, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 4, + "month_has_30_days": [ + true, + false, + true, + false, + false, + true, + false, + true, + true, + true, + false, + true, + false + ], + "leap_month_idx": 5 + }, + { + "ny_offset": 23, + "month_has_30_days": [ + true, + false, + true, + false, + false, + true, + false, + true, + true, + false, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 13, + "month_has_30_days": [ + false, + true, + false, + true, + false, + false, + true, + false, + true, + false, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 2, + "month_has_30_days": [ + true, + false, + true, + false, + true, + false, + false, + true, + false, + false, + true, + true, + true + ], + "leap_month_idx": 4 + }, + { + "ny_offset": 20, + "month_has_30_days": [ + false, + true, + true, + false, + true, + false, + false, + true, + false, + false, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 9, + "month_has_30_days": [ + false, + true, + true, + true, + false, + false, + true, + false, + true, + false, + false, + true, + true + ], + "leap_month_idx": 8 + }, + { + "ny_offset": 28, + "month_has_30_days": [ + false, + true, + true, + false, + true, + false, + true, + false, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 17, + "month_has_30_days": [ + true, + false, + true, + false, + true, + true, + false, + true, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 6, + "month_has_30_days": [ + false, + true, + false, + false, + true, + true, + false, + true, + true, + false, + true, + false, + true + ], + "leap_month_idx": 6 + }, + { + "ny_offset": 25, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + true, + true, + false, + true, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 14, + "month_has_30_days": [ + true, + false, + true, + false, + false, + true, + false, + true, + false, + true, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 4, + "month_has_30_days": [ + false, + true, + false, + true, + false, + false, + true, + false, + false, + true, + true, + true, + false + ], + "leap_month_idx": 5 + }, + { + "ny_offset": 21, + "month_has_30_days": [ + true, + true, + false, + true, + false, + false, + false, + true, + false, + true, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 10, + "month_has_30_days": [ + true, + true, + true, + false, + true, + false, + false, + true, + false, + false, + true, + true, + false + ], + "leap_month_idx": 9 + }, + { + "ny_offset": 29, + "month_has_30_days": [ + true, + true, + false, + true, + false, + true, + false, + true, + false, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 18, + "month_has_30_days": [ + true, + true, + false, + true, + true, + false, + true, + false, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 7, + "month_has_30_days": [ + false, + true, + true, + false, + true, + false, + true, + true, + false, + true, + false, + true, + false + ], + "leap_month_idx": 7 + }, + { + "ny_offset": 26, + "month_has_30_days": [ + false, + true, + false, + true, + false, + true, + true, + false, + true, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 16, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + true, + false, + true, + true, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 5, + "month_has_30_days": [ + true, + false, + true, + false, + false, + true, + false, + false, + true, + true, + true, + false, + true + ], + "leap_month_idx": 5 + }, + { + "ny_offset": 23, + "month_has_30_days": [ + true, + false, + true, + false, + false, + false, + true, + false, + true, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 12, + "month_has_30_days": [ + true, + true, + false, + true, + false, + false, + false, + true, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 1, + "month_has_30_days": [ + true, + true, + false, + true, + true, + false, + false, + true, + false, + false, + true, + false, + true + ], + "leap_month_idx": 3 + }, + { + "ny_offset": 20, + "month_has_30_days": [ + true, + true, + false, + true, + false, + true, + false, + true, + false, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 9, + "month_has_30_days": [ + true, + true, + false, + true, + true, + false, + true, + false, + true, + false, + false, + true, + false + ], + "leap_month_idx": 8 + }, + { + "ny_offset": 28, + "month_has_30_days": [ + true, + false, + true, + true, + false, + true, + false, + true, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 18, + "month_has_30_days": [ + false, + true, + false, + true, + false, + true, + false, + true, + true, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 8, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + true, + false, + true, + true, + false, + true, + true + ], + "leap_month_idx": 6 + }, + { + "ny_offset": 26, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + false, + true, + true, + false, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 15, + "month_has_30_days": [ + true, + false, + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 4, + "month_has_30_days": [ + true, + true, + false, + true, + false, + false, + true, + false, + false, + true, + false, + true, + true + ], + "leap_month_idx": 5 + }, + { + "ny_offset": 23, + "month_has_30_days": [ + true, + false, + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 11, + "month_has_30_days": [ + true, + false, + true, + true, + false, + true, + false, + true, + false, + false, + true, + false, + true + ], + "leap_month_idx": 10 + }, + { + "ny_offset": 30, + "month_has_30_days": [ + false, + true, + true, + false, + true, + true, + false, + true, + false, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 19, + "month_has_30_days": [ + true, + false, + true, + false, + true, + true, + false, + true, + false, + true, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 9, + "month_has_30_days": [ + false, + true, + false, + true, + false, + true, + false, + true, + true, + false, + true, + true, + false + ], + "leap_month_idx": 7 + }, + { + "ny_offset": 27, + "month_has_30_days": [ + true, + false, + false, + true, + false, + false, + true, + true, + false, + true, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 17, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 6, + "month_has_30_days": [ + false, + true, + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + true + ], + "leap_month_idx": 5 + }, + { + "ny_offset": 25, + "month_has_30_days": [ + false, + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 13, + "month_has_30_days": [ + false, + true, + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 2, + "month_has_30_days": [ + false, + true, + true, + false, + true, + true, + false, + true, + false, + false, + true, + false, + true + ], + "leap_month_idx": 4 + }, + { + "ny_offset": 21, + "month_has_30_days": [ + false, + true, + true, + false, + true, + false, + true, + false, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 10, + "month_has_30_days": [ + true, + false, + true, + false, + true, + false, + true, + true, + false, + true, + false, + true, + false + ], + "leap_month_idx": 8 + }, + { + "ny_offset": 28, + "month_has_30_days": [ + true, + false, + true, + false, + true, + false, + true, + false, + true, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 18, + "month_has_30_days": [ + false, + true, + false, + true, + false, + false, + true, + false, + true, + true, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 7, + "month_has_30_days": [ + true, + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + true, + false + ], + "leap_month_idx": 6 + }, + { + "ny_offset": 26, + "month_has_30_days": [ + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 14, + "month_has_30_days": [ + true, + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 3, + "month_has_30_days": [ + true, + true, + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + false + ], + "leap_month_idx": 5 + }, + { + "ny_offset": 22, + "month_has_30_days": [ + true, + true, + false, + true, + true, + false, + false, + true, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 12, + "month_has_30_days": [ + false, + true, + false, + true, + true, + false, + true, + false, + true, + false, + true, + false, + true + ], + "leap_month_idx": 12 + }, + { + "ny_offset": 30, + "month_has_30_days": [ + false, + true, + false, + true, + false, + true, + true, + false, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 19, + "month_has_30_days": [ + true, + false, + true, + false, + false, + true, + true, + false, + true, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 9, + "month_has_30_days": [ + false, + true, + false, + true, + false, + false, + true, + false, + true, + true, + true, + false, + true + ], + "leap_month_idx": 7 + }, + { + "ny_offset": 28, + "month_has_30_days": [ + false, + true, + false, + true, + false, + false, + true, + false, + true, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 16, + "month_has_30_days": [ + true, + false, + true, + false, + true, + false, + false, + false, + true, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 5, + "month_has_30_days": [ + true, + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + false, + true + ], + "leap_month_idx": 6 + }, + { + "ny_offset": 24, + "month_has_30_days": [ + true, + false, + true, + true, + false, + false, + true, + false, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 13, + "month_has_30_days": [ + true, + false, + true, + true, + false, + true, + false, + true, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 2, + "month_has_30_days": [ + false, + true, + false, + true, + false, + true, + true, + false, + true, + false, + true, + false, + true + ], + "leap_month_idx": 3 + }, + { + "ny_offset": 21, + "month_has_30_days": [ + false, + true, + false, + true, + false, + true, + false, + true, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 10, + "month_has_30_days": [ + true, + false, + true, + false, + false, + true, + false, + true, + true, + true, + false, + true, + false + ], + "leap_month_idx": 8 + }, + { + "ny_offset": 29, + "month_has_30_days": [ + true, + false, + true, + false, + false, + true, + false, + true, + true, + false, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 18, + "month_has_30_days": [ + false, + true, + false, + true, + false, + false, + true, + false, + true, + false, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 7, + "month_has_30_days": [ + true, + false, + true, + false, + true, + false, + false, + false, + true, + false, + true, + true, + true + ], + "leap_month_idx": 6 + }, + { + "ny_offset": 26, + "month_has_30_days": [ + false, + true, + true, + false, + true, + false, + false, + false, + true, + false, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 15, + "month_has_30_days": [ + false, + true, + true, + true, + false, + false, + true, + false, + true, + false, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 3, + "month_has_30_days": [ + true, + false, + true, + true, + false, + true, + false, + true, + false, + true, + false, + true, + false + ], + "leap_month_idx": 5 + }, + { + "ny_offset": 22, + "month_has_30_days": [ + false, + true, + true, + false, + true, + false, + true, + true, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 12, + "month_has_30_days": [ + false, + false, + true, + false, + true, + true, + false, + true, + true, + false, + true, + false, + true + ], + "leap_month_idx": 12 + }, + { + "ny_offset": 31, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + true, + true, + false, + true, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 19, + "month_has_30_days": [ + true, + false, + true, + false, + false, + true, + false, + true, + false, + true, + true, + true, + false + ], + "leap_month_idx": null + } + ] +} diff --git a/provider/datagen/tests/data/json/calendar/dangicache@1/und.json b/provider/datagen/tests/data/json/calendar/dangicache@1/und.json new file mode 100644 index 00000000000..0c1836cb07a --- /dev/null +++ b/provider/datagen/tests/data/json/calendar/dangicache@1/und.json @@ -0,0 +1,4755 @@ +{ + "first_extended_year": 4233, + "data": [ + { + "ny_offset": 11, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + true, + true, + false, + true, + true, + false, + true + ], + "leap_month_idx": 9 + }, + { + "ny_offset": 30, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + true, + false, + true, + true, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 19, + "month_has_30_days": [ + true, + false, + true, + false, + false, + true, + false, + true, + false, + true, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 9, + "month_has_30_days": [ + false, + true, + false, + true, + false, + false, + true, + false, + false, + true, + true, + true, + false + ], + "leap_month_idx": 6 + }, + { + "ny_offset": 27, + "month_has_30_days": [ + true, + true, + false, + true, + false, + false, + true, + false, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 15, + "month_has_30_days": [ + true, + true, + true, + false, + true, + false, + false, + true, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 5, + "month_has_30_days": [ + false, + true, + true, + false, + true, + false, + true, + false, + true, + false, + true, + false, + true + ], + "leap_month_idx": 5 + }, + { + "ny_offset": 24, + "month_has_30_days": [ + false, + true, + false, + true, + false, + true, + true, + false, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 13, + "month_has_30_days": [ + true, + false, + true, + false, + true, + false, + true, + false, + true, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 2, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + true, + false, + true, + true, + true, + false, + true + ], + "leap_month_idx": 3 + }, + { + "ny_offset": 21, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + true, + false, + true, + true, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 10, + "month_has_30_days": [ + true, + false, + true, + false, + false, + true, + false, + false, + true, + true, + true, + false, + true + ], + "leap_month_idx": 7 + }, + { + "ny_offset": 29, + "month_has_30_days": [ + true, + false, + true, + false, + false, + true, + false, + false, + true, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 17, + "month_has_30_days": [ + true, + true, + false, + true, + false, + false, + true, + false, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 6, + "month_has_30_days": [ + true, + true, + false, + true, + true, + false, + false, + true, + false, + true, + false, + false, + true + ], + "leap_month_idx": 6 + }, + { + "ny_offset": 25, + "month_has_30_days": [ + true, + false, + true, + true, + false, + true, + false, + true, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 15, + "month_has_30_days": [ + false, + true, + false, + true, + false, + true, + true, + false, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 3, + "month_has_30_days": [ + true, + false, + false, + true, + false, + true, + true, + false, + true, + true, + false, + true, + false + ], + "leap_month_idx": 3 + }, + { + "ny_offset": 22, + "month_has_30_days": [ + true, + false, + false, + true, + false, + true, + false, + true, + true, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 12, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + true, + false, + true, + true, + false, + true, + true + ], + "leap_month_idx": 8 + }, + { + "ny_offset": 31, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + false, + true, + true, + false, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 19, + "month_has_30_days": [ + true, + false, + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 8, + "month_has_30_days": [ + true, + false, + true, + true, + false, + false, + true, + false, + false, + true, + false, + true, + true + ], + "leap_month_idx": 6 + }, + { + "ny_offset": 27, + "month_has_30_days": [ + false, + true, + true, + false, + true, + false, + true, + false, + true, + false, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 16, + "month_has_30_days": [ + true, + false, + true, + false, + true, + true, + false, + true, + false, + true, + false, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 4, + "month_has_30_days": [ + true, + false, + true, + true, + false, + true, + false, + true, + true, + false, + true, + false, + true + ], + "leap_month_idx": 5 + }, + { + "ny_offset": 24, + "month_has_30_days": [ + false, + false, + true, + false, + true, + false, + true, + true, + false, + true, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 13, + "month_has_30_days": [ + true, + false, + false, + true, + false, + true, + false, + true, + true, + false, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 3, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + false, + true, + true, + false, + true, + true, + true + ], + "leap_month_idx": 3 + }, + { + "ny_offset": 21, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 10, + "month_has_30_days": [ + false, + true, + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + false + ], + "leap_month_idx": 7 + }, + { + "ny_offset": 28, + "month_has_30_days": [ + true, + true, + true, + false, + false, + true, + false, + false, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 17, + "month_has_30_days": [ + true, + true, + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 6, + "month_has_30_days": [ + false, + true, + true, + false, + true, + true, + false, + true, + false, + true, + false, + false, + true + ], + "leap_month_idx": 6 + }, + { + "ny_offset": 25, + "month_has_30_days": [ + false, + true, + false, + true, + true, + false, + true, + true, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 15, + "month_has_30_days": [ + false, + false, + true, + false, + true, + false, + true, + true, + false, + true, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 4, + "month_has_30_days": [ + true, + false, + false, + true, + false, + true, + false, + true, + false, + true, + true, + true, + false + ], + "leap_month_idx": 4 + }, + { + "ny_offset": 22, + "month_has_30_days": [ + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 11, + "month_has_30_days": [ + true, + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + false, + true + ], + "leap_month_idx": 8 + }, + { + "ny_offset": 30, + "month_has_30_days": [ + true, + true, + false, + false, + true, + false, + false, + true, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 19, + "month_has_30_days": [ + true, + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 7, + "month_has_30_days": [ + true, + true, + false, + true, + true, + false, + true, + false, + false, + true, + false, + true, + false + ], + "leap_month_idx": 7 + }, + { + "ny_offset": 26, + "month_has_30_days": [ + true, + false, + true, + true, + false, + true, + true, + false, + true, + false, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 16, + "month_has_30_days": [ + false, + true, + false, + true, + false, + true, + true, + false, + true, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 6, + "month_has_30_days": [ + false, + false, + true, + false, + true, + false, + true, + false, + true, + true, + false, + true, + true + ], + "leap_month_idx": 5 + }, + { + "ny_offset": 24, + "month_has_30_days": [ + false, + false, + true, + false, + false, + true, + false, + true, + true, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 13, + "month_has_30_days": [ + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 2, + "month_has_30_days": [ + true, + true, + false, + false, + true, + false, + false, + true, + false, + true, + false, + true, + true + ], + "leap_month_idx": 3 + }, + { + "ny_offset": 21, + "month_has_30_days": [ + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 9, + "month_has_30_days": [ + true, + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + false, + true + ], + "leap_month_idx": 8 + }, + { + "ny_offset": 28, + "month_has_30_days": [ + true, + false, + true, + true, + false, + true, + false, + false, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 17, + "month_has_30_days": [ + true, + false, + true, + true, + false, + true, + false, + true, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 7, + "month_has_30_days": [ + false, + true, + false, + true, + false, + true, + true, + false, + true, + false, + true, + false, + true + ], + "leap_month_idx": 6 + }, + { + "ny_offset": 25, + "month_has_30_days": [ + false, + true, + false, + false, + true, + true, + false, + true, + true, + false, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 15, + "month_has_30_days": [ + false, + false, + true, + false, + false, + true, + false, + true, + true, + false, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 4, + "month_has_30_days": [ + true, + false, + false, + true, + false, + false, + true, + false, + true, + false, + true, + true, + true + ], + "leap_month_idx": 4 + }, + { + "ny_offset": 23, + "month_has_30_days": [ + false, + true, + false, + true, + false, + false, + true, + false, + true, + false, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 11, + "month_has_30_days": [ + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + false, + true, + true + ], + "leap_month_idx": 9 + }, + { + "ny_offset": 30, + "month_has_30_days": [ + false, + true, + true, + false, + true, + false, + false, + true, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 19, + "month_has_30_days": [ + false, + true, + true, + false, + true, + false, + true, + false, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 8, + "month_has_30_days": [ + true, + false, + true, + false, + true, + true, + false, + true, + false, + true, + false, + true, + false + ], + "leap_month_idx": 7 + }, + { + "ny_offset": 26, + "month_has_30_days": [ + true, + false, + true, + false, + true, + false, + true, + true, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 16, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + true, + true, + false, + true, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 5, + "month_has_30_days": [ + true, + false, + true, + false, + false, + true, + false, + true, + false, + true, + true, + true, + false + ], + "leap_month_idx": 5 + }, + { + "ny_offset": 24, + "month_has_30_days": [ + true, + false, + true, + false, + false, + true, + false, + true, + false, + true, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 13, + "month_has_30_days": [ + false, + true, + false, + true, + false, + false, + true, + false, + false, + true, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 2, + "month_has_30_days": [ + false, + true, + true, + false, + true, + false, + false, + true, + false, + false, + true, + true, + false + ], + "leap_month_idx": 4 + }, + { + "ny_offset": 20, + "month_has_30_days": [ + true, + true, + false, + true, + true, + false, + false, + true, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 10, + "month_has_30_days": [ + false, + true, + true, + false, + true, + false, + true, + false, + true, + false, + true, + false, + true + ], + "leap_month_idx": 8 + }, + { + "ny_offset": 28, + "month_has_30_days": [ + false, + true, + false, + true, + false, + true, + true, + false, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 17, + "month_has_30_days": [ + true, + false, + false, + true, + true, + false, + true, + false, + true, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 7, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + true, + false, + true, + true, + true, + false, + true + ], + "leap_month_idx": 6 + }, + { + "ny_offset": 26, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + true, + false, + true, + true, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 14, + "month_has_30_days": [ + true, + false, + true, + false, + false, + true, + false, + false, + true, + true, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 3, + "month_has_30_days": [ + true, + true, + false, + true, + false, + false, + true, + false, + false, + true, + true, + false, + true + ], + "leap_month_idx": 5 + }, + { + "ny_offset": 22, + "month_has_30_days": [ + true, + true, + false, + true, + false, + false, + true, + false, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 11, + "month_has_30_days": [ + true, + true, + false, + true, + false, + true, + false, + true, + false, + true, + false, + false, + true + ], + "leap_month_idx": 9 + }, + { + "ny_offset": 29, + "month_has_30_days": [ + true, + false, + true, + true, + false, + true, + false, + true, + false, + true, + false, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 18, + "month_has_30_days": [ + true, + true, + false, + true, + false, + true, + true, + false, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 8, + "month_has_30_days": [ + true, + false, + false, + true, + false, + true, + true, + false, + true, + true, + false, + true, + false + ], + "leap_month_idx": 7 + }, + { + "ny_offset": 27, + "month_has_30_days": [ + true, + false, + false, + true, + false, + true, + false, + true, + true, + false, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 16, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + false, + true, + true, + false, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 5, + "month_has_30_days": [ + true, + false, + true, + false, + false, + true, + false, + false, + true, + true, + false, + true, + true + ], + "leap_month_idx": 5 + }, + { + "ny_offset": 24, + "month_has_30_days": [ + true, + false, + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 13, + "month_has_30_days": [ + true, + false, + true, + true, + false, + false, + true, + false, + false, + true, + false, + true, + true + ], + "leap_month_idx": 11 + }, + { + "ny_offset": 31, + "month_has_30_days": [ + false, + true, + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 20, + "month_has_30_days": [ + false, + true, + true, + false, + true, + true, + false, + true, + false, + true, + false, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 9, + "month_has_30_days": [ + true, + false, + true, + true, + false, + true, + false, + true, + true, + false, + true, + false, + true + ], + "leap_month_idx": 7 + }, + { + "ny_offset": 29, + "month_has_30_days": [ + false, + false, + true, + false, + true, + false, + true, + true, + false, + true, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 17, + "month_has_30_days": [ + true, + false, + false, + true, + false, + true, + false, + true, + true, + false, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 7, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + false, + true, + true, + false, + true, + true, + true + ], + "leap_month_idx": 6 + }, + { + "ny_offset": 26, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 15, + "month_has_30_days": [ + false, + true, + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 3, + "month_has_30_days": [ + false, + true, + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + false + ], + "leap_month_idx": 4 + }, + { + "ny_offset": 21, + "month_has_30_days": [ + true, + true, + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 11, + "month_has_30_days": [ + false, + true, + true, + false, + true, + true, + false, + true, + false, + true, + false, + false, + true + ], + "leap_month_idx": 9 + }, + { + "ny_offset": 30, + "month_has_30_days": [ + false, + true, + false, + true, + true, + false, + true, + false, + true, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 19, + "month_has_30_days": [ + false, + false, + true, + false, + true, + false, + true, + true, + false, + true, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 8, + "month_has_30_days": [ + true, + false, + false, + true, + false, + false, + true, + true, + false, + true, + true, + true, + false + ], + "leap_month_idx": 6 + }, + { + "ny_offset": 27, + "month_has_30_days": [ + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 16, + "month_has_30_days": [ + true, + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 4, + "month_has_30_days": [ + true, + true, + true, + false, + false, + true, + false, + false, + true, + false, + true, + false, + true + ], + "leap_month_idx": 5 + }, + { + "ny_offset": 23, + "month_has_30_days": [ + true, + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 12, + "month_has_30_days": [ + true, + true, + false, + true, + true, + false, + true, + false, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 2, + "month_has_30_days": [ + false, + true, + false, + true, + true, + false, + true, + false, + true, + false, + true, + false, + true + ], + "leap_month_idx": 3 + }, + { + "ny_offset": 20, + "month_has_30_days": [ + false, + true, + false, + true, + false, + true, + true, + false, + true, + true, + false, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 9, + "month_has_30_days": [ + true, + false, + true, + false, + true, + false, + true, + false, + true, + true, + false, + true, + true + ], + "leap_month_idx": 8 + }, + { + "ny_offset": 29, + "month_has_30_days": [ + false, + false, + true, + false, + false, + true, + false, + true, + true, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 18, + "month_has_30_days": [ + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 6, + "month_has_30_days": [ + true, + true, + false, + false, + true, + false, + false, + true, + false, + true, + false, + true, + true + ], + "leap_month_idx": 6 + }, + { + "ny_offset": 25, + "month_has_30_days": [ + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 14, + "month_has_30_days": [ + true, + false, + true, + true, + false, + true, + false, + false, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 3, + "month_has_30_days": [ + true, + false, + true, + true, + true, + false, + true, + false, + false, + true, + false, + true, + false + ], + "leap_month_idx": 4 + }, + { + "ny_offset": 21, + "month_has_30_days": [ + true, + false, + true, + true, + false, + true, + false, + true, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 11, + "month_has_30_days": [ + false, + true, + false, + true, + false, + true, + false, + true, + true, + false, + true, + false, + true + ], + "leap_month_idx": 10 + }, + { + "ny_offset": 30, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + true, + true, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 19, + "month_has_30_days": [ + true, + false, + true, + false, + false, + true, + false, + true, + true, + false, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 8, + "month_has_30_days": [ + false, + true, + false, + true, + false, + false, + true, + false, + true, + false, + true, + true, + true + ], + "leap_month_idx": 6 + }, + { + "ny_offset": 27, + "month_has_30_days": [ + false, + true, + false, + true, + false, + false, + true, + false, + true, + false, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 16, + "month_has_30_days": [ + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 5, + "month_has_30_days": [ + true, + false, + true, + true, + false, + true, + false, + false, + true, + false, + true, + false, + true + ], + "leap_month_idx": 5 + }, + { + "ny_offset": 23, + "month_has_30_days": [ + false, + true, + true, + false, + true, + false, + true, + false, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 12, + "month_has_30_days": [ + true, + false, + true, + false, + true, + true, + false, + true, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 2, + "month_has_30_days": [ + false, + true, + false, + true, + false, + true, + false, + true, + true, + false, + true, + false, + true + ], + "leap_month_idx": 3 + }, + { + "ny_offset": 21, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + true, + true, + false, + true, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 9, + "month_has_30_days": [ + true, + false, + true, + false, + false, + true, + false, + true, + false, + true, + true, + true, + false + ], + "leap_month_idx": 7 + }, + { + "ny_offset": 28, + "month_has_30_days": [ + true, + false, + true, + false, + false, + true, + false, + true, + false, + true, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 18, + "month_has_30_days": [ + false, + true, + false, + true, + false, + false, + true, + false, + false, + true, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 7, + "month_has_30_days": [ + false, + true, + true, + false, + true, + false, + false, + true, + false, + false, + true, + true, + false + ], + "leap_month_idx": 6 + }, + { + "ny_offset": 24, + "month_has_30_days": [ + true, + true, + false, + true, + true, + false, + false, + true, + false, + false, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 14, + "month_has_30_days": [ + false, + true, + false, + true, + true, + false, + true, + false, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 3, + "month_has_30_days": [ + true, + false, + true, + false, + true, + false, + true, + true, + false, + true, + false, + true, + false + ], + "leap_month_idx": 4 + }, + { + "ny_offset": 22, + "month_has_30_days": [ + true, + false, + false, + true, + false, + true, + true, + false, + true, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 11, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + true, + false, + true, + true, + true, + false, + true + ], + "leap_month_idx": 12 + }, + { + "ny_offset": 30, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + true, + false, + true, + true, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 19, + "month_has_30_days": [ + true, + false, + true, + false, + false, + true, + false, + false, + true, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 8, + "month_has_30_days": [ + true, + true, + false, + true, + false, + false, + true, + false, + false, + true, + true, + false, + true + ], + "leap_month_idx": 7 + }, + { + "ny_offset": 26, + "month_has_30_days": [ + true, + true, + false, + true, + false, + false, + true, + false, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 15, + "month_has_30_days": [ + true, + true, + false, + true, + false, + true, + false, + true, + false, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 4, + "month_has_30_days": [ + true, + true, + false, + true, + true, + false, + true, + false, + true, + false, + true, + false, + false + ], + "leap_month_idx": 6 + }, + { + "ny_offset": 23, + "month_has_30_days": [ + true, + false, + true, + true, + false, + true, + true, + false, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 12, + "month_has_30_days": [ + true, + false, + false, + true, + false, + true, + true, + false, + true, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 2, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + true, + false, + true, + true, + false, + true, + true + ], + "leap_month_idx": 3 + }, + { + "ny_offset": 21, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + false, + true, + true, + false, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 10, + "month_has_30_days": [ + true, + false, + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + true + ], + "leap_month_idx": 8 + }, + { + "ny_offset": 28, + "month_has_30_days": [ + true, + false, + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 17, + "month_has_30_days": [ + true, + false, + true, + true, + false, + false, + true, + false, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 6, + "month_has_30_days": [ + true, + false, + true, + true, + false, + true, + false, + true, + false, + false, + true, + false, + true + ], + "leap_month_idx": 6 + }, + { + "ny_offset": 25, + "month_has_30_days": [ + false, + true, + true, + false, + true, + true, + false, + true, + false, + true, + false, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 13, + "month_has_30_days": [ + true, + false, + true, + false, + true, + true, + false, + true, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 3, + "month_has_30_days": [ + true, + false, + false, + true, + false, + true, + false, + true, + true, + false, + true, + true, + false + ], + "leap_month_idx": 4 + }, + { + "ny_offset": 22, + "month_has_30_days": [ + true, + false, + false, + true, + false, + true, + false, + true, + false, + true, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 12, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + false, + true, + true, + false, + true, + true, + true + ], + "leap_month_idx": 9 + }, + { + "ny_offset": 30, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 19, + "month_has_30_days": [ + false, + true, + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 8, + "month_has_30_days": [ + false, + true, + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + false + ], + "leap_month_idx": 7 + }, + { + "ny_offset": 26, + "month_has_30_days": [ + true, + true, + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 15, + "month_has_30_days": [ + false, + true, + true, + false, + true, + false, + true, + true, + false, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 4, + "month_has_30_days": [ + true, + false, + true, + false, + true, + true, + false, + true, + false, + true, + true, + false, + false + ], + "leap_month_idx": 5 + }, + { + "ny_offset": 23, + "month_has_30_days": [ + true, + false, + true, + false, + true, + false, + true, + true, + false, + true, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 13, + "month_has_30_days": [ + true, + false, + false, + true, + false, + false, + true, + true, + false, + true, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 2, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + true, + false + ], + "leap_month_idx": 4 + }, + { + "ny_offset": 20, + "month_has_30_days": [ + true, + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 9, + "month_has_30_days": [ + true, + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + false, + true + ], + "leap_month_idx": 8 + }, + { + "ny_offset": 28, + "month_has_30_days": [ + true, + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 16, + "month_has_30_days": [ + true, + true, + false, + true, + true, + false, + true, + false, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 6, + "month_has_30_days": [ + false, + true, + false, + true, + true, + false, + true, + false, + true, + false, + true, + false, + true + ], + "leap_month_idx": 6 + }, + { + "ny_offset": 25, + "month_has_30_days": [ + false, + true, + false, + true, + false, + true, + true, + false, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 14, + "month_has_30_days": [ + true, + false, + true, + false, + true, + false, + true, + false, + true, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 3, + "month_has_30_days": [ + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + true, + false, + true + ], + "leap_month_idx": 5 + }, + { + "ny_offset": 22, + "month_has_30_days": [ + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 11, + "month_has_30_days": [ + true, + true, + false, + false, + true, + false, + false, + true, + false, + true, + false, + true, + true + ], + "leap_month_idx": 9 + }, + { + "ny_offset": 30, + "month_has_30_days": [ + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 18, + "month_has_30_days": [ + true, + false, + true, + true, + false, + true, + false, + false, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 7, + "month_has_30_days": [ + true, + false, + true, + true, + false, + true, + false, + true, + false, + true, + false, + true, + false + ], + "leap_month_idx": 7 + }, + { + "ny_offset": 26, + "month_has_30_days": [ + true, + false, + true, + false, + true, + true, + false, + true, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 16, + "month_has_30_days": [ + false, + true, + false, + true, + false, + true, + false, + true, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 4, + "month_has_30_days": [ + true, + false, + true, + false, + false, + true, + false, + true, + true, + true, + false, + true, + false + ], + "leap_month_idx": 5 + }, + { + "ny_offset": 23, + "month_has_30_days": [ + true, + false, + true, + false, + false, + true, + false, + true, + true, + false, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 13, + "month_has_30_days": [ + false, + true, + false, + true, + false, + false, + true, + false, + true, + false, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 2, + "month_has_30_days": [ + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + false, + true, + true + ], + "leap_month_idx": 4 + }, + { + "ny_offset": 20, + "month_has_30_days": [ + true, + false, + true, + false, + true, + false, + false, + true, + false, + false, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 9, + "month_has_30_days": [ + false, + true, + true, + true, + false, + true, + false, + false, + true, + false, + true, + false, + true + ], + "leap_month_idx": 8 + }, + { + "ny_offset": 28, + "month_has_30_days": [ + false, + true, + true, + false, + true, + false, + true, + false, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 17, + "month_has_30_days": [ + true, + false, + true, + false, + true, + true, + false, + true, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 6, + "month_has_30_days": [ + false, + true, + false, + false, + true, + true, + false, + true, + true, + false, + true, + false, + true + ], + "leap_month_idx": 6 + }, + { + "ny_offset": 25, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + true, + true, + false, + true, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 14, + "month_has_30_days": [ + true, + false, + true, + false, + false, + true, + false, + true, + false, + true, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 4, + "month_has_30_days": [ + false, + true, + false, + true, + false, + false, + true, + false, + false, + true, + true, + true, + true + ], + "leap_month_idx": 5 + }, + { + "ny_offset": 22, + "month_has_30_days": [ + false, + true, + false, + true, + false, + false, + true, + false, + false, + true, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 10, + "month_has_30_days": [ + true, + true, + true, + false, + true, + false, + false, + true, + false, + false, + true, + true, + false + ], + "leap_month_idx": 9 + }, + { + "ny_offset": 29, + "month_has_30_days": [ + true, + true, + false, + true, + false, + true, + false, + true, + false, + false, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 19, + "month_has_30_days": [ + false, + true, + false, + true, + true, + false, + true, + false, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 7, + "month_has_30_days": [ + true, + false, + true, + false, + true, + false, + true, + true, + false, + true, + false, + true, + false + ], + "leap_month_idx": 7 + }, + { + "ny_offset": 26, + "month_has_30_days": [ + true, + false, + false, + true, + false, + true, + true, + false, + true, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 16, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + true, + false, + true, + true, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 5, + "month_has_30_days": [ + true, + false, + true, + false, + false, + true, + false, + true, + false, + true, + true, + false, + true + ], + "leap_month_idx": 5 + }, + { + "ny_offset": 23, + "month_has_30_days": [ + true, + false, + true, + false, + false, + true, + false, + false, + true, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 12, + "month_has_30_days": [ + true, + true, + false, + true, + false, + false, + true, + false, + false, + true, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 1, + "month_has_30_days": [ + true, + true, + true, + false, + true, + false, + false, + true, + false, + false, + true, + false, + true + ], + "leap_month_idx": 4 + }, + { + "ny_offset": 20, + "month_has_30_days": [ + true, + true, + false, + true, + false, + true, + false, + true, + false, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 9, + "month_has_30_days": [ + true, + true, + false, + true, + true, + false, + true, + false, + true, + false, + true, + false, + false + ], + "leap_month_idx": 8 + }, + { + "ny_offset": 28, + "month_has_30_days": [ + true, + false, + true, + true, + false, + true, + false, + true, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 18, + "month_has_30_days": [ + true, + false, + false, + true, + false, + true, + true, + false, + true, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 8, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + true, + false, + true, + true, + false, + true, + true + ], + "leap_month_idx": 6 + }, + { + "ny_offset": 26, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + false, + true, + true, + false, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 15, + "month_has_30_days": [ + true, + false, + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 4, + "month_has_30_days": [ + true, + true, + false, + true, + false, + false, + true, + false, + false, + true, + false, + true, + true + ], + "leap_month_idx": 5 + }, + { + "ny_offset": 23, + "month_has_30_days": [ + true, + false, + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 11, + "month_has_30_days": [ + true, + false, + true, + true, + false, + true, + false, + true, + false, + false, + true, + false, + true + ], + "leap_month_idx": 10 + }, + { + "ny_offset": 30, + "month_has_30_days": [ + false, + true, + true, + false, + true, + true, + false, + true, + false, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 19, + "month_has_30_days": [ + true, + false, + true, + false, + true, + true, + false, + true, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 9, + "month_has_30_days": [ + false, + true, + false, + true, + false, + true, + false, + true, + true, + false, + true, + true, + false + ], + "leap_month_idx": 7 + }, + { + "ny_offset": 27, + "month_has_30_days": [ + true, + false, + false, + true, + false, + false, + true, + true, + false, + true, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 17, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 6, + "month_has_30_days": [ + true, + false, + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + true + ], + "leap_month_idx": 5 + }, + { + "ny_offset": 25, + "month_has_30_days": [ + false, + true, + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 13, + "month_has_30_days": [ + false, + true, + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 2, + "month_has_30_days": [ + false, + true, + true, + true, + false, + true, + false, + true, + false, + false, + true, + false, + true + ], + "leap_month_idx": 4 + }, + { + "ny_offset": 21, + "month_has_30_days": [ + false, + true, + true, + false, + true, + false, + true, + true, + false, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 10, + "month_has_30_days": [ + true, + false, + true, + false, + true, + false, + true, + true, + false, + true, + false, + true, + false + ], + "leap_month_idx": 8 + }, + { + "ny_offset": 28, + "month_has_30_days": [ + true, + false, + true, + false, + true, + false, + true, + true, + false, + true, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 18, + "month_has_30_days": [ + true, + false, + false, + true, + false, + false, + true, + true, + false, + true, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 7, + "month_has_30_days": [ + true, + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + true, + false + ], + "leap_month_idx": 6 + }, + { + "ny_offset": 26, + "month_has_30_days": [ + true, + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 14, + "month_has_30_days": [ + true, + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 3, + "month_has_30_days": [ + true, + true, + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + false + ], + "leap_month_idx": 5 + }, + { + "ny_offset": 22, + "month_has_30_days": [ + true, + true, + false, + true, + true, + false, + true, + false, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 12, + "month_has_30_days": [ + false, + true, + false, + true, + true, + false, + true, + false, + true, + false, + true, + false, + true + ], + "leap_month_idx": 10 + }, + { + "ny_offset": 30, + "month_has_30_days": [ + false, + true, + false, + true, + false, + true, + true, + false, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 19, + "month_has_30_days": [ + true, + false, + true, + false, + false, + true, + true, + false, + true, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 9, + "month_has_30_days": [ + false, + true, + false, + true, + false, + false, + true, + false, + true, + true, + true, + false, + true + ], + "leap_month_idx": 7 + }, + { + "ny_offset": 28, + "month_has_30_days": [ + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 16, + "month_has_30_days": [ + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 5, + "month_has_30_days": [ + true, + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + false, + true + ], + "leap_month_idx": 6 + }, + { + "ny_offset": 24, + "month_has_30_days": [ + true, + false, + true, + true, + false, + true, + false, + false, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 13, + "month_has_30_days": [ + true, + false, + true, + true, + false, + true, + false, + true, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 2, + "month_has_30_days": [ + false, + true, + false, + true, + false, + true, + true, + false, + true, + false, + true, + false, + true + ], + "leap_month_idx": 3 + }, + { + "ny_offset": 21, + "month_has_30_days": [ + false, + true, + false, + true, + false, + true, + false, + true, + true, + false, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 10, + "month_has_30_days": [ + true, + false, + true, + false, + false, + true, + false, + true, + true, + true, + false, + true, + false + ], + "leap_month_idx": 8 + }, + { + "ny_offset": 29, + "month_has_30_days": [ + true, + false, + true, + false, + false, + true, + false, + true, + true, + false, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 18, + "month_has_30_days": [ + false, + true, + false, + true, + false, + false, + true, + false, + true, + false, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 7, + "month_has_30_days": [ + true, + false, + true, + false, + true, + false, + false, + true, + false, + false, + true, + true, + true + ], + "leap_month_idx": 6 + }, + { + "ny_offset": 26, + "month_has_30_days": [ + false, + true, + true, + false, + true, + false, + false, + true, + false, + false, + true, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 15, + "month_has_30_days": [ + false, + true, + true, + true, + false, + false, + true, + false, + true, + false, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 3, + "month_has_30_days": [ + true, + false, + true, + true, + false, + true, + false, + true, + false, + true, + false, + true, + false + ], + "leap_month_idx": 5 + }, + { + "ny_offset": 22, + "month_has_30_days": [ + true, + false, + true, + false, + true, + true, + false, + true, + false, + true, + false, + true, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 12, + "month_has_30_days": [ + false, + true, + false, + false, + true, + true, + false, + true, + true, + false, + true, + false, + true + ], + "leap_month_idx": 12 + }, + { + "ny_offset": 31, + "month_has_30_days": [ + false, + true, + false, + false, + true, + false, + true, + true, + false, + true, + true, + false, + false + ], + "leap_month_idx": null + }, + { + "ny_offset": 19, + "month_has_30_days": [ + true, + false, + true, + false, + false, + true, + false, + true, + false, + true, + true, + true, + false + ], + "leap_month_idx": null + } + ] +} diff --git a/provider/datagen/tests/data/postcard/fingerprints.csv b/provider/datagen/tests/data/postcard/fingerprints.csv index 7ebce7fb438..f05f733ecd9 100644 --- a/provider/datagen/tests/data/postcard/fingerprints.csv +++ b/provider/datagen/tests/data/postcard/fingerprints.csv @@ -1,3 +1,5 @@ +calendar/chinesecache@1, und, 754B, c116ab2a7479b26d +calendar/dangicache@1, und, 754B, d7565838cc8c6aa6 calendar/japanese@1, und, 111B, b31e52deaf52706f calendar/japanext@1, und, 5216B, 6c20e216c8cd6e41 collator/data@1, ar, 8267B, fce742b37324adbe