Coverage Report

Created: 2025-08-26 06:41

/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
}