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