Coverage Report

Created: 2026-01-09 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/calendrical_calculations-0.1.2/src/hebrew.rs
Line
Count
Source
1
// This file is part of ICU4X.
2
//
3
// The contents of this file implement algorithms from Calendrical Calculations
4
// by Reingold & Dershowitz, Cambridge University Press, 4th edition (2018),
5
// which have been released as Lisp code at <https://github.com/EdReingold/calendar-code2/>
6
// under the Apache-2.0 license. Accordingly, this file is released under
7
// the Apache License, Version 2.0 which can be found at the calendrical_calculations
8
// package root or at http://www.apache.org/licenses/LICENSE-2.0.
9
10
use crate::helpers::{final_func, i64_to_i32, next_u8};
11
use crate::rata_die::{Moment, RataDie};
12
#[allow(unused_imports)]
13
use core_maths::*;
14
15
/// Lisp code reference: <https://github.com/EdReingold/calendar-code2/blob/main/calendar.l#L2206>
16
pub(crate) const FIXED_HEBREW_EPOCH: RataDie =
17
    crate::julian::fixed_from_julian_book_version(-3761, 10, 7);
18
19
/// Biblical Hebrew dates. The months are reckoned a bit strangely, with the new year occurring on
20
/// Tishri (as in the civil calendar) but the months being numbered in a different order
21
#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq, PartialOrd, Ord)]
22
#[allow(clippy::exhaustive_structs)]
23
pub struct BookHebrew {
24
    /// The year
25
    pub year: i32,
26
    /// The month
27
    pub month: u8,
28
    /// The day
29
    pub day: u8,
30
}
31
32
// The BookHebrew Months
33
/// The biblical month number used for the month of Nisan
34
pub const NISAN: u8 = 1;
35
/// The biblical month number used for the month of Iyyar
36
pub const IYYAR: u8 = 2;
37
/// The biblical month number used for the month of Sivan
38
pub const SIVAN: u8 = 3;
39
/// The biblical month number used for the month of Tammuz
40
pub const TAMMUZ: u8 = 4;
41
/// The biblical month number used for the month of Av
42
pub const AV: u8 = 5;
43
/// The biblical month number used for the month of Elul
44
pub const ELUL: u8 = 6;
45
/// The biblical month number used for the month of Tishri
46
pub const TISHRI: u8 = 7;
47
/// The biblical month number used for the month of Marheshvan
48
pub const MARHESHVAN: u8 = 8;
49
/// The biblical month number used for the month of Kislev
50
pub const KISLEV: u8 = 9;
51
/// The biblical month number used for the month of Tevet
52
pub const TEVET: u8 = 10;
53
/// The biblical month number used for the month of Shevat
54
pub const SHEVAT: u8 = 11;
55
/// The biblical month number used for the month of Adar (and Adar I)
56
pub const ADAR: u8 = 12;
57
/// The biblical month number used for the month of Adar II
58
pub const ADARII: u8 = 13;
59
60
// BIBLICAL HEBREW CALENDAR FUNCTIONS
61
62
impl BookHebrew {
63
    /// The civil calendar has the same year and day numbering as the book one, but the months are numbered
64
    /// differently
65
0
    pub fn to_civil_date(self) -> (i32, u8, u8) {
66
0
        let biblical_month = self.month;
67
0
        let biblical_year = self.year;
68
        let mut civil_month;
69
0
        civil_month = (biblical_month + 6) % 12;
70
71
0
        if civil_month == 0 {
72
0
            civil_month = 12;
73
0
        }
74
75
0
        if Self::is_hebrew_leap_year(biblical_year) && biblical_month < TISHRI {
76
0
            civil_month += 1;
77
0
        }
78
0
        (biblical_year, civil_month, self.day)
79
0
    }
80
81
    /// The civil calendar has the same year and day numbering as the book one, but the months are numbered
82
    /// differently
83
0
    pub fn from_civil_date(civil_year: i32, civil_month: u8, civil_day: u8) -> Self {
84
        let mut biblical_month;
85
86
0
        if civil_month <= 6 {
87
0
            biblical_month = civil_month + 6; //  months 1-6 correspond to biblical months 7-12
88
0
        } else {
89
0
            biblical_month = civil_month - 6; //  months 7-12 correspond to biblical months 1-6
90
0
            if Self::is_hebrew_leap_year(civil_year) {
91
0
                biblical_month -= 1
92
0
            }
93
0
            if biblical_month == 0 {
94
0
                // Special case for Adar II in a leap year
95
0
                biblical_month = 13;
96
0
            }
97
        }
98
99
0
        BookHebrew {
100
0
            year: civil_year,
101
0
            month: biblical_month,
102
0
            day: civil_day,
103
0
        }
104
0
    }
105
    // Moment of mean conjunction (New Moon) of h_month in BookHebrew
106
    /// Lisp code reference: <https://github.com/EdReingold/calendar-code2/blob/main/calendar.l#L2244>
107
    #[allow(dead_code)]
108
0
    pub(crate) fn molad(book_year: i32, book_month: u8) -> Moment {
109
0
        let y = if book_month < TISHRI {
110
0
            book_year + 1
111
        } else {
112
0
            book_year
113
        }; // Treat Nisan as start of year
114
115
0
        let months_elapsed = (book_month as f64 - TISHRI as f64) // Months this year
116
0
            + ((235.0 * y as f64 - 234.0) / 19.0).floor(); // Months until New Year.
117
118
0
        Moment::new(
119
0
            FIXED_HEBREW_EPOCH.to_f64_date() - (876.0 / 25920.0)
120
0
                + months_elapsed * (29.0 + (1.0 / 2.0) + (793.0 / 25920.0)),
121
        )
122
0
    }
123
124
    // ADAR = 12, ADARII = 13
125
    /// Lisp code reference: <https://github.com/EdReingold/calendar-code2/blob/main/calendar.l#L2217>
126
    #[allow(dead_code)]
127
0
    fn last_month_of_book_hebrew_year(book_year: i32) -> u8 {
128
0
        if Self::is_hebrew_leap_year(book_year) {
129
0
            ADARII
130
        } else {
131
0
            ADAR
132
        }
133
0
    }
134
135
    // Number of days elapsed from the (Sunday) noon prior to the epoch of the BookHebrew Calendar to the molad of Tishri of BookHebrew year (h_year) or one day later
136
    /// Lisp code reference: <https://github.com/EdReingold/calendar-code2/blob/main/calendar.l#L2261>
137
0
    fn book_hebrew_calendar_elapsed_days(book_year: i32) -> i32 {
138
0
        let months_elapsed = ((235.0 * book_year as f64 - 234.0) / 19.0).floor() as i64;
139
0
        let parts_elapsed = 12084 + 13753 * months_elapsed;
140
0
        let days = 29 * months_elapsed + (parts_elapsed as f64 / 25920.0).floor() as i64;
141
142
0
        if (3 * (days + 1)).rem_euclid(7) < 3 {
143
0
            days as i32 + 1
144
        } else {
145
0
            days as i32
146
        }
147
0
    }
148
149
    // Delays to start of BookHebrew year to keep ordinary year in range 353-356 and leap year in range 383-386
150
    /// Lisp code reference: <https://github.com/EdReingold/calendar-code2/blob/main/calendar.l#L2301>
151
0
    fn book_hebrew_year_length_correction(book_year: i32) -> u8 {
152
0
        let ny0 = Self::book_hebrew_calendar_elapsed_days(book_year - 1);
153
0
        let ny1 = Self::book_hebrew_calendar_elapsed_days(book_year);
154
0
        let ny2 = Self::book_hebrew_calendar_elapsed_days(book_year + 1);
155
156
0
        if (ny2 - ny1) == 356 {
157
0
            2
158
0
        } else if (ny1 - ny0) == 382 {
159
0
            1
160
        } else {
161
0
            0
162
        }
163
0
    }
164
165
    // Fixed date of BookHebrew new year
166
    /// Lisp code reference: <https://github.com/EdReingold/calendar-code2/blob/main/calendar.l#L2294>
167
0
    pub fn book_hebrew_new_year(book_year: i32) -> RataDie {
168
0
        RataDie::new(
169
0
            FIXED_HEBREW_EPOCH.to_i64_date()
170
0
                + Self::book_hebrew_calendar_elapsed_days(book_year) as i64
171
0
                + Self::book_hebrew_year_length_correction(book_year) as i64,
172
        )
173
0
    }
174
175
    /// Lisp code reference: <https://github.com/EdReingold/calendar-code2/blob/main/calendar.l#L2315>
176
0
    pub fn days_in_book_hebrew_year(book_year: i32) -> u16 {
177
0
        (Self::book_hebrew_new_year(1 + book_year) - Self::book_hebrew_new_year(book_year)) as u16
178
0
    }
179
180
    /// Lisp code reference: <https://github.com/EdReingold/calendar-code2/blob/1ee51ecfaae6f856b0d7de3e36e9042100b4f424/calendar.l#L2275-L2278>
181
0
    pub fn is_hebrew_leap_year(book_year: i32) -> bool {
182
0
        (7 * book_year + 1).rem_euclid(19) < 7
183
0
    }
184
185
    // True if the month Marheshvan is going to be long in given BookHebrew year
186
    /// Lisp code reference: <https://github.com/EdReingold/calendar-code2/blob/main/calendar.l#L2321>
187
    #[allow(dead_code)]
188
0
    fn is_long_marheshvan(book_year: i32) -> bool {
189
0
        let long_marheshavan_year_lengths = [355, 385];
190
0
        long_marheshavan_year_lengths.contains(&Self::days_in_book_hebrew_year(book_year))
191
0
    }
192
193
    // True if the month Kislve is going to be short in given BookHebrew year
194
    /// Lisp code reference: <https://github.com/EdReingold/calendar-code2/blob/main/calendar.l#L2326>
195
    #[allow(dead_code)]
196
0
    fn is_short_kislev(book_year: i32) -> bool {
197
0
        let short_kislev_year_lengths = [353, 383];
198
0
        short_kislev_year_lengths.contains(&Self::days_in_book_hebrew_year(book_year))
199
0
    }
200
201
    // Last day of month (h_month) in BookHebrew year (book_year)
202
    /// Lisp code reference: <https://github.com/EdReingold/calendar-code2/blob/main/calendar.l#L2230>
203
0
    pub fn last_day_of_book_hebrew_month(book_year: i32, book_month: u8) -> u8 {
204
0
        match book_month {
205
0
            IYYAR | TAMMUZ | ELUL | TEVET | ADARII => 29,
206
            ADAR => {
207
0
                if !Self::is_hebrew_leap_year(book_year) {
208
0
                    29
209
                } else {
210
0
                    30
211
                }
212
            }
213
            MARHESHVAN => {
214
0
                if !Self::is_long_marheshvan(book_year) {
215
0
                    29
216
                } else {
217
0
                    30
218
                }
219
            }
220
            KISLEV => {
221
0
                if Self::is_short_kislev(book_year) {
222
0
                    29
223
                } else {
224
0
                    30
225
                }
226
            }
227
0
            _ => 30,
228
        }
229
0
    }
230
231
    /// Lisp code reference: <https://github.com/EdReingold/calendar-code2/blob/main/calendar.l#L2331>
232
0
    pub fn fixed_from_book_hebrew(date: BookHebrew) -> RataDie {
233
0
        let book_year = date.year;
234
0
        let book_month = date.month;
235
0
        let book_day = date.day;
236
237
0
        let mut total_days = Self::book_hebrew_new_year(book_year) + book_day.into() - 1; // (day - 1) Days so far this month.
238
239
0
        if book_month < TISHRI {
240
            // Then add days in prior months this year before
241
0
            for m in
242
0
                (TISHRI..=Self::last_month_of_book_hebrew_year(book_year)).chain(NISAN..book_month)
243
0
            {
244
0
                total_days += Self::last_day_of_book_hebrew_month(book_year, m).into();
245
0
            }
246
        } else {
247
            // Else add days in prior months this year
248
0
            for m in TISHRI..book_month {
249
0
                total_days += Self::last_day_of_book_hebrew_month(book_year, m).into();
250
0
            }
251
        }
252
253
0
        total_days
254
0
    }
255
256
    /// Lisp code reference: <https://github.com/EdReingold/calendar-code2/blob/main/calendar.l#L2352>
257
0
    pub fn book_hebrew_from_fixed(date: RataDie) -> BookHebrew {
258
0
        let approx = i64_to_i32(
259
0
            1 + ((date - FIXED_HEBREW_EPOCH) as f64).div_euclid(35975351.0 / 98496.0) as i64, //  The value 35975351/98496, the average length of a BookHebrew year, can be approximated by 365.25
260
        )
261
0
        .unwrap_or_else(|e| e.saturate());
262
263
        // Search forward for the year
264
0
        let year_condition = |year: i32| Self::book_hebrew_new_year(year) <= date;
265
0
        let year = final_func(approx - 1, year_condition);
266
267
        // Starting month for search for month.
268
0
        let start = if date
269
0
            < Self::fixed_from_book_hebrew(BookHebrew {
270
0
                year,
271
0
                month: NISAN,
272
0
                day: 1,
273
0
            }) {
274
0
            TISHRI
275
        } else {
276
0
            NISAN
277
        };
278
279
0
        let month_condition = |m: u8| {
280
0
            date <= Self::fixed_from_book_hebrew(BookHebrew {
281
0
                year,
282
0
                month: m,
283
0
                day: Self::last_day_of_book_hebrew_month(year, m),
284
0
            })
285
0
        };
286
        // Search forward from either Tishri or Nisan.
287
0
        let month = next_u8(start, month_condition);
288
289
        // Calculate the day by subtraction.
290
0
        let day = (date
291
0
            - Self::fixed_from_book_hebrew(BookHebrew {
292
0
                year,
293
0
                month,
294
0
                day: 1,
295
0
            }))
296
0
            + 1;
297
298
0
        BookHebrew {
299
0
            year,
300
0
            month,
301
0
            day: day as u8,
302
0
        }
303
0
    }
304
}
305
306
#[cfg(test)]
307
mod tests {
308
    use super::*;
309
310
    #[derive(Debug)]
311
    struct DateCase {
312
        year: i32,
313
        month: u8,
314
        day: u8,
315
    }
316
317
    static TEST_FIXED_DATE: [i64; 33] = [
318
        -214193, -61387, 25469, 49217, 171307, 210155, 253427, 369740, 400085, 434355, 452605,
319
        470160, 473837, 507850, 524156, 544676, 567118, 569477, 601716, 613424, 626596, 645554,
320
        664224, 671401, 694799, 704424, 708842, 709409, 709580, 727274, 728714, 744313, 764652,
321
    ];
322
323
    static HEBREW_DATES: [DateCase; 33] = [
324
        DateCase {
325
            year: 3174,
326
            month: 5,
327
            day: 10,
328
        },
329
        DateCase {
330
            year: 3593,
331
            month: 9,
332
            day: 25,
333
        },
334
        DateCase {
335
            year: 3831,
336
            month: 7,
337
            day: 3,
338
        },
339
        DateCase {
340
            year: 3896,
341
            month: 7,
342
            day: 9,
343
        },
344
        DateCase {
345
            year: 4230,
346
            month: 10,
347
            day: 18,
348
        },
349
        DateCase {
350
            year: 4336,
351
            month: 3,
352
            day: 4,
353
        },
354
        DateCase {
355
            year: 4455,
356
            month: 8,
357
            day: 13,
358
        },
359
        DateCase {
360
            year: 4773,
361
            month: 2,
362
            day: 6,
363
        },
364
        DateCase {
365
            year: 4856,
366
            month: 2,
367
            day: 23,
368
        },
369
        DateCase {
370
            year: 4950,
371
            month: 1,
372
            day: 7,
373
        },
374
        DateCase {
375
            year: 5000,
376
            month: 13,
377
            day: 8,
378
        },
379
        DateCase {
380
            year: 5048,
381
            month: 1,
382
            day: 21,
383
        },
384
        DateCase {
385
            year: 5058,
386
            month: 2,
387
            day: 7,
388
        },
389
        DateCase {
390
            year: 5151,
391
            month: 4,
392
            day: 1,
393
        },
394
        DateCase {
395
            year: 5196,
396
            month: 11,
397
            day: 7,
398
        },
399
        DateCase {
400
            year: 5252,
401
            month: 1,
402
            day: 3,
403
        },
404
        DateCase {
405
            year: 5314,
406
            month: 7,
407
            day: 1,
408
        },
409
        DateCase {
410
            year: 5320,
411
            month: 12,
412
            day: 27,
413
        },
414
        DateCase {
415
            year: 5408,
416
            month: 3,
417
            day: 20,
418
        },
419
        DateCase {
420
            year: 5440,
421
            month: 4,
422
            day: 3,
423
        },
424
        DateCase {
425
            year: 5476,
426
            month: 5,
427
            day: 5,
428
        },
429
        DateCase {
430
            year: 5528,
431
            month: 4,
432
            day: 4,
433
        },
434
        DateCase {
435
            year: 5579,
436
            month: 5,
437
            day: 11,
438
        },
439
        DateCase {
440
            year: 5599,
441
            month: 1,
442
            day: 12,
443
        },
444
        DateCase {
445
            year: 5663,
446
            month: 1,
447
            day: 22,
448
        },
449
        DateCase {
450
            year: 5689,
451
            month: 5,
452
            day: 19,
453
        },
454
        DateCase {
455
            year: 5702,
456
            month: 7,
457
            day: 8,
458
        },
459
        DateCase {
460
            year: 5703,
461
            month: 1,
462
            day: 14,
463
        },
464
        DateCase {
465
            year: 5704,
466
            month: 7,
467
            day: 8,
468
        },
469
        DateCase {
470
            year: 5752,
471
            month: 13,
472
            day: 12,
473
        },
474
        DateCase {
475
            year: 5756,
476
            month: 12,
477
            day: 5,
478
        },
479
        DateCase {
480
            year: 5799,
481
            month: 8,
482
            day: 12,
483
        },
484
        DateCase {
485
            year: 5854,
486
            month: 5,
487
            day: 5,
488
        },
489
    ];
490
491
    static EXPECTED_MOLAD_DATES: [f64; 33] = [
492
        -1850718767f64 / 8640f64,
493
        -1591805959f64 / 25920f64,
494
        660097927f64 / 25920f64,
495
        1275506059f64 / 25920f64,
496
        4439806081f64 / 25920f64,
497
        605235101f64 / 2880f64,
498
        3284237627f64 / 12960f64,
499
        9583515841f64 / 25920f64,
500
        2592403883f64 / 6480f64,
501
        2251656649f64 / 5184f64,
502
        11731320839f64 / 25920f64,
503
        12185988041f64 / 25920f64,
504
        6140833583f64 / 12960f64,
505
        6581722991f64 / 12960f64,
506
        6792982499f64 / 12960f64,
507
        4705980311f64 / 8640f64,
508
        14699670013f64 / 25920f64,
509
        738006961f64 / 1296f64,
510
        1949499007f64 / 3240f64,
511
        5299956319f64 / 8640f64,
512
        3248250415f64 / 5184f64,
513
        16732660061f64 / 25920f64,
514
        17216413717f64 / 25920f64,
515
        1087650871f64 / 1620f64,
516
        2251079609f64 / 3240f64,
517
        608605601f64 / 864f64,
518
        306216383f64 / 432f64,
519
        18387526207f64 / 25920f64,
520
        3678423761f64 / 5184f64,
521
        1570884431f64 / 2160f64,
522
        18888119389f64 / 25920f64,
523
        19292268013f64 / 25920f64,
524
        660655045f64 / 864f64,
525
    ];
526
527
    static EXPECTED_LAST_HEBREW_MONTH: [u8; 33] = [
528
        12, 12, 12, 12, 12, 12, 12, 12, 13, 12, 13, 12, 12, 12, 12, 13, 12, 13, 12, 13, 12, 12, 12,
529
        12, 12, 13, 12, 13, 12, 13, 12, 12, 12,
530
    ];
531
532
    static EXPECTED_HEBREW_ELASPED_CALENDAR_DAYS: [i32; 33] = [
533
        1158928, 1311957, 1398894, 1422636, 1544627, 1583342, 1626812, 1742956, 1773254, 1807597,
534
        1825848, 1843388, 1847051, 1881010, 1897460, 1917895, 1940545, 1942729, 1974889, 1986554,
535
        1999723, 2018712, 2037346, 2044640, 2068027, 2077507, 2082262, 2082617, 2083000, 2100511,
536
        2101988, 2117699, 2137779,
537
    ];
538
539
    static EXPECTED_FIXED_HEBREW_NEW_YEAR: [i64; 33] = [
540
        -214497, -61470, 25467, 49209, 171200, 209915, 253385, 369529, 399827, 434172, 452421,
541
        469963, 473624, 507583, 524033, 544468, 567118, 569302, 601462, 613127, 626296, 645285,
542
        663919, 671213, 694600, 704080, 708835, 709190, 709573, 727084, 728561, 744272, 764352,
543
    ];
544
545
    static EXPECTED_DAYS_IN_HEBREW_YEAR: [u16; 33] = [
546
        354, 354, 355, 355, 355, 355, 355, 353, 383, 354, 383, 354, 354, 355, 353, 383, 353, 385,
547
        353, 383, 355, 354, 354, 354, 355, 385, 355, 383, 354, 385, 355, 354, 355,
548
    ];
549
550
    static EXPECTED_MARHESHVAN_VALUES: [bool; 33] = [
551
        false, false, true, true, true, true, true, false, false, false, false, false, false, true,
552
        false, false, false, true, false, false, true, false, false, false, true, true, true,
553
        false, false, true, true, false, true,
554
    ];
555
556
    static EXPECTED_KISLEV_VALUES: [bool; 33] = [
557
        false, false, false, false, false, false, false, true, true, false, true, false, false,
558
        false, true, true, true, false, true, true, false, false, false, false, false, false,
559
        false, true, false, false, false, false, false,
560
    ];
561
562
    static EXPECTED_DAY_IN_MONTH: [u8; 33] = [
563
        30, 30, 30, 30, 29, 30, 30, 29, 29, 30, 29, 30, 29, 29, 30, 30, 30, 30, 30, 29, 30, 29, 30,
564
        30, 30, 30, 30, 30, 30, 29, 29, 29, 30,
565
    ];
566
567
    #[allow(dead_code)]
568
    static CIVIL_EXPECTED_DAY_IN_MONTH: [u8; 33] = [
569
        30, 30, 30, 30, 29, 30, 29, 29, 29, 30, 30, 30, 29, 29, 30, 29, 30, 29, 29, 30, 30, 29, 30,
570
        30, 30, 30, 30, 29, 30, 30, 29, 29, 30,
571
    ];
572
573
    #[test]
574
    fn test_hebrew_epoch() {
575
        // page 119 of the Calendrical Calculations book
576
        let fixed_hebrew_date = -1373427.0;
577
        assert_eq!(FIXED_HEBREW_EPOCH.to_f64_date(), fixed_hebrew_date);
578
    }
579
580
    #[test]
581
    fn test_hebrew_molad() {
582
        let precision = 1_00000f64;
583
        for (case, expected) in HEBREW_DATES.iter().zip(EXPECTED_MOLAD_DATES.iter()) {
584
            let molad =
585
                (BookHebrew::molad(case.year, case.month).inner() * precision).round() / precision;
586
            let final_expected = (expected * precision).round() / precision;
587
            assert_eq!(molad, final_expected, "{case:?}");
588
        }
589
    }
590
591
    #[test]
592
    fn test_last_book_hebrew_month() {
593
        for (case, expected) in HEBREW_DATES.iter().zip(EXPECTED_LAST_HEBREW_MONTH.iter()) {
594
            let last_month = BookHebrew::last_month_of_book_hebrew_year(case.year);
595
            assert_eq!(last_month, *expected);
596
        }
597
    }
598
599
    #[test]
600
    fn test_book_hebrew_calendar_elapsed_days() {
601
        for (case, expected) in HEBREW_DATES
602
            .iter()
603
            .zip(EXPECTED_HEBREW_ELASPED_CALENDAR_DAYS.iter())
604
        {
605
            let elapsed_days = BookHebrew::book_hebrew_calendar_elapsed_days(case.year);
606
            assert_eq!(elapsed_days, *expected);
607
        }
608
    }
609
610
    #[test]
611
    fn test_book_hebrew_year_length_correction() {
612
        let year_length_correction: [u8; 33] = [
613
            2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
614
            0, 0, 0, 0,
615
        ];
616
        for (case, expected) in HEBREW_DATES.iter().zip(year_length_correction.iter()) {
617
            let correction = BookHebrew::book_hebrew_year_length_correction(case.year);
618
            assert_eq!(correction, *expected);
619
        }
620
    }
621
622
    #[test]
623
    fn test_book_hebrew_new_year() {
624
        for (case, expected) in HEBREW_DATES
625
            .iter()
626
            .zip(EXPECTED_FIXED_HEBREW_NEW_YEAR.iter())
627
        {
628
            let f_date = BookHebrew::book_hebrew_new_year(case.year);
629
            assert_eq!(f_date.to_i64_date(), *expected);
630
        }
631
    }
632
633
    #[test]
634
    fn test_days_in_book_hebrew_year() {
635
        for (case, expected) in HEBREW_DATES.iter().zip(EXPECTED_DAYS_IN_HEBREW_YEAR.iter()) {
636
            let days_in_year = BookHebrew::days_in_book_hebrew_year(case.year);
637
            assert_eq!(days_in_year, *expected);
638
        }
639
    }
640
641
    #[test]
642
    fn test_long_marheshvan() {
643
        for (case, expected) in HEBREW_DATES.iter().zip(EXPECTED_MARHESHVAN_VALUES.iter()) {
644
            let marsheshvan = BookHebrew::is_long_marheshvan(case.year);
645
            assert_eq!(marsheshvan, *expected);
646
        }
647
    }
648
649
    #[test]
650
    fn test_short_kislev() {
651
        for (case, expected) in HEBREW_DATES.iter().zip(EXPECTED_KISLEV_VALUES.iter()) {
652
            let kislev = BookHebrew::is_short_kislev(case.year);
653
            assert_eq!(kislev, *expected);
654
        }
655
    }
656
657
    #[test]
658
    fn test_last_day_in_book_hebrew_month() {
659
        for (case, expected) in HEBREW_DATES.iter().zip(EXPECTED_DAY_IN_MONTH.iter()) {
660
            let days_in_month = BookHebrew::last_day_of_book_hebrew_month(case.year, case.month);
661
            assert_eq!(days_in_month, *expected);
662
        }
663
    }
664
665
    #[test]
666
    fn test_fixed_from_book_hebrew() {
667
        for (case, f_date) in HEBREW_DATES.iter().zip(TEST_FIXED_DATE.iter()) {
668
            assert_eq!(
669
                BookHebrew::fixed_from_book_hebrew(BookHebrew {
670
                    year: case.year,
671
                    month: case.month,
672
                    day: case.day
673
                }),
674
                RataDie::new(*f_date),
675
                "{case:?}"
676
            );
677
        }
678
    }
679
680
    #[test]
681
    fn test_book_hebrew_from_fixed() {
682
        for (case, f_date) in HEBREW_DATES.iter().zip(TEST_FIXED_DATE.iter()) {
683
            assert_eq!(
684
                BookHebrew::book_hebrew_from_fixed(RataDie::new(*f_date)),
685
                BookHebrew {
686
                    year: case.year,
687
                    month: case.month,
688
                    day: case.day
689
                },
690
                "{case:?}"
691
            );
692
        }
693
    }
694
695
    #[test]
696
    fn test_civil_to_book_conversion() {
697
        for (f_date, case) in TEST_FIXED_DATE.iter().zip(HEBREW_DATES.iter()) {
698
            let book_hebrew = BookHebrew::book_hebrew_from_fixed(RataDie::new(*f_date));
699
            let (y, m, d) = book_hebrew.to_civil_date();
700
            let book_hebrew = BookHebrew::from_civil_date(y, m, d);
701
702
            assert_eq!(
703
                (case.year, case.month),
704
                (book_hebrew.year, book_hebrew.month)
705
            )
706
        }
707
    }
708
}