/rust/registry/src/index.crates.io-1949cf8c6b5b557f/icu_calendar-1.5.2/src/islamic.rs
Line | Count | Source |
1 | | // This file is part of ICU4X. For terms of use, please see the file |
2 | | // called LICENSE at the top level of the ICU4X source tree |
3 | | // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). |
4 | | |
5 | | //! This module contains types and implementations for the Islamic calendars. |
6 | | //! |
7 | | //! ```rust |
8 | | //! use icu::calendar::islamic::IslamicObservational; |
9 | | //! use icu::calendar::{Date, DateTime, Ref}; |
10 | | //! |
11 | | //! let islamic = IslamicObservational::new_always_calculating(); |
12 | | //! let islamic = Ref(&islamic); // to avoid cloning |
13 | | //! |
14 | | //! // `Date` type |
15 | | //! let islamic_date = |
16 | | //! Date::try_new_observational_islamic_date(1348, 10, 11, islamic) |
17 | | //! .expect("Failed to initialize islamic Date instance."); |
18 | | //! |
19 | | //! // `DateTime` type |
20 | | //! let islamic_datetime = DateTime::try_new_observational_islamic_datetime( |
21 | | //! 1348, 10, 11, 13, 1, 0, islamic, |
22 | | //! ) |
23 | | //! .expect("Failed to initialize islamic DateTime instance."); |
24 | | //! |
25 | | //! // `Date` checks |
26 | | //! assert_eq!(islamic_date.year().number, 1348); |
27 | | //! assert_eq!(islamic_date.month().ordinal, 10); |
28 | | //! assert_eq!(islamic_date.day_of_month().0, 11); |
29 | | //! |
30 | | //! // `DateTime` checks |
31 | | //! assert_eq!(islamic_datetime.date.year().number, 1348); |
32 | | //! assert_eq!(islamic_datetime.date.month().ordinal, 10); |
33 | | //! assert_eq!(islamic_datetime.date.day_of_month().0, 11); |
34 | | //! assert_eq!(islamic_datetime.time.hour.number(), 13); |
35 | | //! assert_eq!(islamic_datetime.time.minute.number(), 1); |
36 | | //! assert_eq!(islamic_datetime.time.second.number(), 0); |
37 | | //! ``` |
38 | | |
39 | | use crate::calendar_arithmetic::PrecomputedDataSource; |
40 | | use crate::calendar_arithmetic::{ArithmeticDate, CalendarArithmetic}; |
41 | | use crate::provider::islamic::{ |
42 | | IslamicCacheV1, IslamicObservationalCacheV1Marker, IslamicUmmAlQuraCacheV1Marker, |
43 | | PackedIslamicYearInfo, |
44 | | }; |
45 | | use crate::AnyCalendarKind; |
46 | | use crate::AsCalendar; |
47 | | use crate::Iso; |
48 | | use crate::{types, Calendar, CalendarError, Date, DateDuration, DateDurationUnit, DateTime, Time}; |
49 | | use calendrical_calculations::islamic::{ |
50 | | IslamicBasedMarker, ObservationalIslamicMarker, SaudiIslamicMarker, |
51 | | }; |
52 | | use calendrical_calculations::rata_die::RataDie; |
53 | | use core::marker::PhantomData; |
54 | | use icu_provider::prelude::*; |
55 | | use tinystr::tinystr; |
56 | | |
57 | | /// Islamic Observational Calendar (Default) |
58 | | /// |
59 | | /// # Era codes |
60 | | /// |
61 | | /// This calendar supports a single era code, Anno Mundi, with code `"ah"` |
62 | | /// |
63 | | /// # Month codes |
64 | | /// |
65 | | /// This calendar is a pure lunar calendar with no leap months. It uses month codes |
66 | | /// `"M01" - "M12"`. |
67 | | #[derive(Clone, Debug, Default)] |
68 | | pub struct IslamicObservational { |
69 | | data: Option<DataPayload<IslamicObservationalCacheV1Marker>>, |
70 | | } |
71 | | |
72 | | /// Civil / Arithmetical Islamic Calendar (Used for administrative purposes) |
73 | | /// |
74 | | /// # Era codes |
75 | | /// |
76 | | /// This calendar supports a single era code, Anno Mundi, with code `"ah"` |
77 | | /// |
78 | | /// # Month codes |
79 | | /// |
80 | | /// This calendar is a pure lunar calendar with no leap months. It uses month codes |
81 | | /// `"M01" - "M12"`. |
82 | | #[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq, PartialOrd, Ord)] |
83 | | #[allow(clippy::exhaustive_structs)] // unit struct |
84 | | pub struct IslamicCivil; |
85 | | |
86 | | /// Umm al-Qura Hijri Calendar (Used in Saudi Arabia) |
87 | | /// |
88 | | /// # Era codes |
89 | | /// |
90 | | /// This calendar supports a single era code, Anno Mundi, with code `"ah"` |
91 | | /// |
92 | | /// # Month codes |
93 | | /// |
94 | | /// This calendar is a pure lunar calendar with no leap months. It uses month codes |
95 | | /// `"M01" - "M12"`. |
96 | | #[derive(Clone, Debug, Default)] |
97 | | pub struct IslamicUmmAlQura { |
98 | | data: Option<DataPayload<IslamicUmmAlQuraCacheV1Marker>>, |
99 | | } |
100 | | |
101 | | /// A Tabular version of the Arithmetical Islamic Calendar |
102 | | /// |
103 | | /// # Era codes |
104 | | /// |
105 | | /// This calendar supports a single era code, Anno Mundi, with code `"ah"` |
106 | | /// |
107 | | /// # Month codes |
108 | | /// |
109 | | /// This calendar is a pure lunar calendar with no leap months. It uses month codes |
110 | | /// `"M01" - "M12"`. |
111 | | #[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq, PartialOrd, Ord)] |
112 | | #[allow(clippy::exhaustive_structs)] // unit struct |
113 | | pub struct IslamicTabular; |
114 | | |
115 | | impl IslamicObservational { |
116 | | /// Creates a new [`IslamicObservational`] with some compiled data containing precomputed calendrical calculations. |
117 | | /// |
118 | | /// ✨ *Enabled with the `compiled_data` Cargo feature.* |
119 | | /// |
120 | | /// [📚 Help choosing a constructor](icu_provider::constructors) |
121 | | #[cfg(feature = "compiled_data")] |
122 | 0 | pub const fn new() -> Self { |
123 | 0 | Self { |
124 | 0 | data: Some(DataPayload::from_static_ref( |
125 | 0 | crate::provider::Baked::SINGLETON_CALENDAR_ISLAMICOBSERVATIONALCACHE_V1, |
126 | 0 | )), |
127 | 0 | } |
128 | 0 | } |
129 | | |
130 | | icu_provider::gen_any_buffer_data_constructors!(locale: skip, options: skip, error: CalendarError, |
131 | | #[cfg(skip)] |
132 | | functions: [ |
133 | | new, |
134 | | try_new_with_any_provider, |
135 | | try_new_with_buffer_provider, |
136 | | try_new_unstable, |
137 | | Self, |
138 | | ]); |
139 | | |
140 | | #[doc = icu_provider::gen_any_buffer_unstable_docs!(UNSTABLE, Self::new)] |
141 | 0 | pub fn try_new_unstable<D: DataProvider<IslamicObservationalCacheV1Marker> + ?Sized>( |
142 | 0 | provider: &D, |
143 | 0 | ) -> Result<Self, CalendarError> { |
144 | | Ok(Self { |
145 | 0 | data: Some(provider.load(Default::default())?.take_payload()?), |
146 | | }) |
147 | 0 | } Unexecuted instantiation: <icu_calendar::islamic::IslamicObservational>::try_new_unstable::<icu_provider::any::DowncastingAnyProvider<icu_provider_adapters::empty::EmptyDataProvider>> Unexecuted instantiation: <icu_calendar::islamic::IslamicObservational>::try_new_unstable::<_> |
148 | | |
149 | | /// Construct a new [`IslamicObservational`] without any precomputed calendrical calculations. |
150 | 0 | pub fn new_always_calculating() -> Self { |
151 | 0 | Self { data: None } |
152 | 0 | } |
153 | | } |
154 | | |
155 | | impl IslamicCivil { |
156 | | /// Construct a new [`IslamicCivil`] |
157 | 0 | pub fn new() -> Self { |
158 | 0 | Self |
159 | 0 | } |
160 | | |
161 | | /// Construct a new [`IslamicCivil`] (deprecated: we will not add precomputation to this calendar) |
162 | | #[deprecated = "Precomputation not needed for this calendar"] |
163 | 0 | pub fn new_always_calculating() -> Self { |
164 | 0 | Self |
165 | 0 | } |
166 | | } |
167 | | |
168 | | impl IslamicUmmAlQura { |
169 | | /// Creates a new [`IslamicUmmAlQura`] with some compiled data containing precomputed calendrical calculations. |
170 | | /// |
171 | | /// ✨ *Enabled with the `compiled_data` Cargo feature.* |
172 | | /// |
173 | | /// [📚 Help choosing a constructor](icu_provider::constructors) |
174 | | #[cfg(feature = "compiled_data")] |
175 | 0 | pub const fn new() -> Self { |
176 | 0 | Self { |
177 | 0 | data: Some(DataPayload::from_static_ref( |
178 | 0 | crate::provider::Baked::SINGLETON_CALENDAR_ISLAMICUMMALQURACACHE_V1, |
179 | 0 | )), |
180 | 0 | } |
181 | 0 | } |
182 | | |
183 | | icu_provider::gen_any_buffer_data_constructors!(locale: skip, options: skip, error: CalendarError, |
184 | | #[cfg(skip)] |
185 | | functions: [ |
186 | | new, |
187 | | try_new_with_any_provider, |
188 | | try_new_with_buffer_provider, |
189 | | try_new_unstable, |
190 | | Self, |
191 | | ]); |
192 | | |
193 | | #[doc = icu_provider::gen_any_buffer_unstable_docs!(UNSTABLE, Self::new)] |
194 | 0 | pub fn try_new_unstable<D: DataProvider<IslamicUmmAlQuraCacheV1Marker> + ?Sized>( |
195 | 0 | provider: &D, |
196 | 0 | ) -> Result<Self, CalendarError> { |
197 | | Ok(Self { |
198 | 0 | data: Some(provider.load(Default::default())?.take_payload()?), |
199 | | }) |
200 | 0 | } Unexecuted instantiation: <icu_calendar::islamic::IslamicUmmAlQura>::try_new_unstable::<icu_provider::any::DowncastingAnyProvider<icu_provider_adapters::empty::EmptyDataProvider>> Unexecuted instantiation: <icu_calendar::islamic::IslamicUmmAlQura>::try_new_unstable::<_> |
201 | | |
202 | | /// Construct a new [`IslamicUmmAlQura`] without any precomputed calendrical calculations. |
203 | 0 | pub fn new_always_calculating() -> Self { |
204 | 0 | Self { data: None } |
205 | 0 | } |
206 | | } |
207 | | |
208 | | impl IslamicTabular { |
209 | | /// Construct a new [`IslamicTabular`] |
210 | 0 | pub fn new() -> Self { |
211 | 0 | Self |
212 | 0 | } |
213 | | |
214 | | /// Construct a new [`IslamicTabular`] (deprecated: we will not add precomputation to this calendar) |
215 | | #[deprecated = "Precomputation not needed for this calendar"] |
216 | 0 | pub fn new_always_calculating() -> Self { |
217 | 0 | Self |
218 | 0 | } |
219 | | } |
220 | | |
221 | | /// Compact representation of the length of an Islamic year. |
222 | | #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] |
223 | | enum IslamicYearLength { |
224 | | /// Long (355-day) Islamic year |
225 | | L355, |
226 | | /// Short (354-day) Islamic year |
227 | | L354, |
228 | | /// Unexpectedly Short (353-day) Islamic year |
229 | | /// |
230 | | /// It is probably a bug when this year length is returned. See: |
231 | | /// <https://github.com/unicode-org/icu4x/issues/4930> |
232 | | L353, |
233 | | } |
234 | | |
235 | | impl Default for IslamicYearLength { |
236 | 0 | fn default() -> Self { |
237 | 0 | Self::L354 |
238 | 0 | } |
239 | | } |
240 | | |
241 | | impl IslamicYearLength { |
242 | 0 | fn try_from_int(value: i64) -> Option<Self> { |
243 | 0 | match value { |
244 | 0 | 355 => Some(Self::L355), |
245 | 0 | 354 => Some(Self::L354), |
246 | 0 | 353 => Some(Self::L353), |
247 | 0 | _ => None, |
248 | | } |
249 | 0 | } |
250 | 0 | fn to_int(self) -> u16 { |
251 | 0 | match self { |
252 | 0 | Self::L355 => 355, |
253 | 0 | Self::L354 => 354, |
254 | 0 | Self::L353 => 353, |
255 | | } |
256 | 0 | } |
257 | | } |
258 | | |
259 | | #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] |
260 | | pub(crate) struct IslamicYearInfo { |
261 | | packed_data: PackedIslamicYearInfo, |
262 | | prev_year_length: IslamicYearLength, |
263 | | } |
264 | | |
265 | | impl IslamicYearInfo { |
266 | | pub(crate) const LONG_YEAR_LEN: u16 = 355; |
267 | | const SHORT_YEAR_LEN: u16 = 354; |
268 | 0 | pub(crate) fn new( |
269 | 0 | prev_packed: PackedIslamicYearInfo, |
270 | 0 | this_packed: PackedIslamicYearInfo, |
271 | 0 | extended_year: i32, |
272 | 0 | ) -> (Self, i32) { |
273 | 0 | let days_in_year = prev_packed.days_in_year(); |
274 | 0 | let days_in_year = match IslamicYearLength::try_from_int(days_in_year as i64) { |
275 | 0 | Some(x) => x, |
276 | | None => { |
277 | 0 | debug_assert!(false, "Found wrong year length for Islamic year {extended_year}: Expected 355, 354, or 353, got {days_in_year}"); |
278 | 0 | Default::default() |
279 | | } |
280 | | }; |
281 | 0 | let year_info = Self { |
282 | 0 | prev_year_length: days_in_year, |
283 | 0 | packed_data: this_packed, |
284 | 0 | }; |
285 | 0 | (year_info, extended_year) |
286 | 0 | } |
287 | | |
288 | 0 | fn compute<IB: IslamicBasedMarker>(extended_year: i32) -> Self { |
289 | 0 | let ny = IB::fixed_from_islamic(extended_year, 1, 1); |
290 | 0 | let packed_data = PackedIslamicYearInfo::compute_with_ny::<IB>(extended_year, ny); |
291 | 0 | let prev_ny = IB::fixed_from_islamic(extended_year - 1, 1, 1); |
292 | 0 | let rd_diff = ny - prev_ny; |
293 | 0 | let rd_diff = match IslamicYearLength::try_from_int(rd_diff) { |
294 | 0 | Some(x) => x, |
295 | | None => { |
296 | 0 | debug_assert!(false, "({}) Found wrong year length for Islamic year {extended_year}: Expected 355, 354, or 353, got {rd_diff}", IB::DEBUG_NAME); |
297 | 0 | Default::default() |
298 | | } |
299 | | }; |
300 | 0 | Self { |
301 | 0 | prev_year_length: rd_diff, |
302 | 0 | packed_data, |
303 | 0 | } |
304 | 0 | } Unexecuted instantiation: <icu_calendar::islamic::IslamicYearInfo>::compute::<calendrical_calculations::islamic::SaudiIslamicMarker> Unexecuted instantiation: <icu_calendar::islamic::IslamicYearInfo>::compute::<calendrical_calculations::islamic::ObservationalIslamicMarker> |
305 | | /// Get the new year R.D. given the extended year that this yearinfo is for |
306 | 0 | fn new_year<IB: IslamicBasedMarker>(self, extended_year: i32) -> RataDie { |
307 | 0 | IB::mean_synodic_ny(extended_year) + i64::from(self.packed_data.ny_offset()) |
308 | 0 | } Unexecuted instantiation: <icu_calendar::islamic::IslamicYearInfo>::new_year::<calendrical_calculations::islamic::SaudiIslamicMarker> Unexecuted instantiation: <icu_calendar::islamic::IslamicYearInfo>::new_year::<calendrical_calculations::islamic::ObservationalIslamicMarker> |
309 | | |
310 | | /// Get the date's R.D. given (y, m, d) in this info's year |
311 | 0 | fn rd_for<IB: IslamicBasedMarker>(self, extended_year: i32, month: u8, day: u8) -> RataDie { |
312 | 0 | let ny = self.new_year::<IB>(extended_year); |
313 | 0 | let month_offset = if month == 1 { |
314 | 0 | 0 |
315 | | } else { |
316 | 0 | self.packed_data.last_day_of_month(month - 1) |
317 | | }; |
318 | | // -1 since the offset is 1-indexed but the new year is also day 1 |
319 | 0 | ny - 1 + month_offset.into() + day.into() |
320 | 0 | } Unexecuted instantiation: <icu_calendar::islamic::IslamicYearInfo>::rd_for::<calendrical_calculations::islamic::SaudiIslamicMarker> Unexecuted instantiation: <icu_calendar::islamic::IslamicYearInfo>::rd_for::<calendrical_calculations::islamic::ObservationalIslamicMarker> |
321 | | |
322 | | #[inline] |
323 | 0 | fn days_in_prev_year(self) -> u16 { |
324 | 0 | self.prev_year_length.to_int() |
325 | 0 | } |
326 | | } |
327 | | |
328 | | /// Contains any loaded precomputed data. If constructed with Default, will |
329 | | /// *not* contain any extra data and will always compute stuff from scratch |
330 | | #[derive(Default)] |
331 | | pub(crate) struct IslamicPrecomputedData<'a, IB: IslamicBasedMarker> { |
332 | | data: Option<&'a IslamicCacheV1<'a>>, |
333 | | _ib: PhantomData<IB>, |
334 | | } |
335 | | |
336 | | impl<'b, IB: IslamicBasedMarker> PrecomputedDataSource<IslamicYearInfo> |
337 | | for IslamicPrecomputedData<'b, IB> |
338 | | { |
339 | 0 | fn load_or_compute_info(&self, extended_year: i32) -> IslamicYearInfo { |
340 | 0 | self.data |
341 | 0 | .and_then(|d| d.get_for_extended_year(extended_year)) Unexecuted instantiation: <icu_calendar::islamic::IslamicPrecomputedData<calendrical_calculations::islamic::SaudiIslamicMarker> as icu_calendar::calendar_arithmetic::PrecomputedDataSource<icu_calendar::islamic::IslamicYearInfo>>::load_or_compute_info::{closure#0} Unexecuted instantiation: <icu_calendar::islamic::IslamicPrecomputedData<calendrical_calculations::islamic::ObservationalIslamicMarker> as icu_calendar::calendar_arithmetic::PrecomputedDataSource<icu_calendar::islamic::IslamicYearInfo>>::load_or_compute_info::{closure#0} |
342 | 0 | .unwrap_or_else(|| IslamicYearInfo::compute::<IB>(extended_year)) Unexecuted instantiation: <icu_calendar::islamic::IslamicPrecomputedData<calendrical_calculations::islamic::SaudiIslamicMarker> as icu_calendar::calendar_arithmetic::PrecomputedDataSource<icu_calendar::islamic::IslamicYearInfo>>::load_or_compute_info::{closure#1} Unexecuted instantiation: <icu_calendar::islamic::IslamicPrecomputedData<calendrical_calculations::islamic::ObservationalIslamicMarker> as icu_calendar::calendar_arithmetic::PrecomputedDataSource<icu_calendar::islamic::IslamicYearInfo>>::load_or_compute_info::{closure#1} |
343 | 0 | } Unexecuted instantiation: <icu_calendar::islamic::IslamicPrecomputedData<calendrical_calculations::islamic::SaudiIslamicMarker> as icu_calendar::calendar_arithmetic::PrecomputedDataSource<icu_calendar::islamic::IslamicYearInfo>>::load_or_compute_info Unexecuted instantiation: <icu_calendar::islamic::IslamicPrecomputedData<calendrical_calculations::islamic::ObservationalIslamicMarker> as icu_calendar::calendar_arithmetic::PrecomputedDataSource<icu_calendar::islamic::IslamicYearInfo>>::load_or_compute_info |
344 | | } |
345 | | |
346 | | /// Given a year info and the first month it is possible for this date to be in, return the |
347 | | /// month and day this is in |
348 | 0 | fn compute_month_day(info: IslamicYearInfo, mut possible_month: u8, day_of_year: u16) -> (u8, u8) { |
349 | 0 | let mut last_day_of_month = info.packed_data.last_day_of_month(possible_month); |
350 | 0 | let mut last_day_of_prev_month = if possible_month == 1 { |
351 | 0 | 0 |
352 | | } else { |
353 | 0 | info.packed_data.last_day_of_month(possible_month - 1) |
354 | | }; |
355 | | |
356 | 0 | while day_of_year > last_day_of_month && possible_month <= 12 { |
357 | 0 | possible_month += 1; |
358 | 0 | last_day_of_prev_month = last_day_of_month; |
359 | 0 | last_day_of_month = info.packed_data.last_day_of_month(possible_month); |
360 | 0 | } |
361 | 0 | let day = u8::try_from(day_of_year - last_day_of_prev_month); |
362 | 0 | debug_assert!( |
363 | 0 | day.is_ok(), |
364 | 0 | "Found day {} that doesn't fit in month!", |
365 | 0 | day_of_year - last_day_of_prev_month |
366 | | ); |
367 | 0 | (possible_month, day.unwrap_or(29)) |
368 | 0 | } |
369 | | impl<'b, IB: IslamicBasedMarker> IslamicPrecomputedData<'b, IB> { |
370 | 0 | pub(crate) fn new(data: Option<&'b IslamicCacheV1<'b>>) -> Self { |
371 | 0 | Self { |
372 | 0 | data, |
373 | 0 | _ib: PhantomData, |
374 | 0 | } |
375 | 0 | } Unexecuted instantiation: <icu_calendar::islamic::IslamicPrecomputedData<calendrical_calculations::islamic::SaudiIslamicMarker>>::new Unexecuted instantiation: <icu_calendar::islamic::IslamicPrecomputedData<calendrical_calculations::islamic::ObservationalIslamicMarker>>::new |
376 | | /// Given an ISO date (in both ArithmeticDate and R.D. format), returns the IslamicYearInfo and extended year for that date, loading |
377 | | /// from cache or computing. |
378 | 0 | fn load_or_compute_info_for_iso(&self, fixed: RataDie) -> (IslamicYearInfo, i32, u8, u8) { |
379 | 0 | let cached = self.data.and_then(|d| d.get_for_fixed::<IB>(fixed)); Unexecuted instantiation: <icu_calendar::islamic::IslamicPrecomputedData<calendrical_calculations::islamic::SaudiIslamicMarker>>::load_or_compute_info_for_iso::{closure#0} Unexecuted instantiation: <icu_calendar::islamic::IslamicPrecomputedData<calendrical_calculations::islamic::ObservationalIslamicMarker>>::load_or_compute_info_for_iso::{closure#0} |
380 | 0 | if let Some((cached, year)) = cached { |
381 | 0 | let ny = cached.packed_data.ny::<IB>(year); |
382 | 0 | let day_of_year = (fixed - ny) as u16 + 1; |
383 | 0 | debug_assert!(day_of_year < 360); |
384 | | // We divide by 30, not 29, to account for the case where all months before this |
385 | | // were length 30 (possible near the beginning of the year) |
386 | | // We add +1 because months are 1-indexed |
387 | 0 | let possible_month = u8::try_from(1 + (day_of_year / 30)).unwrap_or(1); |
388 | 0 | let (m, d) = compute_month_day(cached, possible_month, day_of_year); |
389 | 0 | return (cached, year, m, d); |
390 | 0 | }; |
391 | | // compute |
392 | | |
393 | 0 | let (y, m, d) = IB::islamic_from_fixed(fixed); |
394 | 0 | let info = IslamicYearInfo::compute::<IB>(y); |
395 | 0 | let ny = info.packed_data.ny::<IB>(y); |
396 | 0 | let day_of_year = (fixed - ny) as u16 + 1; |
397 | | // We can't use the m/d from islamic_from_fixed because that code |
398 | | // occasionally throws up 31-day months, which we normalize out. So we instead back-compute, starting with the previous month |
399 | 0 | let (m, d) = if m > 1 { |
400 | 0 | compute_month_day(info, m - 1, day_of_year) |
401 | | } else { |
402 | 0 | (m, d) |
403 | | }; |
404 | 0 | (info, y, m, d) |
405 | 0 | } Unexecuted instantiation: <icu_calendar::islamic::IslamicPrecomputedData<calendrical_calculations::islamic::SaudiIslamicMarker>>::load_or_compute_info_for_iso Unexecuted instantiation: <icu_calendar::islamic::IslamicPrecomputedData<calendrical_calculations::islamic::ObservationalIslamicMarker>>::load_or_compute_info_for_iso |
406 | | } |
407 | | |
408 | | /// The inner date type used for representing [`Date`]s of [`IslamicObservational`]. See [`Date`] and [`IslamicObservational`] for more details. |
409 | | |
410 | | #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)] |
411 | | pub struct IslamicDateInner(ArithmeticDate<IslamicObservational>); |
412 | | |
413 | | impl CalendarArithmetic for IslamicObservational { |
414 | | type YearInfo = IslamicYearInfo; |
415 | | |
416 | 0 | fn month_days(_year: i32, month: u8, year_info: IslamicYearInfo) -> u8 { |
417 | 0 | year_info.packed_data.days_in_month(month) |
418 | 0 | } |
419 | | |
420 | 0 | fn months_for_every_year(_year: i32, _year_info: IslamicYearInfo) -> u8 { |
421 | 0 | 12 |
422 | 0 | } |
423 | | |
424 | 0 | fn days_in_provided_year(_year: i32, year_info: IslamicYearInfo) -> u16 { |
425 | 0 | year_info.packed_data.days_in_year() |
426 | 0 | } |
427 | | |
428 | | // As an true lunar calendar, it does not have leap years. |
429 | 0 | fn is_leap_year(_year: i32, year_info: IslamicYearInfo) -> bool { |
430 | 0 | year_info.packed_data.days_in_year() != IslamicYearInfo::SHORT_YEAR_LEN |
431 | 0 | } |
432 | | |
433 | 0 | fn last_month_day_in_year(year: i32, year_info: IslamicYearInfo) -> (u8, u8) { |
434 | 0 | let days = Self::month_days(year, 12, year_info); |
435 | | |
436 | 0 | (12, days) |
437 | 0 | } |
438 | | } |
439 | | |
440 | | impl Calendar for IslamicObservational { |
441 | | type DateInner = IslamicDateInner; |
442 | 0 | fn date_from_codes( |
443 | 0 | &self, |
444 | 0 | era: types::Era, |
445 | 0 | year: i32, |
446 | 0 | month_code: types::MonthCode, |
447 | 0 | day: u8, |
448 | 0 | ) -> Result<Self::DateInner, CalendarError> { |
449 | 0 | let year = if era.0 == tinystr!(16, "islamic") || era.0 == tinystr!(16, "ah") { |
450 | 0 | year |
451 | | } else { |
452 | 0 | return Err(CalendarError::UnknownEra(era.0, self.debug_name())); |
453 | | }; |
454 | 0 | let month = if let Some((ordinal, false)) = month_code.parsed() { |
455 | 0 | ordinal |
456 | | } else { |
457 | 0 | return Err(CalendarError::UnknownMonthCode( |
458 | 0 | month_code.0, |
459 | 0 | self.debug_name(), |
460 | 0 | )); |
461 | | }; |
462 | 0 | ArithmeticDate::new_from_ordinals_with_info( |
463 | 0 | year, |
464 | 0 | month, |
465 | 0 | day, |
466 | 0 | self.precomputed_data().load_or_compute_info(year), |
467 | | ) |
468 | 0 | .map(IslamicDateInner) |
469 | 0 | } |
470 | | |
471 | 0 | fn date_from_iso(&self, iso: Date<crate::Iso>) -> Self::DateInner { |
472 | 0 | let fixed_iso = Iso::fixed_from_iso(*iso.inner()); |
473 | | |
474 | 0 | let (year_info, y, m, d) = self |
475 | 0 | .precomputed_data() |
476 | 0 | .load_or_compute_info_for_iso(fixed_iso); |
477 | 0 | IslamicDateInner(ArithmeticDate::new_unchecked_with_info(y, m, d, year_info)) |
478 | 0 | } |
479 | | |
480 | 0 | fn date_to_iso(&self, date: &Self::DateInner) -> Date<crate::Iso> { |
481 | 0 | let fixed = date.0.year_info.rd_for::<ObservationalIslamicMarker>( |
482 | 0 | date.0.year, |
483 | 0 | date.0.month, |
484 | 0 | date.0.day, |
485 | | ); |
486 | 0 | Iso::iso_from_fixed(fixed) |
487 | 0 | } |
488 | | |
489 | 0 | fn months_in_year(&self, date: &Self::DateInner) -> u8 { |
490 | 0 | date.0.months_in_year() |
491 | 0 | } |
492 | | |
493 | 0 | fn days_in_year(&self, date: &Self::DateInner) -> u16 { |
494 | 0 | date.0.days_in_year() |
495 | 0 | } |
496 | | |
497 | 0 | fn days_in_month(&self, date: &Self::DateInner) -> u8 { |
498 | 0 | date.0.days_in_month() |
499 | 0 | } |
500 | | |
501 | 0 | fn day_of_week(&self, date: &Self::DateInner) -> types::IsoWeekday { |
502 | 0 | Iso.day_of_week(self.date_to_iso(date).inner()) |
503 | 0 | } |
504 | | |
505 | 0 | fn offset_date(&self, date: &mut Self::DateInner, offset: DateDuration<Self>) { |
506 | 0 | date.0.offset_date(offset, &self.precomputed_data()) |
507 | 0 | } |
508 | | |
509 | 0 | fn until( |
510 | 0 | &self, |
511 | 0 | date1: &Self::DateInner, |
512 | 0 | date2: &Self::DateInner, |
513 | 0 | _calendar2: &Self, |
514 | 0 | _largest_unit: DateDurationUnit, |
515 | 0 | _smallest_unit: DateDurationUnit, |
516 | 0 | ) -> DateDuration<Self> { |
517 | 0 | date1.0.until(date2.0, _largest_unit, _smallest_unit) |
518 | 0 | } |
519 | | |
520 | 0 | fn debug_name(&self) -> &'static str { |
521 | 0 | Self::DEBUG_NAME |
522 | 0 | } |
523 | | |
524 | 0 | fn year(&self, date: &Self::DateInner) -> types::FormattableYear { |
525 | 0 | Self::year_as_islamic(date.0.year) |
526 | 0 | } |
527 | | |
528 | 0 | fn is_in_leap_year(&self, date: &Self::DateInner) -> bool { |
529 | 0 | Self::is_leap_year(date.0.year, date.0.year_info) |
530 | 0 | } |
531 | | |
532 | 0 | fn month(&self, date: &Self::DateInner) -> types::FormattableMonth { |
533 | 0 | date.0.month() |
534 | 0 | } |
535 | | |
536 | 0 | fn day_of_month(&self, date: &Self::DateInner) -> types::DayOfMonth { |
537 | 0 | date.0.day_of_month() |
538 | 0 | } |
539 | | |
540 | 0 | fn day_of_year_info(&self, date: &Self::DateInner) -> types::DayOfYearInfo { |
541 | 0 | let prev_year = date.0.year.saturating_sub(1); |
542 | 0 | let next_year = date.0.year.saturating_add(1); |
543 | 0 | types::DayOfYearInfo { |
544 | 0 | day_of_year: date.0.day_of_year(), |
545 | 0 | days_in_year: date.0.days_in_year(), |
546 | 0 | prev_year: Self::year_as_islamic(prev_year), |
547 | 0 | days_in_prev_year: date.0.year_info.days_in_prev_year(), |
548 | 0 | next_year: Self::year_as_islamic(next_year), |
549 | 0 | } |
550 | 0 | } |
551 | | |
552 | 0 | fn any_calendar_kind(&self) -> Option<AnyCalendarKind> { |
553 | 0 | Some(AnyCalendarKind::IslamicObservational) |
554 | 0 | } |
555 | | } |
556 | | |
557 | | impl IslamicObservational { |
558 | 0 | fn precomputed_data(&self) -> IslamicPrecomputedData<ObservationalIslamicMarker> { |
559 | 0 | IslamicPrecomputedData::new(self.data.as_ref().map(|x| x.get())) |
560 | 0 | } |
561 | | |
562 | 0 | fn year_as_islamic(year: i32) -> types::FormattableYear { |
563 | 0 | types::FormattableYear { |
564 | 0 | era: types::Era(tinystr!(16, "islamic")), |
565 | 0 | number: year, |
566 | 0 | cyclic: None, |
567 | 0 | related_iso: None, |
568 | 0 | } |
569 | 0 | } |
570 | | pub(crate) const DEBUG_NAME: &'static str = "Islamic (observational)"; |
571 | | } |
572 | | |
573 | | impl<A: AsCalendar<Calendar = IslamicObservational>> Date<A> { |
574 | | /// Construct new Islamic Observational Date. |
575 | | /// |
576 | | /// Has no negative years, only era is the AH. |
577 | | /// |
578 | | /// ```rust |
579 | | /// use icu::calendar::islamic::IslamicObservational; |
580 | | /// use icu::calendar::Date; |
581 | | /// |
582 | | /// let islamic = IslamicObservational::new_always_calculating(); |
583 | | /// |
584 | | /// let date_islamic = |
585 | | /// Date::try_new_observational_islamic_date(1392, 4, 25, islamic) |
586 | | /// .expect("Failed to initialize Islamic Date instance."); |
587 | | /// |
588 | | /// assert_eq!(date_islamic.year().number, 1392); |
589 | | /// assert_eq!(date_islamic.month().ordinal, 4); |
590 | | /// assert_eq!(date_islamic.day_of_month().0, 25); |
591 | | /// ``` |
592 | 0 | pub fn try_new_observational_islamic_date( |
593 | 0 | year: i32, |
594 | 0 | month: u8, |
595 | 0 | day: u8, |
596 | 0 | calendar: A, |
597 | 0 | ) -> Result<Date<A>, CalendarError> { |
598 | 0 | let year_info = calendar |
599 | 0 | .as_calendar() |
600 | 0 | .precomputed_data() |
601 | 0 | .load_or_compute_info(year); |
602 | 0 | ArithmeticDate::new_from_ordinals_with_info(year, month, day, year_info) |
603 | 0 | .map(IslamicDateInner) |
604 | 0 | .map(|inner| Date::from_raw(inner, calendar)) |
605 | 0 | } |
606 | | } |
607 | | |
608 | | impl<A: AsCalendar<Calendar = IslamicObservational>> DateTime<A> { |
609 | | /// Construct a new Islamic Observational datetime from integers. |
610 | | /// |
611 | | /// ```rust |
612 | | /// use icu::calendar::islamic::IslamicObservational; |
613 | | /// use icu::calendar::DateTime; |
614 | | /// |
615 | | /// let islamic = IslamicObservational::new_always_calculating(); |
616 | | /// |
617 | | /// let datetime_islamic = DateTime::try_new_observational_islamic_datetime( |
618 | | /// 474, 10, 11, 13, 1, 0, islamic, |
619 | | /// ) |
620 | | /// .expect("Failed to initialize Islamic DateTime instance."); |
621 | | /// |
622 | | /// assert_eq!(datetime_islamic.date.year().number, 474); |
623 | | /// assert_eq!(datetime_islamic.date.month().ordinal, 10); |
624 | | /// assert_eq!(datetime_islamic.date.day_of_month().0, 11); |
625 | | /// assert_eq!(datetime_islamic.time.hour.number(), 13); |
626 | | /// assert_eq!(datetime_islamic.time.minute.number(), 1); |
627 | | /// assert_eq!(datetime_islamic.time.second.number(), 0); |
628 | | /// ``` |
629 | 0 | pub fn try_new_observational_islamic_datetime( |
630 | 0 | year: i32, |
631 | 0 | month: u8, |
632 | 0 | day: u8, |
633 | 0 | hour: u8, |
634 | 0 | minute: u8, |
635 | 0 | second: u8, |
636 | 0 | calendar: A, |
637 | 0 | ) -> Result<DateTime<A>, CalendarError> { |
638 | | Ok(DateTime { |
639 | 0 | date: Date::try_new_observational_islamic_date(year, month, day, calendar)?, |
640 | 0 | time: Time::try_new(hour, minute, second, 0)?, |
641 | | }) |
642 | 0 | } |
643 | | } |
644 | | |
645 | | #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)] |
646 | | /// The inner date type used for representing [`Date`]s of [`IslamicUmmAlQura`]. See [`Date`] and [`IslamicUmmAlQura`] for more details. |
647 | | pub struct IslamicUmmAlQuraDateInner(ArithmeticDate<IslamicUmmAlQura>); |
648 | | |
649 | | impl CalendarArithmetic for IslamicUmmAlQura { |
650 | | type YearInfo = IslamicYearInfo; |
651 | | |
652 | 0 | fn month_days(_year: i32, month: u8, year_info: IslamicYearInfo) -> u8 { |
653 | 0 | year_info.packed_data.days_in_month(month) |
654 | 0 | } |
655 | | |
656 | 0 | fn months_for_every_year(_year: i32, _year_info: IslamicYearInfo) -> u8 { |
657 | 0 | 12 |
658 | 0 | } |
659 | | |
660 | 0 | fn days_in_provided_year(_year: i32, year_info: IslamicYearInfo) -> u16 { |
661 | 0 | year_info.packed_data.days_in_year() |
662 | 0 | } |
663 | | |
664 | | // As an true lunar calendar, it does not have leap years. |
665 | 0 | fn is_leap_year(_year: i32, year_info: IslamicYearInfo) -> bool { |
666 | 0 | year_info.packed_data.days_in_year() != IslamicYearInfo::SHORT_YEAR_LEN |
667 | 0 | } |
668 | | |
669 | 0 | fn last_month_day_in_year(year: i32, year_info: IslamicYearInfo) -> (u8, u8) { |
670 | 0 | let days = Self::month_days(year, 12, year_info); |
671 | | |
672 | 0 | (12, days) |
673 | 0 | } |
674 | | } |
675 | | |
676 | | impl Calendar for IslamicUmmAlQura { |
677 | | type DateInner = IslamicUmmAlQuraDateInner; |
678 | 0 | fn date_from_codes( |
679 | 0 | &self, |
680 | 0 | era: types::Era, |
681 | 0 | year: i32, |
682 | 0 | month_code: types::MonthCode, |
683 | 0 | day: u8, |
684 | 0 | ) -> Result<Self::DateInner, CalendarError> { |
685 | 0 | let year = if era.0 == tinystr!(16, "islamic-umalqura") |
686 | 0 | || era.0 == tinystr!(16, "islamic") |
687 | 0 | || era.0 == tinystr!(16, "ah") |
688 | | { |
689 | 0 | year |
690 | | } else { |
691 | 0 | return Err(CalendarError::UnknownEra(era.0, self.debug_name())); |
692 | | }; |
693 | | |
694 | 0 | let month = if let Some((ordinal, false)) = month_code.parsed() { |
695 | 0 | ordinal |
696 | | } else { |
697 | 0 | return Err(CalendarError::UnknownMonthCode( |
698 | 0 | month_code.0, |
699 | 0 | self.debug_name(), |
700 | 0 | )); |
701 | | }; |
702 | 0 | ArithmeticDate::new_from_ordinals_with_info( |
703 | 0 | year, |
704 | 0 | month, |
705 | 0 | day, |
706 | 0 | self.precomputed_data().load_or_compute_info(year), |
707 | | ) |
708 | 0 | .map(IslamicUmmAlQuraDateInner) |
709 | 0 | } |
710 | | |
711 | 0 | fn date_from_iso(&self, iso: Date<Iso>) -> Self::DateInner { |
712 | 0 | let fixed_iso = Iso::fixed_from_iso(*iso.inner()); |
713 | | |
714 | 0 | let (year_info, y, m, d) = self |
715 | 0 | .precomputed_data() |
716 | 0 | .load_or_compute_info_for_iso(fixed_iso); |
717 | 0 | IslamicUmmAlQuraDateInner(ArithmeticDate::new_unchecked_with_info(y, m, d, year_info)) |
718 | 0 | } |
719 | | |
720 | 0 | fn date_to_iso(&self, date: &Self::DateInner) -> Date<Iso> { |
721 | 0 | let fixed = |
722 | 0 | date.0 |
723 | 0 | .year_info |
724 | 0 | .rd_for::<SaudiIslamicMarker>(date.0.year, date.0.month, date.0.day); |
725 | 0 | Iso::iso_from_fixed(fixed) |
726 | 0 | } |
727 | | |
728 | 0 | fn months_in_year(&self, date: &Self::DateInner) -> u8 { |
729 | 0 | date.0.months_in_year() |
730 | 0 | } |
731 | | |
732 | 0 | fn days_in_year(&self, date: &Self::DateInner) -> u16 { |
733 | 0 | date.0.days_in_year() |
734 | 0 | } |
735 | | |
736 | 0 | fn days_in_month(&self, date: &Self::DateInner) -> u8 { |
737 | 0 | date.0.days_in_month() |
738 | 0 | } |
739 | | |
740 | 0 | fn offset_date(&self, date: &mut Self::DateInner, offset: DateDuration<Self>) { |
741 | 0 | date.0.offset_date(offset, &self.precomputed_data()) |
742 | 0 | } |
743 | | |
744 | 0 | fn until( |
745 | 0 | &self, |
746 | 0 | date1: &Self::DateInner, |
747 | 0 | date2: &Self::DateInner, |
748 | 0 | _calendar2: &Self, |
749 | 0 | _largest_unit: DateDurationUnit, |
750 | 0 | _smallest_unit: DateDurationUnit, |
751 | 0 | ) -> DateDuration<Self> { |
752 | 0 | date1.0.until(date2.0, _largest_unit, _smallest_unit) |
753 | 0 | } |
754 | | |
755 | 0 | fn debug_name(&self) -> &'static str { |
756 | 0 | Self::DEBUG_NAME |
757 | 0 | } |
758 | | |
759 | 0 | fn year(&self, date: &Self::DateInner) -> types::FormattableYear { |
760 | 0 | Self::year_as_islamic(date.0.year) |
761 | 0 | } |
762 | | |
763 | 0 | fn is_in_leap_year(&self, date: &Self::DateInner) -> bool { |
764 | 0 | Self::is_leap_year(date.0.year, date.0.year_info) |
765 | 0 | } |
766 | | |
767 | 0 | fn month(&self, date: &Self::DateInner) -> types::FormattableMonth { |
768 | 0 | date.0.month() |
769 | 0 | } |
770 | | |
771 | 0 | fn day_of_month(&self, date: &Self::DateInner) -> types::DayOfMonth { |
772 | 0 | date.0.day_of_month() |
773 | 0 | } |
774 | | |
775 | 0 | fn day_of_year_info(&self, date: &Self::DateInner) -> types::DayOfYearInfo { |
776 | 0 | let prev_year = date.0.year.saturating_sub(1); |
777 | 0 | let next_year = date.0.year.saturating_add(1); |
778 | 0 | types::DayOfYearInfo { |
779 | 0 | day_of_year: date.0.day_of_year(), |
780 | 0 | days_in_year: date.0.days_in_year(), |
781 | 0 | prev_year: Self::year_as_islamic(prev_year), |
782 | 0 | days_in_prev_year: date.0.year_info.days_in_prev_year(), |
783 | 0 | next_year: Self::year_as_islamic(next_year), |
784 | 0 | } |
785 | 0 | } |
786 | | |
787 | 0 | fn any_calendar_kind(&self) -> Option<AnyCalendarKind> { |
788 | 0 | Some(AnyCalendarKind::IslamicUmmAlQura) |
789 | 0 | } |
790 | | } |
791 | | |
792 | | impl IslamicUmmAlQura { |
793 | 0 | fn precomputed_data(&self) -> IslamicPrecomputedData<SaudiIslamicMarker> { |
794 | 0 | IslamicPrecomputedData::new(self.data.as_ref().map(|x| x.get())) |
795 | 0 | } |
796 | | |
797 | 0 | fn year_as_islamic(year: i32) -> types::FormattableYear { |
798 | 0 | types::FormattableYear { |
799 | 0 | era: types::Era(tinystr!(16, "islamic")), |
800 | 0 | number: year, |
801 | 0 | cyclic: None, |
802 | 0 | related_iso: None, |
803 | 0 | } |
804 | 0 | } |
805 | | pub(crate) const DEBUG_NAME: &'static str = "Islamic (Umm al-Qura)"; |
806 | | } |
807 | | |
808 | | impl<A: AsCalendar<Calendar = IslamicUmmAlQura>> Date<A> { |
809 | | /// Construct new Islamic Umm al-Qura Date. |
810 | | /// |
811 | | /// Has no negative years, only era is the AH. |
812 | | /// |
813 | | /// ```rust |
814 | | /// use icu::calendar::islamic::IslamicUmmAlQura; |
815 | | /// use icu::calendar::Date; |
816 | | /// |
817 | | /// let islamic = IslamicUmmAlQura::new_always_calculating(); |
818 | | /// |
819 | | /// let date_islamic = Date::try_new_ummalqura_date(1392, 4, 25, islamic) |
820 | | /// .expect("Failed to initialize Islamic Date instance."); |
821 | | /// |
822 | | /// assert_eq!(date_islamic.year().number, 1392); |
823 | | /// assert_eq!(date_islamic.month().ordinal, 4); |
824 | | /// assert_eq!(date_islamic.day_of_month().0, 25); |
825 | | /// ``` |
826 | 0 | pub fn try_new_ummalqura_date( |
827 | 0 | year: i32, |
828 | 0 | month: u8, |
829 | 0 | day: u8, |
830 | 0 | calendar: A, |
831 | 0 | ) -> Result<Date<A>, CalendarError> { |
832 | 0 | let year_info = calendar |
833 | 0 | .as_calendar() |
834 | 0 | .precomputed_data() |
835 | 0 | .load_or_compute_info(year); |
836 | 0 | ArithmeticDate::new_from_ordinals_with_info(year, month, day, year_info) |
837 | 0 | .map(IslamicUmmAlQuraDateInner) |
838 | 0 | .map(|inner| Date::from_raw(inner, calendar)) |
839 | 0 | } |
840 | | } |
841 | | |
842 | | impl<A: AsCalendar<Calendar = IslamicUmmAlQura>> DateTime<A> { |
843 | | /// Construct a new Islamic Umm al-Qura datetime from integers. |
844 | | /// |
845 | | /// ```rust |
846 | | /// use icu::calendar::islamic::IslamicUmmAlQura; |
847 | | /// use icu::calendar::DateTime; |
848 | | /// |
849 | | /// let islamic = IslamicUmmAlQura::new_always_calculating(); |
850 | | /// |
851 | | /// let datetime_islamic = |
852 | | /// DateTime::try_new_ummalqura_datetime(474, 10, 11, 13, 1, 0, islamic) |
853 | | /// .expect("Failed to initialize Islamic DateTime instance."); |
854 | | /// |
855 | | /// assert_eq!(datetime_islamic.date.year().number, 474); |
856 | | /// assert_eq!(datetime_islamic.date.month().ordinal, 10); |
857 | | /// assert_eq!(datetime_islamic.date.day_of_month().0, 11); |
858 | | /// assert_eq!(datetime_islamic.time.hour.number(), 13); |
859 | | /// assert_eq!(datetime_islamic.time.minute.number(), 1); |
860 | | /// assert_eq!(datetime_islamic.time.second.number(), 0); |
861 | | /// ``` |
862 | 0 | pub fn try_new_ummalqura_datetime( |
863 | 0 | year: i32, |
864 | 0 | month: u8, |
865 | 0 | day: u8, |
866 | 0 | hour: u8, |
867 | 0 | minute: u8, |
868 | 0 | second: u8, |
869 | 0 | calendar: A, |
870 | 0 | ) -> Result<DateTime<A>, CalendarError> { |
871 | | Ok(DateTime { |
872 | 0 | date: Date::try_new_ummalqura_date(year, month, day, calendar)?, |
873 | 0 | time: Time::try_new(hour, minute, second, 0)?, |
874 | | }) |
875 | 0 | } |
876 | | } |
877 | | |
878 | | /// The inner date type used for representing [`Date`]s of [`IslamicCivil`]. See [`Date`] and [`IslamicCivil`] for more details. |
879 | | |
880 | | #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)] |
881 | | pub struct IslamicCivilDateInner(ArithmeticDate<IslamicCivil>); |
882 | | |
883 | | impl CalendarArithmetic for IslamicCivil { |
884 | | type YearInfo = (); |
885 | | |
886 | 0 | fn month_days(year: i32, month: u8, _data: ()) -> u8 { |
887 | 0 | match month { |
888 | 0 | 1 | 3 | 5 | 7 | 9 | 11 => 30, |
889 | 0 | 2 | 4 | 6 | 8 | 10 => 29, |
890 | 0 | 12 if Self::is_leap_year(year, ()) => 30, |
891 | 0 | 12 => 29, |
892 | 0 | _ => 0, |
893 | | } |
894 | 0 | } |
895 | | |
896 | 0 | fn months_for_every_year(_year: i32, _data: ()) -> u8 { |
897 | 0 | 12 |
898 | 0 | } |
899 | | |
900 | 0 | fn days_in_provided_year(year: i32, _data: ()) -> u16 { |
901 | 0 | if Self::is_leap_year(year, ()) { |
902 | 0 | IslamicYearInfo::LONG_YEAR_LEN |
903 | | } else { |
904 | 0 | IslamicYearInfo::SHORT_YEAR_LEN |
905 | | } |
906 | 0 | } |
907 | | |
908 | 0 | fn is_leap_year(year: i32, _data: ()) -> bool { |
909 | 0 | (14 + 11 * year).rem_euclid(30) < 11 |
910 | 0 | } |
911 | | |
912 | 0 | fn last_month_day_in_year(year: i32, _data: ()) -> (u8, u8) { |
913 | 0 | if Self::is_leap_year(year, ()) { |
914 | 0 | (12, 30) |
915 | | } else { |
916 | 0 | (12, 29) |
917 | | } |
918 | 0 | } |
919 | | } |
920 | | |
921 | | impl Calendar for IslamicCivil { |
922 | | type DateInner = IslamicCivilDateInner; |
923 | | |
924 | 0 | fn date_from_codes( |
925 | 0 | &self, |
926 | 0 | era: types::Era, |
927 | 0 | year: i32, |
928 | 0 | month_code: types::MonthCode, |
929 | 0 | day: u8, |
930 | 0 | ) -> Result<Self::DateInner, CalendarError> { |
931 | 0 | let year = if era.0 == tinystr!(16, "islamic-civil") |
932 | 0 | || era.0 == tinystr!(16, "islamicc") |
933 | 0 | || era.0 == tinystr!(16, "islamic") |
934 | 0 | || era.0 == tinystr!(16, "ah") |
935 | | { |
936 | | // TODO: Check name and alias |
937 | 0 | year |
938 | | } else { |
939 | 0 | return Err(CalendarError::UnknownEra(era.0, self.debug_name())); |
940 | | }; |
941 | | |
942 | 0 | ArithmeticDate::new_from_codes(self, year, month_code, day).map(IslamicCivilDateInner) |
943 | 0 | } |
944 | | |
945 | 0 | fn date_from_iso(&self, iso: Date<Iso>) -> Self::DateInner { |
946 | 0 | let fixed_iso = Iso::fixed_from_iso(*iso.inner()); |
947 | 0 | Self::islamic_from_fixed(fixed_iso).inner |
948 | 0 | } |
949 | | |
950 | 0 | fn date_to_iso(&self, date: &Self::DateInner) -> Date<Iso> { |
951 | 0 | let fixed_islamic = Self::fixed_from_islamic(*date); |
952 | 0 | Iso::iso_from_fixed(fixed_islamic) |
953 | 0 | } |
954 | | |
955 | 0 | fn months_in_year(&self, date: &Self::DateInner) -> u8 { |
956 | 0 | date.0.months_in_year() |
957 | 0 | } |
958 | | |
959 | 0 | fn days_in_year(&self, date: &Self::DateInner) -> u16 { |
960 | 0 | date.0.days_in_year() |
961 | 0 | } |
962 | | |
963 | 0 | fn days_in_month(&self, date: &Self::DateInner) -> u8 { |
964 | 0 | date.0.days_in_month() |
965 | 0 | } |
966 | | |
967 | 0 | fn day_of_week(&self, date: &Self::DateInner) -> types::IsoWeekday { |
968 | 0 | Iso.day_of_week(self.date_to_iso(date).inner()) |
969 | 0 | } |
970 | | |
971 | 0 | fn offset_date(&self, date: &mut Self::DateInner, offset: DateDuration<Self>) { |
972 | 0 | date.0.offset_date(offset, &()) |
973 | 0 | } |
974 | | |
975 | 0 | fn until( |
976 | 0 | &self, |
977 | 0 | date1: &Self::DateInner, |
978 | 0 | date2: &Self::DateInner, |
979 | 0 | _calendar2: &Self, |
980 | 0 | _largest_unit: DateDurationUnit, |
981 | 0 | _smallest_unit: DateDurationUnit, |
982 | 0 | ) -> DateDuration<Self> { |
983 | 0 | date1.0.until(date2.0, _largest_unit, _smallest_unit) |
984 | 0 | } |
985 | | |
986 | 0 | fn debug_name(&self) -> &'static str { |
987 | 0 | "Islamic (civil)" |
988 | 0 | } |
989 | | |
990 | 0 | fn year(&self, date: &Self::DateInner) -> types::FormattableYear { |
991 | 0 | Self::year_as_islamic(date.0.year) |
992 | 0 | } |
993 | | |
994 | 0 | fn is_in_leap_year(&self, date: &Self::DateInner) -> bool { |
995 | 0 | Self::is_leap_year(date.0.year, ()) |
996 | 0 | } |
997 | | |
998 | 0 | fn month(&self, date: &Self::DateInner) -> types::FormattableMonth { |
999 | 0 | date.0.month() |
1000 | 0 | } |
1001 | | |
1002 | 0 | fn day_of_month(&self, date: &Self::DateInner) -> types::DayOfMonth { |
1003 | 0 | date.0.day_of_month() |
1004 | 0 | } |
1005 | | |
1006 | 0 | fn day_of_year_info(&self, date: &Self::DateInner) -> types::DayOfYearInfo { |
1007 | 0 | let prev_year = date.0.year.saturating_sub(1); |
1008 | 0 | let next_year = date.0.year.saturating_add(1); |
1009 | 0 | types::DayOfYearInfo { |
1010 | 0 | day_of_year: date.0.day_of_year(), |
1011 | 0 | days_in_year: date.0.days_in_year(), |
1012 | 0 | prev_year: Self::year_as_islamic(prev_year), |
1013 | 0 | days_in_prev_year: Self::days_in_provided_year(prev_year, ()), |
1014 | 0 | next_year: Self::year_as_islamic(next_year), |
1015 | 0 | } |
1016 | 0 | } |
1017 | 0 | fn any_calendar_kind(&self) -> Option<AnyCalendarKind> { |
1018 | 0 | Some(AnyCalendarKind::IslamicCivil) |
1019 | 0 | } |
1020 | | } |
1021 | | |
1022 | | impl IslamicCivil { |
1023 | 0 | fn fixed_from_islamic(i_date: IslamicCivilDateInner) -> RataDie { |
1024 | 0 | calendrical_calculations::islamic::fixed_from_islamic_civil( |
1025 | 0 | i_date.0.year, |
1026 | 0 | i_date.0.month, |
1027 | 0 | i_date.0.day, |
1028 | | ) |
1029 | 0 | } |
1030 | | |
1031 | 0 | fn islamic_from_fixed(date: RataDie) -> Date<IslamicCivil> { |
1032 | 0 | let (y, m, d) = calendrical_calculations::islamic::islamic_civil_from_fixed(date); |
1033 | | |
1034 | 0 | debug_assert!( |
1035 | 0 | Date::try_new_islamic_civil_date_with_calendar(y, m, d, IslamicCivil).is_ok() |
1036 | | ); |
1037 | 0 | Date::from_raw( |
1038 | 0 | IslamicCivilDateInner(ArithmeticDate::new_unchecked(y, m, d)), |
1039 | 0 | IslamicCivil, |
1040 | | ) |
1041 | 0 | } |
1042 | | |
1043 | 0 | fn year_as_islamic(year: i32) -> types::FormattableYear { |
1044 | 0 | types::FormattableYear { |
1045 | 0 | era: types::Era(tinystr!(16, "islamic")), |
1046 | 0 | number: year, |
1047 | 0 | cyclic: None, |
1048 | 0 | related_iso: None, |
1049 | 0 | } |
1050 | 0 | } |
1051 | | } |
1052 | | |
1053 | | impl<A: AsCalendar<Calendar = IslamicCivil>> Date<A> { |
1054 | | /// Construct new Civil Islamic Date. |
1055 | | /// |
1056 | | /// Has no negative years, only era is the AH. |
1057 | | /// |
1058 | | /// ```rust |
1059 | | /// use icu::calendar::islamic::IslamicCivil; |
1060 | | /// use icu::calendar::Date; |
1061 | | /// |
1062 | | /// let islamic = IslamicCivil::new_always_calculating(); |
1063 | | /// |
1064 | | /// let date_islamic = |
1065 | | /// Date::try_new_islamic_civil_date_with_calendar(1392, 4, 25, islamic) |
1066 | | /// .expect("Failed to initialize Islamic Date instance."); |
1067 | | /// |
1068 | | /// assert_eq!(date_islamic.year().number, 1392); |
1069 | | /// assert_eq!(date_islamic.month().ordinal, 4); |
1070 | | /// assert_eq!(date_islamic.day_of_month().0, 25); |
1071 | | /// ``` |
1072 | 0 | pub fn try_new_islamic_civil_date_with_calendar( |
1073 | 0 | year: i32, |
1074 | 0 | month: u8, |
1075 | 0 | day: u8, |
1076 | 0 | calendar: A, |
1077 | 0 | ) -> Result<Date<A>, CalendarError> { |
1078 | 0 | ArithmeticDate::new_from_ordinals(year, month, day) |
1079 | 0 | .map(IslamicCivilDateInner) |
1080 | 0 | .map(|inner| Date::from_raw(inner, calendar)) |
1081 | 0 | } |
1082 | | } |
1083 | | |
1084 | | impl<A: AsCalendar<Calendar = IslamicCivil>> DateTime<A> { |
1085 | | /// Construct a new Civil Islamic datetime from integers. |
1086 | | /// |
1087 | | /// ```rust |
1088 | | /// use icu::calendar::islamic::IslamicCivil; |
1089 | | /// use icu::calendar::DateTime; |
1090 | | /// |
1091 | | /// let islamic = IslamicCivil::new_always_calculating(); |
1092 | | /// |
1093 | | /// let datetime_islamic = |
1094 | | /// DateTime::try_new_islamic_civil_datetime_with_calendar( |
1095 | | /// 474, 10, 11, 13, 1, 0, islamic, |
1096 | | /// ) |
1097 | | /// .expect("Failed to initialize Islamic DateTime instance."); |
1098 | | /// |
1099 | | /// assert_eq!(datetime_islamic.date.year().number, 474); |
1100 | | /// assert_eq!(datetime_islamic.date.month().ordinal, 10); |
1101 | | /// assert_eq!(datetime_islamic.date.day_of_month().0, 11); |
1102 | | /// assert_eq!(datetime_islamic.time.hour.number(), 13); |
1103 | | /// assert_eq!(datetime_islamic.time.minute.number(), 1); |
1104 | | /// assert_eq!(datetime_islamic.time.second.number(), 0); |
1105 | | /// ``` |
1106 | 0 | pub fn try_new_islamic_civil_datetime_with_calendar( |
1107 | 0 | year: i32, |
1108 | 0 | month: u8, |
1109 | 0 | day: u8, |
1110 | 0 | hour: u8, |
1111 | 0 | minute: u8, |
1112 | 0 | second: u8, |
1113 | 0 | calendar: A, |
1114 | 0 | ) -> Result<DateTime<A>, CalendarError> { |
1115 | | Ok(DateTime { |
1116 | 0 | date: Date::try_new_islamic_civil_date_with_calendar(year, month, day, calendar)?, |
1117 | 0 | time: Time::try_new(hour, minute, second, 0)?, |
1118 | | }) |
1119 | 0 | } |
1120 | | } |
1121 | | |
1122 | | /// The inner date type used for representing [`Date`]s of [`IslamicTabular`]. See [`Date`] and [`IslamicTabular`] for more details. |
1123 | | |
1124 | | #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)] |
1125 | | pub struct IslamicTabularDateInner(ArithmeticDate<IslamicTabular>); |
1126 | | |
1127 | | impl CalendarArithmetic for IslamicTabular { |
1128 | | type YearInfo = (); |
1129 | | |
1130 | 0 | fn month_days(year: i32, month: u8, _data: ()) -> u8 { |
1131 | 0 | match month { |
1132 | 0 | 1 | 3 | 5 | 7 | 9 | 11 => 30, |
1133 | 0 | 2 | 4 | 6 | 8 | 10 => 29, |
1134 | 0 | 12 if Self::is_leap_year(year, ()) => 30, |
1135 | 0 | 12 => 29, |
1136 | 0 | _ => 0, |
1137 | | } |
1138 | 0 | } |
1139 | | |
1140 | 0 | fn months_for_every_year(_year: i32, _data: ()) -> u8 { |
1141 | 0 | 12 |
1142 | 0 | } |
1143 | | |
1144 | 0 | fn days_in_provided_year(year: i32, _data: ()) -> u16 { |
1145 | 0 | if Self::is_leap_year(year, ()) { |
1146 | 0 | IslamicYearInfo::LONG_YEAR_LEN |
1147 | | } else { |
1148 | 0 | IslamicYearInfo::SHORT_YEAR_LEN |
1149 | | } |
1150 | 0 | } |
1151 | | |
1152 | 0 | fn is_leap_year(year: i32, _data: ()) -> bool { |
1153 | 0 | (14 + 11 * year).rem_euclid(30) < 11 |
1154 | 0 | } |
1155 | | |
1156 | 0 | fn last_month_day_in_year(year: i32, _data: ()) -> (u8, u8) { |
1157 | 0 | if Self::is_leap_year(year, ()) { |
1158 | 0 | (12, 30) |
1159 | | } else { |
1160 | 0 | (12, 29) |
1161 | | } |
1162 | 0 | } |
1163 | | } |
1164 | | |
1165 | | impl Calendar for IslamicTabular { |
1166 | | type DateInner = IslamicTabularDateInner; |
1167 | | |
1168 | 0 | fn date_from_codes( |
1169 | 0 | &self, |
1170 | 0 | era: types::Era, |
1171 | 0 | year: i32, |
1172 | 0 | month_code: types::MonthCode, |
1173 | 0 | day: u8, |
1174 | 0 | ) -> Result<Self::DateInner, CalendarError> { |
1175 | 0 | let year = if era.0 == tinystr!(16, "islamic-tbla") |
1176 | 0 | || era.0 == tinystr!(16, "islamic") |
1177 | 0 | || era.0 == tinystr!(16, "ah") |
1178 | | { |
1179 | 0 | year |
1180 | | } else { |
1181 | 0 | return Err(CalendarError::UnknownEra(era.0, self.debug_name())); |
1182 | | }; |
1183 | | |
1184 | 0 | ArithmeticDate::new_from_codes(self, year, month_code, day).map(IslamicTabularDateInner) |
1185 | 0 | } |
1186 | | |
1187 | 0 | fn date_from_iso(&self, iso: Date<Iso>) -> Self::DateInner { |
1188 | 0 | let fixed_iso = Iso::fixed_from_iso(*iso.inner()); |
1189 | 0 | Self::islamic_from_fixed(fixed_iso).inner |
1190 | 0 | } |
1191 | | |
1192 | 0 | fn date_to_iso(&self, date: &Self::DateInner) -> Date<Iso> { |
1193 | 0 | let fixed_islamic = Self::fixed_from_islamic(*date); |
1194 | 0 | Iso::iso_from_fixed(fixed_islamic) |
1195 | 0 | } |
1196 | | |
1197 | 0 | fn months_in_year(&self, date: &Self::DateInner) -> u8 { |
1198 | 0 | date.0.months_in_year() |
1199 | 0 | } |
1200 | | |
1201 | 0 | fn days_in_year(&self, date: &Self::DateInner) -> u16 { |
1202 | 0 | date.0.days_in_year() |
1203 | 0 | } |
1204 | | |
1205 | 0 | fn days_in_month(&self, date: &Self::DateInner) -> u8 { |
1206 | 0 | date.0.days_in_month() |
1207 | 0 | } |
1208 | | |
1209 | 0 | fn day_of_week(&self, date: &Self::DateInner) -> types::IsoWeekday { |
1210 | 0 | Iso.day_of_week(self.date_to_iso(date).inner()) |
1211 | 0 | } |
1212 | | |
1213 | 0 | fn offset_date(&self, date: &mut Self::DateInner, offset: DateDuration<Self>) { |
1214 | 0 | date.0.offset_date(offset, &()) |
1215 | 0 | } |
1216 | | |
1217 | 0 | fn until( |
1218 | 0 | &self, |
1219 | 0 | date1: &Self::DateInner, |
1220 | 0 | date2: &Self::DateInner, |
1221 | 0 | _calendar2: &Self, |
1222 | 0 | _largest_unit: DateDurationUnit, |
1223 | 0 | _smallest_unit: DateDurationUnit, |
1224 | 0 | ) -> DateDuration<Self> { |
1225 | 0 | date1.0.until(date2.0, _largest_unit, _smallest_unit) |
1226 | 0 | } |
1227 | | |
1228 | 0 | fn debug_name(&self) -> &'static str { |
1229 | 0 | "Islamic (tabular)" |
1230 | 0 | } |
1231 | | |
1232 | 0 | fn year(&self, date: &Self::DateInner) -> types::FormattableYear { |
1233 | 0 | Self::year_as_islamic(date.0.year) |
1234 | 0 | } |
1235 | | |
1236 | 0 | fn is_in_leap_year(&self, date: &Self::DateInner) -> bool { |
1237 | 0 | Self::is_leap_year(date.0.year, ()) |
1238 | 0 | } |
1239 | | |
1240 | 0 | fn month(&self, date: &Self::DateInner) -> types::FormattableMonth { |
1241 | 0 | date.0.month() |
1242 | 0 | } |
1243 | | |
1244 | 0 | fn day_of_month(&self, date: &Self::DateInner) -> types::DayOfMonth { |
1245 | 0 | date.0.day_of_month() |
1246 | 0 | } |
1247 | | |
1248 | 0 | fn day_of_year_info(&self, date: &Self::DateInner) -> types::DayOfYearInfo { |
1249 | 0 | let prev_year = date.0.year.saturating_sub(1); |
1250 | 0 | let next_year = date.0.year.saturating_add(1); |
1251 | 0 | types::DayOfYearInfo { |
1252 | 0 | day_of_year: date.0.day_of_year(), |
1253 | 0 | days_in_year: date.0.days_in_year(), |
1254 | 0 | prev_year: Self::year_as_islamic(prev_year), |
1255 | 0 | days_in_prev_year: Self::days_in_provided_year(prev_year, ()), |
1256 | 0 | next_year: Self::year_as_islamic(next_year), |
1257 | 0 | } |
1258 | 0 | } |
1259 | 0 | fn any_calendar_kind(&self) -> Option<AnyCalendarKind> { |
1260 | 0 | Some(AnyCalendarKind::IslamicTabular) |
1261 | 0 | } |
1262 | | } |
1263 | | |
1264 | | impl IslamicTabular { |
1265 | 0 | fn fixed_from_islamic(i_date: IslamicTabularDateInner) -> RataDie { |
1266 | 0 | calendrical_calculations::islamic::fixed_from_islamic_tabular( |
1267 | 0 | i_date.0.year, |
1268 | 0 | i_date.0.month, |
1269 | 0 | i_date.0.day, |
1270 | | ) |
1271 | 0 | } |
1272 | | |
1273 | 0 | fn islamic_from_fixed(date: RataDie) -> Date<IslamicTabular> { |
1274 | 0 | let (y, m, d) = calendrical_calculations::islamic::islamic_tabular_from_fixed(date); |
1275 | | |
1276 | 0 | debug_assert!( |
1277 | 0 | Date::try_new_islamic_civil_date_with_calendar(y, m, d, IslamicCivil).is_ok() |
1278 | | ); |
1279 | 0 | Date::from_raw( |
1280 | 0 | IslamicTabularDateInner(ArithmeticDate::new_unchecked(y, m, d)), |
1281 | 0 | IslamicTabular, |
1282 | | ) |
1283 | 0 | } |
1284 | | |
1285 | 0 | fn year_as_islamic(year: i32) -> types::FormattableYear { |
1286 | 0 | types::FormattableYear { |
1287 | 0 | era: types::Era(tinystr!(16, "islamic")), |
1288 | 0 | number: year, |
1289 | 0 | cyclic: None, |
1290 | 0 | related_iso: None, |
1291 | 0 | } |
1292 | 0 | } |
1293 | | } |
1294 | | |
1295 | | impl<A: AsCalendar<Calendar = IslamicTabular>> Date<A> { |
1296 | | /// Construct new Tabular Islamic Date. |
1297 | | /// |
1298 | | /// Has no negative years, only era is the AH. |
1299 | | /// |
1300 | | /// ```rust |
1301 | | /// use icu::calendar::islamic::IslamicTabular; |
1302 | | /// use icu::calendar::Date; |
1303 | | /// |
1304 | | /// let islamic = IslamicTabular::new_always_calculating(); |
1305 | | /// |
1306 | | /// let date_islamic = |
1307 | | /// Date::try_new_islamic_tabular_date_with_calendar(1392, 4, 25, islamic) |
1308 | | /// .expect("Failed to initialize Islamic Date instance."); |
1309 | | /// |
1310 | | /// assert_eq!(date_islamic.year().number, 1392); |
1311 | | /// assert_eq!(date_islamic.month().ordinal, 4); |
1312 | | /// assert_eq!(date_islamic.day_of_month().0, 25); |
1313 | | /// ``` |
1314 | 0 | pub fn try_new_islamic_tabular_date_with_calendar( |
1315 | 0 | year: i32, |
1316 | 0 | month: u8, |
1317 | 0 | day: u8, |
1318 | 0 | calendar: A, |
1319 | 0 | ) -> Result<Date<A>, CalendarError> { |
1320 | 0 | ArithmeticDate::new_from_ordinals(year, month, day) |
1321 | 0 | .map(IslamicTabularDateInner) |
1322 | 0 | .map(|inner| Date::from_raw(inner, calendar)) |
1323 | 0 | } |
1324 | | } |
1325 | | |
1326 | | impl<A: AsCalendar<Calendar = IslamicTabular>> DateTime<A> { |
1327 | | /// Construct a new Tabular Islamic datetime from integers. |
1328 | | /// |
1329 | | /// ```rust |
1330 | | /// use icu::calendar::islamic::IslamicTabular; |
1331 | | /// use icu::calendar::DateTime; |
1332 | | /// |
1333 | | /// let islamic = IslamicTabular::new_always_calculating(); |
1334 | | /// |
1335 | | /// let datetime_islamic = |
1336 | | /// DateTime::try_new_islamic_tabular_datetime_with_calendar( |
1337 | | /// 474, 10, 11, 13, 1, 0, islamic, |
1338 | | /// ) |
1339 | | /// .expect("Failed to initialize Islamic DateTime instance."); |
1340 | | /// |
1341 | | /// assert_eq!(datetime_islamic.date.year().number, 474); |
1342 | | /// assert_eq!(datetime_islamic.date.month().ordinal, 10); |
1343 | | /// assert_eq!(datetime_islamic.date.day_of_month().0, 11); |
1344 | | /// assert_eq!(datetime_islamic.time.hour.number(), 13); |
1345 | | /// assert_eq!(datetime_islamic.time.minute.number(), 1); |
1346 | | /// assert_eq!(datetime_islamic.time.second.number(), 0); |
1347 | | /// ``` |
1348 | 0 | pub fn try_new_islamic_tabular_datetime_with_calendar( |
1349 | 0 | year: i32, |
1350 | 0 | month: u8, |
1351 | 0 | day: u8, |
1352 | 0 | hour: u8, |
1353 | 0 | minute: u8, |
1354 | 0 | second: u8, |
1355 | 0 | calendar: A, |
1356 | 0 | ) -> Result<DateTime<A>, CalendarError> { |
1357 | | Ok(DateTime { |
1358 | 0 | date: Date::try_new_islamic_tabular_date_with_calendar(year, month, day, calendar)?, |
1359 | 0 | time: Time::try_new(hour, minute, second, 0)?, |
1360 | | }) |
1361 | 0 | } |
1362 | | } |
1363 | | |
1364 | | #[cfg(test)] |
1365 | | mod test { |
1366 | | use super::*; |
1367 | | use crate::Ref; |
1368 | | |
1369 | | const START_YEAR: i32 = -1245; |
1370 | | const END_YEAR: i32 = 1518; |
1371 | | |
1372 | | #[derive(Debug)] |
1373 | | struct DateCase { |
1374 | | year: i32, |
1375 | | month: u8, |
1376 | | day: u8, |
1377 | | } |
1378 | | |
1379 | | static TEST_FIXED_DATE: [i64; 33] = [ |
1380 | | -214193, -61387, 25469, 49217, 171307, 210155, 253427, 369740, 400085, 434355, 452605, |
1381 | | 470160, 473837, 507850, 524156, 544676, 567118, 569477, 601716, 613424, 626596, 645554, |
1382 | | 664224, 671401, 694799, 704424, 708842, 709409, 709580, 727274, 728714, 744313, 764652, |
1383 | | ]; |
1384 | | // Removed: 601716 and 727274 fixed dates |
1385 | | static TEST_FIXED_DATE_UMMALQURA: [i64; 31] = [ |
1386 | | -214193, -61387, 25469, 49217, 171307, 210155, 253427, 369740, 400085, 434355, 452605, |
1387 | | 470160, 473837, 507850, 524156, 544676, 567118, 569477, 613424, 626596, 645554, 664224, |
1388 | | 671401, 694799, 704424, 708842, 709409, 709580, 728714, 744313, 764652, |
1389 | | ]; |
1390 | | |
1391 | | static UMMALQURA_DATE_EXPECTED: [DateCase; 31] = [ |
1392 | | DateCase { |
1393 | | year: -1245, |
1394 | | month: 12, |
1395 | | day: 11, |
1396 | | }, |
1397 | | DateCase { |
1398 | | year: -813, |
1399 | | month: 2, |
1400 | | day: 26, |
1401 | | }, |
1402 | | DateCase { |
1403 | | year: -568, |
1404 | | month: 4, |
1405 | | day: 3, |
1406 | | }, |
1407 | | DateCase { |
1408 | | year: -501, |
1409 | | month: 4, |
1410 | | day: 8, |
1411 | | }, |
1412 | | DateCase { |
1413 | | year: -157, |
1414 | | month: 10, |
1415 | | day: 18, |
1416 | | }, |
1417 | | DateCase { |
1418 | | year: -47, |
1419 | | month: 6, |
1420 | | day: 4, |
1421 | | }, |
1422 | | DateCase { |
1423 | | year: 75, |
1424 | | month: 7, |
1425 | | day: 14, |
1426 | | }, |
1427 | | DateCase { |
1428 | | year: 403, |
1429 | | month: 10, |
1430 | | day: 6, |
1431 | | }, |
1432 | | DateCase { |
1433 | | year: 489, |
1434 | | month: 5, |
1435 | | day: 23, |
1436 | | }, |
1437 | | DateCase { |
1438 | | year: 586, |
1439 | | month: 2, |
1440 | | day: 8, |
1441 | | }, |
1442 | | DateCase { |
1443 | | year: 637, |
1444 | | month: 8, |
1445 | | day: 8, |
1446 | | }, |
1447 | | DateCase { |
1448 | | year: 687, |
1449 | | month: 2, |
1450 | | day: 22, |
1451 | | }, |
1452 | | DateCase { |
1453 | | year: 697, |
1454 | | month: 7, |
1455 | | day: 8, |
1456 | | }, |
1457 | | DateCase { |
1458 | | year: 793, |
1459 | | month: 7, |
1460 | | day: 1, |
1461 | | }, |
1462 | | DateCase { |
1463 | | year: 839, |
1464 | | month: 7, |
1465 | | day: 7, |
1466 | | }, |
1467 | | DateCase { |
1468 | | year: 897, |
1469 | | month: 6, |
1470 | | day: 3, |
1471 | | }, |
1472 | | DateCase { |
1473 | | year: 960, |
1474 | | month: 10, |
1475 | | day: 1, |
1476 | | }, |
1477 | | DateCase { |
1478 | | year: 967, |
1479 | | month: 5, |
1480 | | day: 28, |
1481 | | }, |
1482 | | DateCase { |
1483 | | year: 1091, |
1484 | | month: 6, |
1485 | | day: 4, |
1486 | | }, |
1487 | | DateCase { |
1488 | | year: 1128, |
1489 | | month: 8, |
1490 | | day: 5, |
1491 | | }, |
1492 | | DateCase { |
1493 | | year: 1182, |
1494 | | month: 2, |
1495 | | day: 4, |
1496 | | }, |
1497 | | DateCase { |
1498 | | year: 1234, |
1499 | | month: 10, |
1500 | | day: 11, |
1501 | | }, |
1502 | | DateCase { |
1503 | | year: 1255, |
1504 | | month: 1, |
1505 | | day: 11, |
1506 | | }, |
1507 | | DateCase { |
1508 | | year: 1321, |
1509 | | month: 1, |
1510 | | day: 21, |
1511 | | }, |
1512 | | DateCase { |
1513 | | year: 1348, |
1514 | | month: 3, |
1515 | | day: 20, |
1516 | | }, |
1517 | | DateCase { |
1518 | | year: 1360, |
1519 | | month: 9, |
1520 | | day: 8, |
1521 | | }, |
1522 | | DateCase { |
1523 | | year: 1362, |
1524 | | month: 4, |
1525 | | day: 14, |
1526 | | }, |
1527 | | DateCase { |
1528 | | year: 1362, |
1529 | | month: 10, |
1530 | | day: 8, |
1531 | | }, |
1532 | | DateCase { |
1533 | | year: 1416, |
1534 | | month: 10, |
1535 | | day: 6, |
1536 | | }, |
1537 | | DateCase { |
1538 | | year: 1460, |
1539 | | month: 10, |
1540 | | day: 13, |
1541 | | }, |
1542 | | DateCase { |
1543 | | year: 1518, |
1544 | | month: 3, |
1545 | | day: 6, |
1546 | | }, |
1547 | | ]; |
1548 | | |
1549 | | static OBSERVATIONAL_CASES: [DateCase; 33] = [ |
1550 | | DateCase { |
1551 | | year: -1245, |
1552 | | month: 12, |
1553 | | day: 11, |
1554 | | }, |
1555 | | DateCase { |
1556 | | year: -813, |
1557 | | month: 2, |
1558 | | day: 25, |
1559 | | }, |
1560 | | DateCase { |
1561 | | year: -568, |
1562 | | month: 4, |
1563 | | day: 2, |
1564 | | }, |
1565 | | DateCase { |
1566 | | year: -501, |
1567 | | month: 4, |
1568 | | day: 7, |
1569 | | }, |
1570 | | DateCase { |
1571 | | year: -157, |
1572 | | month: 10, |
1573 | | day: 18, |
1574 | | }, |
1575 | | DateCase { |
1576 | | year: -47, |
1577 | | month: 6, |
1578 | | day: 3, |
1579 | | }, |
1580 | | DateCase { |
1581 | | year: 75, |
1582 | | month: 7, |
1583 | | day: 13, |
1584 | | }, |
1585 | | DateCase { |
1586 | | year: 403, |
1587 | | month: 10, |
1588 | | day: 5, |
1589 | | }, |
1590 | | DateCase { |
1591 | | year: 489, |
1592 | | month: 5, |
1593 | | day: 22, |
1594 | | }, |
1595 | | DateCase { |
1596 | | year: 586, |
1597 | | month: 2, |
1598 | | day: 7, |
1599 | | }, |
1600 | | DateCase { |
1601 | | year: 637, |
1602 | | month: 8, |
1603 | | day: 7, |
1604 | | }, |
1605 | | DateCase { |
1606 | | year: 687, |
1607 | | month: 2, |
1608 | | day: 21, |
1609 | | }, |
1610 | | DateCase { |
1611 | | year: 697, |
1612 | | month: 7, |
1613 | | day: 7, |
1614 | | }, |
1615 | | DateCase { |
1616 | | year: 793, |
1617 | | month: 6, |
1618 | | day: 30, |
1619 | | }, |
1620 | | DateCase { |
1621 | | year: 839, |
1622 | | month: 7, |
1623 | | day: 6, |
1624 | | }, |
1625 | | DateCase { |
1626 | | year: 897, |
1627 | | month: 6, |
1628 | | day: 2, |
1629 | | }, |
1630 | | DateCase { |
1631 | | year: 960, |
1632 | | month: 9, |
1633 | | day: 30, |
1634 | | }, |
1635 | | DateCase { |
1636 | | year: 967, |
1637 | | month: 5, |
1638 | | day: 27, |
1639 | | }, |
1640 | | DateCase { |
1641 | | year: 1058, |
1642 | | month: 5, |
1643 | | day: 18, |
1644 | | }, |
1645 | | DateCase { |
1646 | | year: 1091, |
1647 | | month: 6, |
1648 | | day: 3, |
1649 | | }, |
1650 | | DateCase { |
1651 | | year: 1128, |
1652 | | month: 8, |
1653 | | day: 4, |
1654 | | }, |
1655 | | DateCase { |
1656 | | year: 1182, |
1657 | | month: 2, |
1658 | | day: 4, |
1659 | | }, |
1660 | | DateCase { |
1661 | | year: 1234, |
1662 | | month: 10, |
1663 | | day: 10, |
1664 | | }, |
1665 | | DateCase { |
1666 | | year: 1255, |
1667 | | month: 1, |
1668 | | day: 11, |
1669 | | }, |
1670 | | DateCase { |
1671 | | year: 1321, |
1672 | | month: 1, |
1673 | | day: 20, |
1674 | | }, |
1675 | | DateCase { |
1676 | | year: 1348, |
1677 | | month: 3, |
1678 | | day: 19, |
1679 | | }, |
1680 | | DateCase { |
1681 | | year: 1360, |
1682 | | month: 9, |
1683 | | day: 7, |
1684 | | }, |
1685 | | DateCase { |
1686 | | year: 1362, |
1687 | | month: 4, |
1688 | | day: 14, |
1689 | | }, |
1690 | | DateCase { |
1691 | | year: 1362, |
1692 | | month: 10, |
1693 | | day: 7, |
1694 | | }, |
1695 | | DateCase { |
1696 | | year: 1412, |
1697 | | month: 9, |
1698 | | day: 12, |
1699 | | }, |
1700 | | DateCase { |
1701 | | year: 1416, |
1702 | | month: 10, |
1703 | | day: 5, |
1704 | | }, |
1705 | | DateCase { |
1706 | | year: 1460, |
1707 | | month: 10, |
1708 | | day: 12, |
1709 | | }, |
1710 | | DateCase { |
1711 | | year: 1518, |
1712 | | month: 3, |
1713 | | day: 5, |
1714 | | }, |
1715 | | ]; |
1716 | | |
1717 | | static ARITHMETIC_CASES: [DateCase; 33] = [ |
1718 | | DateCase { |
1719 | | year: -1245, |
1720 | | month: 12, |
1721 | | day: 9, |
1722 | | }, |
1723 | | DateCase { |
1724 | | year: -813, |
1725 | | month: 2, |
1726 | | day: 23, |
1727 | | }, |
1728 | | DateCase { |
1729 | | year: -568, |
1730 | | month: 4, |
1731 | | day: 1, |
1732 | | }, |
1733 | | DateCase { |
1734 | | year: -501, |
1735 | | month: 4, |
1736 | | day: 6, |
1737 | | }, |
1738 | | DateCase { |
1739 | | year: -157, |
1740 | | month: 10, |
1741 | | day: 17, |
1742 | | }, |
1743 | | DateCase { |
1744 | | year: -47, |
1745 | | month: 6, |
1746 | | day: 3, |
1747 | | }, |
1748 | | DateCase { |
1749 | | year: 75, |
1750 | | month: 7, |
1751 | | day: 13, |
1752 | | }, |
1753 | | DateCase { |
1754 | | year: 403, |
1755 | | month: 10, |
1756 | | day: 5, |
1757 | | }, |
1758 | | DateCase { |
1759 | | year: 489, |
1760 | | month: 5, |
1761 | | day: 22, |
1762 | | }, |
1763 | | DateCase { |
1764 | | year: 586, |
1765 | | month: 2, |
1766 | | day: 7, |
1767 | | }, |
1768 | | DateCase { |
1769 | | year: 637, |
1770 | | month: 8, |
1771 | | day: 7, |
1772 | | }, |
1773 | | DateCase { |
1774 | | year: 687, |
1775 | | month: 2, |
1776 | | day: 20, |
1777 | | }, |
1778 | | DateCase { |
1779 | | year: 697, |
1780 | | month: 7, |
1781 | | day: 7, |
1782 | | }, |
1783 | | DateCase { |
1784 | | year: 793, |
1785 | | month: 7, |
1786 | | day: 1, |
1787 | | }, |
1788 | | DateCase { |
1789 | | year: 839, |
1790 | | month: 7, |
1791 | | day: 6, |
1792 | | }, |
1793 | | DateCase { |
1794 | | year: 897, |
1795 | | month: 6, |
1796 | | day: 1, |
1797 | | }, |
1798 | | DateCase { |
1799 | | year: 960, |
1800 | | month: 9, |
1801 | | day: 30, |
1802 | | }, |
1803 | | DateCase { |
1804 | | year: 967, |
1805 | | month: 5, |
1806 | | day: 27, |
1807 | | }, |
1808 | | DateCase { |
1809 | | year: 1058, |
1810 | | month: 5, |
1811 | | day: 18, |
1812 | | }, |
1813 | | DateCase { |
1814 | | year: 1091, |
1815 | | month: 6, |
1816 | | day: 2, |
1817 | | }, |
1818 | | DateCase { |
1819 | | year: 1128, |
1820 | | month: 8, |
1821 | | day: 4, |
1822 | | }, |
1823 | | DateCase { |
1824 | | year: 1182, |
1825 | | month: 2, |
1826 | | day: 3, |
1827 | | }, |
1828 | | DateCase { |
1829 | | year: 1234, |
1830 | | month: 10, |
1831 | | day: 10, |
1832 | | }, |
1833 | | DateCase { |
1834 | | year: 1255, |
1835 | | month: 1, |
1836 | | day: 11, |
1837 | | }, |
1838 | | DateCase { |
1839 | | year: 1321, |
1840 | | month: 1, |
1841 | | day: 21, |
1842 | | }, |
1843 | | DateCase { |
1844 | | year: 1348, |
1845 | | month: 3, |
1846 | | day: 19, |
1847 | | }, |
1848 | | DateCase { |
1849 | | year: 1360, |
1850 | | month: 9, |
1851 | | day: 8, |
1852 | | }, |
1853 | | DateCase { |
1854 | | year: 1362, |
1855 | | month: 4, |
1856 | | day: 13, |
1857 | | }, |
1858 | | DateCase { |
1859 | | year: 1362, |
1860 | | month: 10, |
1861 | | day: 7, |
1862 | | }, |
1863 | | DateCase { |
1864 | | year: 1412, |
1865 | | month: 9, |
1866 | | day: 13, |
1867 | | }, |
1868 | | DateCase { |
1869 | | year: 1416, |
1870 | | month: 10, |
1871 | | day: 5, |
1872 | | }, |
1873 | | DateCase { |
1874 | | year: 1460, |
1875 | | month: 10, |
1876 | | day: 12, |
1877 | | }, |
1878 | | DateCase { |
1879 | | year: 1518, |
1880 | | month: 3, |
1881 | | day: 5, |
1882 | | }, |
1883 | | ]; |
1884 | | |
1885 | | static TABULAR_CASES: [DateCase; 33] = [ |
1886 | | DateCase { |
1887 | | year: -1245, |
1888 | | month: 12, |
1889 | | day: 10, |
1890 | | }, |
1891 | | DateCase { |
1892 | | year: -813, |
1893 | | month: 2, |
1894 | | day: 24, |
1895 | | }, |
1896 | | DateCase { |
1897 | | year: -568, |
1898 | | month: 4, |
1899 | | day: 2, |
1900 | | }, |
1901 | | DateCase { |
1902 | | year: -501, |
1903 | | month: 4, |
1904 | | day: 7, |
1905 | | }, |
1906 | | DateCase { |
1907 | | year: -157, |
1908 | | month: 10, |
1909 | | day: 18, |
1910 | | }, |
1911 | | DateCase { |
1912 | | year: -47, |
1913 | | month: 6, |
1914 | | day: 4, |
1915 | | }, |
1916 | | DateCase { |
1917 | | year: 75, |
1918 | | month: 7, |
1919 | | day: 14, |
1920 | | }, |
1921 | | DateCase { |
1922 | | year: 403, |
1923 | | month: 10, |
1924 | | day: 6, |
1925 | | }, |
1926 | | DateCase { |
1927 | | year: 489, |
1928 | | month: 5, |
1929 | | day: 23, |
1930 | | }, |
1931 | | DateCase { |
1932 | | year: 586, |
1933 | | month: 2, |
1934 | | day: 8, |
1935 | | }, |
1936 | | DateCase { |
1937 | | year: 637, |
1938 | | month: 8, |
1939 | | day: 8, |
1940 | | }, |
1941 | | DateCase { |
1942 | | year: 687, |
1943 | | month: 2, |
1944 | | day: 21, |
1945 | | }, |
1946 | | DateCase { |
1947 | | year: 697, |
1948 | | month: 7, |
1949 | | day: 8, |
1950 | | }, |
1951 | | DateCase { |
1952 | | year: 793, |
1953 | | month: 7, |
1954 | | day: 2, |
1955 | | }, |
1956 | | DateCase { |
1957 | | year: 839, |
1958 | | month: 7, |
1959 | | day: 7, |
1960 | | }, |
1961 | | DateCase { |
1962 | | year: 897, |
1963 | | month: 6, |
1964 | | day: 2, |
1965 | | }, |
1966 | | DateCase { |
1967 | | year: 960, |
1968 | | month: 10, |
1969 | | day: 1, |
1970 | | }, |
1971 | | DateCase { |
1972 | | year: 967, |
1973 | | month: 5, |
1974 | | day: 28, |
1975 | | }, |
1976 | | DateCase { |
1977 | | year: 1058, |
1978 | | month: 5, |
1979 | | day: 19, |
1980 | | }, |
1981 | | DateCase { |
1982 | | year: 1091, |
1983 | | month: 6, |
1984 | | day: 3, |
1985 | | }, |
1986 | | DateCase { |
1987 | | year: 1128, |
1988 | | month: 8, |
1989 | | day: 5, |
1990 | | }, |
1991 | | DateCase { |
1992 | | year: 1182, |
1993 | | month: 2, |
1994 | | day: 4, |
1995 | | }, |
1996 | | DateCase { |
1997 | | year: 1234, |
1998 | | month: 10, |
1999 | | day: 11, |
2000 | | }, |
2001 | | DateCase { |
2002 | | year: 1255, |
2003 | | month: 1, |
2004 | | day: 12, |
2005 | | }, |
2006 | | DateCase { |
2007 | | year: 1321, |
2008 | | month: 1, |
2009 | | day: 22, |
2010 | | }, |
2011 | | DateCase { |
2012 | | year: 1348, |
2013 | | month: 3, |
2014 | | day: 20, |
2015 | | }, |
2016 | | DateCase { |
2017 | | year: 1360, |
2018 | | month: 9, |
2019 | | day: 9, |
2020 | | }, |
2021 | | DateCase { |
2022 | | year: 1362, |
2023 | | month: 4, |
2024 | | day: 14, |
2025 | | }, |
2026 | | DateCase { |
2027 | | year: 1362, |
2028 | | month: 10, |
2029 | | day: 8, |
2030 | | }, |
2031 | | DateCase { |
2032 | | year: 1412, |
2033 | | month: 9, |
2034 | | day: 14, |
2035 | | }, |
2036 | | DateCase { |
2037 | | year: 1416, |
2038 | | month: 10, |
2039 | | day: 6, |
2040 | | }, |
2041 | | DateCase { |
2042 | | year: 1460, |
2043 | | month: 10, |
2044 | | day: 13, |
2045 | | }, |
2046 | | DateCase { |
2047 | | year: 1518, |
2048 | | month: 3, |
2049 | | day: 6, |
2050 | | }, |
2051 | | ]; |
2052 | | |
2053 | | #[test] |
2054 | | fn test_observational_islamic_from_fixed() { |
2055 | | let calendar = IslamicObservational::new(); |
2056 | | let calendar = Ref(&calendar); |
2057 | | for (case, f_date) in OBSERVATIONAL_CASES.iter().zip(TEST_FIXED_DATE.iter()) { |
2058 | | let date = |
2059 | | Date::try_new_observational_islamic_date(case.year, case.month, case.day, calendar) |
2060 | | .unwrap(); |
2061 | | let iso = Iso::iso_from_fixed(RataDie::new(*f_date)); |
2062 | | |
2063 | | assert_eq!(iso.to_calendar(calendar).inner, date.inner, "{case:?}"); |
2064 | | } |
2065 | | } |
2066 | | |
2067 | | #[test] |
2068 | | fn test_fixed_from_observational_islamic() { |
2069 | | let calendar = IslamicObservational::new(); |
2070 | | let calendar = Ref(&calendar); |
2071 | | for (case, f_date) in OBSERVATIONAL_CASES.iter().zip(TEST_FIXED_DATE.iter()) { |
2072 | | let date = |
2073 | | Date::try_new_observational_islamic_date(case.year, case.month, case.day, calendar) |
2074 | | .unwrap(); |
2075 | | assert_eq!(date.to_fixed(), RataDie::new(*f_date), "{case:?}"); |
2076 | | } |
2077 | | } |
2078 | | |
2079 | | #[test] |
2080 | | fn test_fixed_from_islamic() { |
2081 | | let calendar = IslamicCivil::new(); |
2082 | | let calendar = Ref(&calendar); |
2083 | | for (case, f_date) in ARITHMETIC_CASES.iter().zip(TEST_FIXED_DATE.iter()) { |
2084 | | let date = Date::try_new_islamic_civil_date_with_calendar( |
2085 | | case.year, case.month, case.day, calendar, |
2086 | | ) |
2087 | | .unwrap(); |
2088 | | assert_eq!(date.to_fixed(), RataDie::new(*f_date), "{case:?}"); |
2089 | | } |
2090 | | } |
2091 | | |
2092 | | #[test] |
2093 | | fn test_islamic_from_fixed() { |
2094 | | let calendar = IslamicCivil::new(); |
2095 | | let calendar = Ref(&calendar); |
2096 | | for (case, f_date) in ARITHMETIC_CASES.iter().zip(TEST_FIXED_DATE.iter()) { |
2097 | | let date = Date::try_new_islamic_civil_date_with_calendar( |
2098 | | case.year, case.month, case.day, calendar, |
2099 | | ) |
2100 | | .unwrap(); |
2101 | | let iso = Iso::iso_from_fixed(RataDie::new(*f_date)); |
2102 | | |
2103 | | assert_eq!(iso.to_calendar(calendar).inner, date.inner, "{case:?}"); |
2104 | | } |
2105 | | } |
2106 | | |
2107 | | #[test] |
2108 | | fn test_fixed_from_islamic_tbla() { |
2109 | | let calendar = IslamicTabular::new(); |
2110 | | let calendar = Ref(&calendar); |
2111 | | for (case, f_date) in TABULAR_CASES.iter().zip(TEST_FIXED_DATE.iter()) { |
2112 | | let date = Date::try_new_islamic_tabular_date_with_calendar( |
2113 | | case.year, case.month, case.day, calendar, |
2114 | | ) |
2115 | | .unwrap(); |
2116 | | assert_eq!(date.to_fixed(), RataDie::new(*f_date), "{case:?}"); |
2117 | | } |
2118 | | } |
2119 | | |
2120 | | #[test] |
2121 | | fn test_islamic_tbla_from_fixed() { |
2122 | | let calendar = IslamicTabular::new(); |
2123 | | let calendar = Ref(&calendar); |
2124 | | for (case, f_date) in TABULAR_CASES.iter().zip(TEST_FIXED_DATE.iter()) { |
2125 | | let date = Date::try_new_islamic_tabular_date_with_calendar( |
2126 | | case.year, case.month, case.day, calendar, |
2127 | | ) |
2128 | | .unwrap(); |
2129 | | let iso = Iso::iso_from_fixed(RataDie::new(*f_date)); |
2130 | | |
2131 | | assert_eq!(iso.to_calendar(calendar).inner, date.inner, "{case:?}"); |
2132 | | } |
2133 | | } |
2134 | | |
2135 | | #[test] |
2136 | | fn test_saudi_islamic_from_fixed() { |
2137 | | let calendar = IslamicUmmAlQura::new(); |
2138 | | let calendar = Ref(&calendar); |
2139 | | for (case, f_date) in UMMALQURA_DATE_EXPECTED |
2140 | | .iter() |
2141 | | .zip(TEST_FIXED_DATE_UMMALQURA.iter()) |
2142 | | { |
2143 | | let date = |
2144 | | Date::try_new_ummalqura_date(case.year, case.month, case.day, calendar).unwrap(); |
2145 | | let iso = Iso::iso_from_fixed(RataDie::new(*f_date)); |
2146 | | |
2147 | | assert_eq!(iso.to_calendar(calendar).inner, date.inner, "{case:?}"); |
2148 | | } |
2149 | | } |
2150 | | |
2151 | | #[test] |
2152 | | fn test_fixed_from_saudi_islamic() { |
2153 | | let calendar = IslamicUmmAlQura::new(); |
2154 | | let calendar = Ref(&calendar); |
2155 | | for (case, f_date) in UMMALQURA_DATE_EXPECTED |
2156 | | .iter() |
2157 | | .zip(TEST_FIXED_DATE_UMMALQURA.iter()) |
2158 | | { |
2159 | | let date = |
2160 | | Date::try_new_ummalqura_date(case.year, case.month, case.day, calendar).unwrap(); |
2161 | | assert_eq!(date.to_fixed(), RataDie::new(*f_date), "{case:?}"); |
2162 | | } |
2163 | | } |
2164 | | |
2165 | | #[ignore] |
2166 | | #[test] |
2167 | | fn test_days_in_provided_year_observational() { |
2168 | | let calendar = IslamicObservational::new(); |
2169 | | let calendar = Ref(&calendar); |
2170 | | // -1245 1 1 = -214526 (R.D Date) |
2171 | | // 1518 1 1 = 764589 (R.D Date) |
2172 | | let sum_days_in_year: i64 = (START_YEAR..END_YEAR) |
2173 | | .map(|year| { |
2174 | | IslamicObservational::days_in_provided_year( |
2175 | | year, |
2176 | | IslamicYearInfo::compute::<ObservationalIslamicMarker>(year), |
2177 | | ) as i64 |
2178 | | }) |
2179 | | .sum(); |
2180 | | let expected_number_of_days = |
2181 | | Date::try_new_observational_islamic_date(END_YEAR, 1, 1, calendar) |
2182 | | .unwrap() |
2183 | | .to_fixed() |
2184 | | - Date::try_new_observational_islamic_date(START_YEAR, 1, 1, calendar) |
2185 | | .unwrap() |
2186 | | .to_fixed(); // The number of days between Islamic years -1245 and 1518 |
2187 | | let tolerance = 1; // One day tolerance (See Astronomical::month_length for more context) |
2188 | | |
2189 | | assert!( |
2190 | | (sum_days_in_year - expected_number_of_days).abs() <= tolerance, |
2191 | | "Difference between sum_days_in_year and expected_number_of_days is more than the tolerance" |
2192 | | ); |
2193 | | } |
2194 | | |
2195 | | #[ignore] |
2196 | | #[test] |
2197 | | fn test_days_in_provided_year_ummalqura() { |
2198 | | let calendar = IslamicUmmAlQura::new(); |
2199 | | let calendar = Ref(&calendar); |
2200 | | // -1245 1 1 = -214528 (R.D Date) |
2201 | | // 1518 1 1 = 764588 (R.D Date) |
2202 | | let sum_days_in_year: i64 = (START_YEAR..END_YEAR) |
2203 | | .map(|year| { |
2204 | | IslamicUmmAlQura::days_in_provided_year( |
2205 | | year, |
2206 | | IslamicYearInfo::compute::<SaudiIslamicMarker>(year), |
2207 | | ) as i64 |
2208 | | }) |
2209 | | .sum(); |
2210 | | let expected_number_of_days = Date::try_new_ummalqura_date(END_YEAR, 1, 1, calendar) |
2211 | | .unwrap() |
2212 | | .to_fixed() |
2213 | | - Date::try_new_ummalqura_date(START_YEAR, 1, 1, calendar) |
2214 | | .unwrap() |
2215 | | .to_fixed(); // The number of days between Umm al-Qura Islamic years -1245 and 1518 |
2216 | | |
2217 | | assert_eq!(sum_days_in_year, expected_number_of_days); |
2218 | | } |
2219 | | |
2220 | | #[test] |
2221 | | fn test_regression_3868() { |
2222 | | // This date used to panic on creation |
2223 | | let iso = Date::try_new_iso_date(2011, 4, 4).unwrap(); |
2224 | | let islamic = iso.to_calendar(IslamicUmmAlQura::new()); |
2225 | | // Data from https://www.ummulqura.org.sa/Index.aspx |
2226 | | assert_eq!(islamic.day_of_month().0, 30); |
2227 | | assert_eq!(islamic.month().ordinal, 4); |
2228 | | assert_eq!(islamic.year().number, 1432); |
2229 | | } |
2230 | | |
2231 | | #[test] |
2232 | | fn test_regression_4914() { |
2233 | | // https://github.com/unicode-org/icu4x/issues/4914 |
2234 | | let cal = IslamicUmmAlQura::new_always_calculating(); |
2235 | | let era = "ah".parse().unwrap(); |
2236 | | let year = -6823; |
2237 | | let month_code = "M01".parse().unwrap(); |
2238 | | let dt = cal.date_from_codes(era, year, month_code, 1).unwrap(); |
2239 | | assert_eq!(dt.0.day, 1); |
2240 | | assert_eq!(dt.0.month, 1); |
2241 | | assert_eq!(dt.0.year, -6823); |
2242 | | } |
2243 | | } |