/rust/registry/src/index.crates.io-6f17d22bba15001f/icu_calendar-1.5.2/src/hebrew.rs
Line | Count | Source (jump to first uncovered line) |
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 Hebrew calendar. |
6 | | //! |
7 | | //! ```rust |
8 | | //! use icu::calendar::{Date, DateTime}; |
9 | | //! |
10 | | //! // `Date` type |
11 | | //! let hebrew_date = Date::try_new_hebrew_date(3425, 10, 11) |
12 | | //! .expect("Failed to initialize hebrew Date instance."); |
13 | | //! |
14 | | //! // `DateTime` type |
15 | | //! let hebrew_datetime = |
16 | | //! DateTime::try_new_hebrew_datetime(3425, 10, 11, 13, 1, 0) |
17 | | //! .expect("Failed to initialize hebrew DateTime instance."); |
18 | | //! |
19 | | //! // `Date` checks |
20 | | //! assert_eq!(hebrew_date.year().number, 3425); |
21 | | //! assert_eq!(hebrew_date.month().ordinal, 10); |
22 | | //! assert_eq!(hebrew_date.day_of_month().0, 11); |
23 | | //! |
24 | | //! // `DateTime` checks |
25 | | //! assert_eq!(hebrew_datetime.date.year().number, 3425); |
26 | | //! assert_eq!(hebrew_datetime.date.month().ordinal, 10); |
27 | | //! assert_eq!(hebrew_datetime.date.day_of_month().0, 11); |
28 | | //! assert_eq!(hebrew_datetime.time.hour.number(), 13); |
29 | | //! assert_eq!(hebrew_datetime.time.minute.number(), 1); |
30 | | //! assert_eq!(hebrew_datetime.time.second.number(), 0); |
31 | | //! ``` |
32 | | |
33 | | use crate::calendar_arithmetic::PrecomputedDataSource; |
34 | | use crate::calendar_arithmetic::{ArithmeticDate, CalendarArithmetic}; |
35 | | use crate::types::FormattableMonth; |
36 | | use crate::AnyCalendarKind; |
37 | | use crate::AsCalendar; |
38 | | use crate::Iso; |
39 | | use crate::{types, Calendar, CalendarError, Date, DateDuration, DateDurationUnit, DateTime, Time}; |
40 | | use ::tinystr::tinystr; |
41 | | use calendrical_calculations::hebrew_keviyah::{Keviyah, YearInfo}; |
42 | | |
43 | | /// The Civil Hebrew Calendar |
44 | | /// |
45 | | /// The [Hebrew calendar] is a lunisolar calendar used as the Jewish liturgical calendar |
46 | | /// as well as an official calendar in Israel. |
47 | | /// |
48 | | /// This calendar is the _civil_ Hebrew calendar, with the year starting at in the month of Tishrei. |
49 | | /// |
50 | | /// # Era codes |
51 | | /// |
52 | | /// This calendar supports a single era code, Anno Mundi, with code `"am"` |
53 | | /// |
54 | | /// # Month codes |
55 | | /// |
56 | | /// This calendar is a lunisolar calendar and thus has a leap month. It supports codes `"M01"-"M12"` |
57 | | /// for regular months, and the leap month Adar I being coded as `"M05L"`. |
58 | | /// |
59 | | /// [`FormattableMonth`] has slightly divergent behavior: because the regular month Adar is formatted |
60 | | /// as "Adar II" in a leap year, this calendar will produce the special code `"M06L"` in any [`FormattableMonth`] |
61 | | /// objects it creates. |
62 | | /// |
63 | | /// [Hebrew calendar]: https://en.wikipedia.org/wiki/Hebrew_calendar |
64 | | #[derive(Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord, Default)] |
65 | | #[allow(clippy::exhaustive_structs)] // unit struct |
66 | | pub struct Hebrew; |
67 | | |
68 | | /// The inner date type used for representing [`Date`]s of [`Hebrew`]. See [`Date`] and [`Hebrew`] for more details. |
69 | | #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)] |
70 | | pub struct HebrewDateInner(ArithmeticDate<Hebrew>); |
71 | | |
72 | | impl Hebrew { |
73 | | /// Construct a new [`Hebrew`] |
74 | 0 | pub fn new() -> Self { |
75 | 0 | Hebrew |
76 | 0 | } |
77 | | |
78 | | /// Construct a new [`Hebrew`] |
79 | | /// |
80 | | /// This is deprecated since the new implementation does not need precomputed data. |
81 | | #[deprecated(since = "1.5.0", note = "Use Hebrew::new()")] |
82 | 0 | pub fn new_always_calculating() -> Self { |
83 | 0 | Hebrew |
84 | 0 | } |
85 | | } |
86 | | |
87 | | #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] |
88 | | pub(crate) struct HebrewYearInfo { |
89 | | keviyah: Keviyah, |
90 | | prev_keviyah: Keviyah, |
91 | | } |
92 | | |
93 | | impl HebrewYearInfo { |
94 | | /// Convenience method to compute for a given year. Don't use this if you actually need |
95 | | /// a YearInfo that you want to call .new_year() on. |
96 | | /// |
97 | | /// This can potentially be optimized with adjacent-year knowledge, but it's complex |
98 | | #[inline] |
99 | 0 | fn compute(h_year: i32) -> Self { |
100 | 0 | let keviyah = YearInfo::compute_for(h_year).keviyah; |
101 | 0 | Self::compute_with_keviyah(keviyah, h_year) |
102 | 0 | } |
103 | | /// Compute for a given year when the keviyah is already known |
104 | | #[inline] |
105 | 0 | fn compute_with_keviyah(keviyah: Keviyah, h_year: i32) -> Self { |
106 | 0 | let prev_keviyah = YearInfo::compute_for(h_year - 1).keviyah; |
107 | 0 | Self { |
108 | 0 | keviyah, |
109 | 0 | prev_keviyah, |
110 | 0 | } |
111 | 0 | } |
112 | | } |
113 | | // HEBREW CALENDAR |
114 | | |
115 | | impl CalendarArithmetic for Hebrew { |
116 | | type YearInfo = HebrewYearInfo; |
117 | | |
118 | 0 | fn month_days(_h_year: i32, ordinal_month: u8, info: HebrewYearInfo) -> u8 { |
119 | 0 | info.keviyah.month_len(ordinal_month) |
120 | 0 | } |
121 | | |
122 | 0 | fn months_for_every_year(_h_year: i32, info: HebrewYearInfo) -> u8 { |
123 | 0 | if info.keviyah.is_leap() { |
124 | 0 | 13 |
125 | | } else { |
126 | 0 | 12 |
127 | | } |
128 | 0 | } |
129 | | |
130 | 0 | fn days_in_provided_year(_h_year: i32, info: HebrewYearInfo) -> u16 { |
131 | 0 | info.keviyah.year_length() |
132 | 0 | } |
133 | | |
134 | 0 | fn is_leap_year(_h_year: i32, info: HebrewYearInfo) -> bool { |
135 | 0 | info.keviyah.is_leap() |
136 | 0 | } |
137 | | |
138 | 0 | fn last_month_day_in_year(_h_year: i32, info: HebrewYearInfo) -> (u8, u8) { |
139 | 0 | info.keviyah.last_month_day_in_year() |
140 | 0 | } |
141 | | } |
142 | | |
143 | | impl PrecomputedDataSource<HebrewYearInfo> for () { |
144 | 0 | fn load_or_compute_info(&self, h_year: i32) -> HebrewYearInfo { |
145 | 0 | HebrewYearInfo::compute(h_year) |
146 | 0 | } |
147 | | } |
148 | | |
149 | | impl Calendar for Hebrew { |
150 | | type DateInner = HebrewDateInner; |
151 | | |
152 | 0 | fn date_from_codes( |
153 | 0 | &self, |
154 | 0 | era: types::Era, |
155 | 0 | year: i32, |
156 | 0 | month_code: types::MonthCode, |
157 | 0 | day: u8, |
158 | 0 | ) -> Result<Self::DateInner, CalendarError> { |
159 | 0 | let year = if era.0 == tinystr!(16, "hebrew") || era.0 == tinystr!(16, "am") { |
160 | 0 | year |
161 | | } else { |
162 | 0 | return Err(CalendarError::UnknownEra(era.0, self.debug_name())); |
163 | | }; |
164 | | |
165 | 0 | let year_info = HebrewYearInfo::compute(year); |
166 | 0 |
|
167 | 0 | let is_leap_year = year_info.keviyah.is_leap(); |
168 | 0 |
|
169 | 0 | let month_code_str = month_code.0.as_str(); |
170 | | |
171 | 0 | let month_ordinal = if is_leap_year { |
172 | 0 | match month_code_str { |
173 | 0 | "M01" => 1, |
174 | 0 | "M02" => 2, |
175 | 0 | "M03" => 3, |
176 | 0 | "M04" => 4, |
177 | 0 | "M05" => 5, |
178 | 0 | "M05L" => 6, |
179 | | // M06L is the formatting era code used for Adar II |
180 | 0 | "M06" | "M06L" => 7, |
181 | 0 | "M07" => 8, |
182 | 0 | "M08" => 9, |
183 | 0 | "M09" => 10, |
184 | 0 | "M10" => 11, |
185 | 0 | "M11" => 12, |
186 | 0 | "M12" => 13, |
187 | | _ => { |
188 | 0 | return Err(CalendarError::UnknownMonthCode( |
189 | 0 | month_code.0, |
190 | 0 | self.debug_name(), |
191 | 0 | )) |
192 | | } |
193 | | } |
194 | | } else { |
195 | 0 | match month_code_str { |
196 | 0 | "M01" => 1, |
197 | 0 | "M02" => 2, |
198 | 0 | "M03" => 3, |
199 | 0 | "M04" => 4, |
200 | 0 | "M05" => 5, |
201 | 0 | "M06" => 6, |
202 | 0 | "M07" => 7, |
203 | 0 | "M08" => 8, |
204 | 0 | "M09" => 9, |
205 | 0 | "M10" => 10, |
206 | 0 | "M11" => 11, |
207 | 0 | "M12" => 12, |
208 | | _ => { |
209 | 0 | return Err(CalendarError::UnknownMonthCode( |
210 | 0 | month_code.0, |
211 | 0 | self.debug_name(), |
212 | 0 | )) |
213 | | } |
214 | | } |
215 | | }; |
216 | | |
217 | 0 | ArithmeticDate::new_from_ordinals_with_info(year, month_ordinal, day, year_info) |
218 | 0 | .map(HebrewDateInner) |
219 | 0 | } |
220 | | |
221 | 0 | fn date_from_iso(&self, iso: Date<Iso>) -> Self::DateInner { |
222 | 0 | let fixed_iso = Iso::fixed_from_iso(*iso.inner()); |
223 | 0 | let (year_info, h_year) = YearInfo::year_containing_rd(fixed_iso); |
224 | 0 | // Obtaining a 1-indexed day-in-year value |
225 | 0 | let day = fixed_iso - year_info.new_year() + 1; |
226 | 0 | let day = u16::try_from(day).unwrap_or(u16::MAX); |
227 | 0 |
|
228 | 0 | let year_info = HebrewYearInfo::compute_with_keviyah(year_info.keviyah, h_year); |
229 | 0 | let (month, day) = year_info.keviyah.month_day_for(day); |
230 | 0 | HebrewDateInner(ArithmeticDate::new_unchecked_with_info( |
231 | 0 | h_year, month, day, year_info, |
232 | 0 | )) |
233 | 0 | } |
234 | | |
235 | 0 | fn date_to_iso(&self, date: &Self::DateInner) -> Date<Iso> { |
236 | 0 | let year_info = date.0.year_info.keviyah.year_info(date.0.year); |
237 | 0 |
|
238 | 0 | let ny = year_info.new_year(); |
239 | 0 | let days_preceding = year_info.keviyah.days_preceding(date.0.month); |
240 | 0 |
|
241 | 0 | // Need to subtract 1 since the new year is itself in this year |
242 | 0 | Iso::iso_from_fixed(ny + i64::from(days_preceding) + i64::from(date.0.day) - 1) |
243 | 0 | } |
244 | | |
245 | 0 | fn months_in_year(&self, date: &Self::DateInner) -> u8 { |
246 | 0 | date.0.months_in_year() |
247 | 0 | } |
248 | | |
249 | 0 | fn days_in_year(&self, date: &Self::DateInner) -> u16 { |
250 | 0 | date.0.days_in_year() |
251 | 0 | } |
252 | | |
253 | 0 | fn days_in_month(&self, date: &Self::DateInner) -> u8 { |
254 | 0 | date.0.days_in_month() |
255 | 0 | } |
256 | | |
257 | 0 | fn offset_date(&self, date: &mut Self::DateInner, offset: DateDuration<Self>) { |
258 | 0 | date.0.offset_date(offset, &()) |
259 | 0 | } |
260 | | |
261 | 0 | fn until( |
262 | 0 | &self, |
263 | 0 | date1: &Self::DateInner, |
264 | 0 | date2: &Self::DateInner, |
265 | 0 | _calendar2: &Self, |
266 | 0 | _largest_unit: DateDurationUnit, |
267 | 0 | _smallest_unit: DateDurationUnit, |
268 | 0 | ) -> DateDuration<Self> { |
269 | 0 | date1.0.until(date2.0, _largest_unit, _smallest_unit) |
270 | 0 | } |
271 | | |
272 | 0 | fn debug_name(&self) -> &'static str { |
273 | 0 | "Hebrew" |
274 | 0 | } |
275 | | |
276 | 0 | fn year(&self, date: &Self::DateInner) -> types::FormattableYear { |
277 | 0 | Self::year_as_hebrew(date.0.year) |
278 | 0 | } |
279 | | |
280 | 0 | fn is_in_leap_year(&self, date: &Self::DateInner) -> bool { |
281 | 0 | Self::is_leap_year(date.0.year, date.0.year_info) |
282 | 0 | } |
283 | | |
284 | 0 | fn month(&self, date: &Self::DateInner) -> FormattableMonth { |
285 | 0 | let mut ordinal = date.0.month; |
286 | 0 | let is_leap_year = Self::is_leap_year(date.0.year, date.0.year_info); |
287 | 0 |
|
288 | 0 | if is_leap_year { |
289 | 0 | if ordinal == 6 { |
290 | 0 | return types::FormattableMonth { |
291 | 0 | ordinal: ordinal as u32, |
292 | 0 | code: types::MonthCode(tinystr!(4, "M05L")), |
293 | 0 | }; |
294 | 0 | } else if ordinal == 7 { |
295 | 0 | return types::FormattableMonth { |
296 | 0 | ordinal: ordinal as u32, |
297 | 0 | code: types::MonthCode(tinystr!(4, "M06L")), |
298 | 0 | }; |
299 | 0 | } |
300 | 0 | } |
301 | | |
302 | 0 | if is_leap_year && ordinal > 6 { |
303 | 0 | ordinal -= 1; |
304 | 0 | } |
305 | | |
306 | 0 | let code = match ordinal { |
307 | 0 | 1 => tinystr!(4, "M01"), |
308 | 0 | 2 => tinystr!(4, "M02"), |
309 | 0 | 3 => tinystr!(4, "M03"), |
310 | 0 | 4 => tinystr!(4, "M04"), |
311 | 0 | 5 => tinystr!(4, "M05"), |
312 | 0 | 6 => tinystr!(4, "M06"), |
313 | 0 | 7 => tinystr!(4, "M07"), |
314 | 0 | 8 => tinystr!(4, "M08"), |
315 | 0 | 9 => tinystr!(4, "M09"), |
316 | 0 | 10 => tinystr!(4, "M10"), |
317 | 0 | 11 => tinystr!(4, "M11"), |
318 | 0 | 12 => tinystr!(4, "M12"), |
319 | 0 | _ => tinystr!(4, "und"), |
320 | | }; |
321 | | |
322 | 0 | types::FormattableMonth { |
323 | 0 | ordinal: date.0.month as u32, |
324 | 0 | code: types::MonthCode(code), |
325 | 0 | } |
326 | 0 | } |
327 | | |
328 | 0 | fn day_of_month(&self, date: &Self::DateInner) -> types::DayOfMonth { |
329 | 0 | date.0.day_of_month() |
330 | 0 | } |
331 | | |
332 | 0 | fn day_of_year_info(&self, date: &Self::DateInner) -> types::DayOfYearInfo { |
333 | 0 | let prev_year = date.0.year.saturating_sub(1); |
334 | 0 | let next_year = date.0.year.saturating_add(1); |
335 | 0 | types::DayOfYearInfo { |
336 | 0 | day_of_year: date.0.day_of_year(), |
337 | 0 | days_in_year: date.0.days_in_year(), |
338 | 0 | prev_year: Self::year_as_hebrew(prev_year), |
339 | 0 | days_in_prev_year: date.0.year_info.prev_keviyah.year_length(), |
340 | 0 | next_year: Self::year_as_hebrew(next_year), |
341 | 0 | } |
342 | 0 | } |
343 | 0 | fn any_calendar_kind(&self) -> Option<AnyCalendarKind> { |
344 | 0 | Some(AnyCalendarKind::Hebrew) |
345 | 0 | } |
346 | | } |
347 | | |
348 | | impl Hebrew { |
349 | 0 | fn year_as_hebrew(civil_year: i32) -> types::FormattableYear { |
350 | 0 | types::FormattableYear { |
351 | 0 | era: types::Era(tinystr!(16, "hebrew")), |
352 | 0 | number: civil_year, |
353 | 0 | cyclic: None, |
354 | 0 | related_iso: None, |
355 | 0 | } |
356 | 0 | } |
357 | | } |
358 | | |
359 | | impl Date<Hebrew> { |
360 | | /// Construct new Hebrew Date. |
361 | | /// |
362 | | /// This datetime will not use any precomputed calendrical calculations, |
363 | | /// one that loads such data from a provider will be added in the future (#3933) |
364 | | /// |
365 | | /// |
366 | | /// ```rust |
367 | | /// use icu::calendar::Date; |
368 | | /// |
369 | | /// let date_hebrew = Date::try_new_hebrew_date(3425, 4, 25) |
370 | | /// .expect("Failed to initialize Hebrew Date instance."); |
371 | | /// |
372 | | /// assert_eq!(date_hebrew.year().number, 3425); |
373 | | /// assert_eq!(date_hebrew.month().ordinal, 4); |
374 | | /// assert_eq!(date_hebrew.day_of_month().0, 25); |
375 | | /// ``` |
376 | 0 | pub fn try_new_hebrew_date( |
377 | 0 | year: i32, |
378 | 0 | month: u8, |
379 | 0 | day: u8, |
380 | 0 | ) -> Result<Date<Hebrew>, CalendarError> { |
381 | 0 | let year_info = HebrewYearInfo::compute(year); |
382 | 0 |
|
383 | 0 | ArithmeticDate::new_from_ordinals_with_info(year, month, day, year_info) |
384 | 0 | .map(HebrewDateInner) |
385 | 0 | .map(|inner| Date::from_raw(inner, Hebrew)) |
386 | 0 | } |
387 | | } |
388 | | |
389 | | impl<A: AsCalendar<Calendar = Hebrew>> Date<A> { |
390 | | /// Construct new Hebrew Date given a calendar. |
391 | | /// |
392 | | /// This is deprecated since `Hebrew` is a zero-sized type, |
393 | | /// but if you find yourself needing this functionality please let us know. |
394 | | #[deprecated(since = "1.5.0", note = "Use Date::try_new_hebrew_date()")] |
395 | 0 | pub fn try_new_hebrew_date_with_calendar( |
396 | 0 | year: i32, |
397 | 0 | month: u8, |
398 | 0 | day: u8, |
399 | 0 | calendar: A, |
400 | 0 | ) -> Result<Date<A>, CalendarError> { |
401 | 0 | let year_info = HebrewYearInfo::compute(year); |
402 | 0 |
|
403 | 0 | ArithmeticDate::new_from_ordinals_with_info(year, month, day, year_info) |
404 | 0 | .map(HebrewDateInner) |
405 | 0 | .map(|inner| Date::from_raw(inner, calendar)) |
406 | 0 | } |
407 | | } |
408 | | |
409 | | impl DateTime<Hebrew> { |
410 | | /// Construct a new Hebrew datetime from integers. |
411 | | /// |
412 | | /// ```rust |
413 | | /// use icu::calendar::DateTime; |
414 | | /// |
415 | | /// let datetime_hebrew = |
416 | | /// DateTime::try_new_hebrew_datetime(4201, 10, 11, 13, 1, 0) |
417 | | /// .expect("Failed to initialize Hebrew DateTime instance"); |
418 | | /// |
419 | | /// assert_eq!(datetime_hebrew.date.year().number, 4201); |
420 | | /// assert_eq!(datetime_hebrew.date.month().ordinal, 10); |
421 | | /// assert_eq!(datetime_hebrew.date.day_of_month().0, 11); |
422 | | /// assert_eq!(datetime_hebrew.time.hour.number(), 13); |
423 | | /// assert_eq!(datetime_hebrew.time.minute.number(), 1); |
424 | | /// assert_eq!(datetime_hebrew.time.second.number(), 0); |
425 | | /// ``` |
426 | 0 | pub fn try_new_hebrew_datetime( |
427 | 0 | year: i32, |
428 | 0 | month: u8, |
429 | 0 | day: u8, |
430 | 0 | hour: u8, |
431 | 0 | minute: u8, |
432 | 0 | second: u8, |
433 | 0 | ) -> Result<DateTime<Hebrew>, CalendarError> { |
434 | 0 | Ok(DateTime { |
435 | 0 | date: Date::try_new_hebrew_date(year, month, day)?, |
436 | 0 | time: Time::try_new(hour, minute, second, 0)?, |
437 | | }) |
438 | 0 | } |
439 | | } |
440 | | |
441 | | impl<A: AsCalendar<Calendar = Hebrew>> DateTime<A> { |
442 | | /// Construct new Hebrew DateTime given a calendar. |
443 | | /// |
444 | | /// This is deprecated since `Hebrew` is a zero-sized type, |
445 | | /// but if you find yourself needing this functionality please let us know. |
446 | | #[deprecated(since = "1.5.0", note = "Use DateTime::try_new_hebrew_datetime()")] |
447 | 0 | pub fn try_new_hebrew_datetime_with_calendar( |
448 | 0 | year: i32, |
449 | 0 | month: u8, |
450 | 0 | day: u8, |
451 | 0 | hour: u8, |
452 | 0 | minute: u8, |
453 | 0 | second: u8, |
454 | 0 | calendar: A, |
455 | 0 | ) -> Result<DateTime<A>, CalendarError> { |
456 | 0 | #[allow(deprecated)] |
457 | 0 | Ok(DateTime { |
458 | 0 | date: Date::try_new_hebrew_date_with_calendar(year, month, day, calendar)?, |
459 | 0 | time: Time::try_new(hour, minute, second, 0)?, |
460 | | }) |
461 | 0 | } |
462 | | } |
463 | | |
464 | | #[cfg(test)] |
465 | | mod tests { |
466 | | |
467 | | use super::*; |
468 | | use crate::types::{Era, MonthCode}; |
469 | | use calendrical_calculations::hebrew_keviyah::*; |
470 | | |
471 | | // Sentinel value for Adar I |
472 | | // We're using normalized month values here so that we can use constants. These do not |
473 | | // distinguish between the different Adars. We add an out-of-range sentinel value of 13 to |
474 | | // specifically talk about Adar I in a leap year |
475 | | const ADARI: u8 = 13; |
476 | | |
477 | | /// The leap years used in the tests below |
478 | | const LEAP_YEARS_IN_TESTS: [i32; 1] = [5782]; |
479 | | /// (iso, hebrew) pairs of testcases. If any of the years here |
480 | | /// are leap years please add them to LEAP_YEARS_IN_TESTS (we have this manually |
481 | | /// so we don't end up exercising potentially buggy codepaths to test this) |
482 | | #[allow(clippy::type_complexity)] |
483 | | const ISO_HEBREW_DATE_PAIRS: [((i32, u8, u8), (i32, u8, u8)); 48] = [ |
484 | | ((2021, 1, 10), (5781, TEVET, 26)), |
485 | | ((2021, 1, 25), (5781, SHEVAT, 12)), |
486 | | ((2021, 2, 10), (5781, SHEVAT, 28)), |
487 | | ((2021, 2, 25), (5781, ADAR, 13)), |
488 | | ((2021, 3, 10), (5781, ADAR, 26)), |
489 | | ((2021, 3, 25), (5781, NISAN, 12)), |
490 | | ((2021, 4, 10), (5781, NISAN, 28)), |
491 | | ((2021, 4, 25), (5781, IYYAR, 13)), |
492 | | ((2021, 5, 10), (5781, IYYAR, 28)), |
493 | | ((2021, 5, 25), (5781, SIVAN, 14)), |
494 | | ((2021, 6, 10), (5781, SIVAN, 30)), |
495 | | ((2021, 6, 25), (5781, TAMMUZ, 15)), |
496 | | ((2021, 7, 10), (5781, AV, 1)), |
497 | | ((2021, 7, 25), (5781, AV, 16)), |
498 | | ((2021, 8, 10), (5781, ELUL, 2)), |
499 | | ((2021, 8, 25), (5781, ELUL, 17)), |
500 | | ((2021, 9, 10), (5782, TISHREI, 4)), |
501 | | ((2021, 9, 25), (5782, TISHREI, 19)), |
502 | | ((2021, 10, 10), (5782, ḤESHVAN, 4)), |
503 | | ((2021, 10, 25), (5782, ḤESHVAN, 19)), |
504 | | ((2021, 11, 10), (5782, KISLEV, 6)), |
505 | | ((2021, 11, 25), (5782, KISLEV, 21)), |
506 | | ((2021, 12, 10), (5782, TEVET, 6)), |
507 | | ((2021, 12, 25), (5782, TEVET, 21)), |
508 | | ((2022, 1, 10), (5782, SHEVAT, 8)), |
509 | | ((2022, 1, 25), (5782, SHEVAT, 23)), |
510 | | ((2022, 2, 10), (5782, ADARI, 9)), |
511 | | ((2022, 2, 25), (5782, ADARI, 24)), |
512 | | ((2022, 3, 10), (5782, ADAR, 7)), |
513 | | ((2022, 3, 25), (5782, ADAR, 22)), |
514 | | ((2022, 4, 10), (5782, NISAN, 9)), |
515 | | ((2022, 4, 25), (5782, NISAN, 24)), |
516 | | ((2022, 5, 10), (5782, IYYAR, 9)), |
517 | | ((2022, 5, 25), (5782, IYYAR, 24)), |
518 | | ((2022, 6, 10), (5782, SIVAN, 11)), |
519 | | ((2022, 6, 25), (5782, SIVAN, 26)), |
520 | | ((2022, 7, 10), (5782, TAMMUZ, 11)), |
521 | | ((2022, 7, 25), (5782, TAMMUZ, 26)), |
522 | | ((2022, 8, 10), (5782, AV, 13)), |
523 | | ((2022, 8, 25), (5782, AV, 28)), |
524 | | ((2022, 9, 10), (5782, ELUL, 14)), |
525 | | ((2022, 9, 25), (5782, ELUL, 29)), |
526 | | ((2022, 10, 10), (5783, TISHREI, 15)), |
527 | | ((2022, 10, 25), (5783, TISHREI, 30)), |
528 | | ((2022, 11, 10), (5783, ḤESHVAN, 16)), |
529 | | ((2022, 11, 25), (5783, KISLEV, 1)), |
530 | | ((2022, 12, 10), (5783, KISLEV, 16)), |
531 | | ((2022, 12, 25), (5783, TEVET, 1)), |
532 | | ]; |
533 | | |
534 | | #[test] |
535 | | fn test_conversions() { |
536 | | for ((iso_y, iso_m, iso_d), (y, m, d)) in ISO_HEBREW_DATE_PAIRS.into_iter() { |
537 | | let iso_date = Date::try_new_iso_date(iso_y, iso_m, iso_d).unwrap(); |
538 | | let month_code = if m == ADARI { |
539 | | MonthCode(tinystr!(4, "M05L")) |
540 | | } else { |
541 | | MonthCode::new_normal(m).unwrap() |
542 | | }; |
543 | | let hebrew_date = |
544 | | Date::try_new_from_codes(tinystr!(16, "am").into(), y, month_code, d, Hebrew) |
545 | | .expect("Date should parse"); |
546 | | |
547 | | let iso_to_hebrew = iso_date.to_calendar(Hebrew); |
548 | | |
549 | | let hebrew_to_iso = hebrew_date.to_calendar(Iso); |
550 | | |
551 | | assert_eq!( |
552 | | hebrew_to_iso, iso_date, |
553 | | "Failed comparing to-ISO value for {hebrew_date:?} => {iso_date:?}" |
554 | | ); |
555 | | assert_eq!( |
556 | | iso_to_hebrew, hebrew_date, |
557 | | "Failed comparing to-hebrew value for {iso_date:?} => {hebrew_date:?}" |
558 | | ); |
559 | | |
560 | | let ordinal_month = if LEAP_YEARS_IN_TESTS.contains(&y) { |
561 | | if m == ADARI { |
562 | | ADAR |
563 | | } else if m >= ADAR { |
564 | | m + 1 |
565 | | } else { |
566 | | m |
567 | | } |
568 | | } else { |
569 | | assert!(m != ADARI); |
570 | | m |
571 | | }; |
572 | | |
573 | | let ordinal_hebrew_date = Date::try_new_hebrew_date(y, ordinal_month, d) |
574 | | .expect("Construction of date must succeed"); |
575 | | |
576 | | assert_eq!(ordinal_hebrew_date, hebrew_date, "Hebrew date construction from codes and ordinals should work the same for {hebrew_date:?}"); |
577 | | } |
578 | | } |
579 | | |
580 | | #[test] |
581 | | fn test_icu_bug_22441() { |
582 | | let yi = YearInfo::compute_for(88369); |
583 | | assert_eq!(yi.keviyah.year_length(), 383); |
584 | | } |
585 | | |
586 | | #[test] |
587 | | fn test_weekdays() { |
588 | | // https://github.com/unicode-org/icu4x/issues/4893 |
589 | | let cal = Hebrew::new(); |
590 | | let era = "am".parse::<Era>().unwrap(); |
591 | | let month_code = "M01".parse::<MonthCode>().unwrap(); |
592 | | let dt = cal.date_from_codes(era, 3760, month_code, 1).unwrap(); |
593 | | |
594 | | // Should be Saturday per: |
595 | | // https://www.hebcal.com/converter?hd=1&hm=Tishrei&hy=3760&h2g=1 |
596 | | assert_eq!(6, cal.day_of_week(&dt) as usize); |
597 | | } |
598 | | } |