/rust/registry/src/index.crates.io-1949cf8c6b5b557f/icu_calendar-1.5.2/src/julian.rs
Line | Count | Source |
1 | | // This file is part of ICU4X. For terms of use, please see the file |
2 | | // called LICENSE at the top level of the ICU4X source tree |
3 | | // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). |
4 | | |
5 | | //! This module contains types and implementations for the Julian calendar. |
6 | | //! |
7 | | //! ```rust |
8 | | //! use icu::calendar::{julian::Julian, Date, DateTime}; |
9 | | //! |
10 | | //! // `Date` type |
11 | | //! let date_iso = Date::try_new_iso_date(1970, 1, 2) |
12 | | //! .expect("Failed to initialize ISO Date instance."); |
13 | | //! let date_julian = Date::new_from_iso(date_iso, Julian); |
14 | | //! |
15 | | //! // `DateTime` type |
16 | | //! let datetime_iso = DateTime::try_new_iso_datetime(1970, 1, 2, 13, 1, 0) |
17 | | //! .expect("Failed to initialize ISO DateTime instance."); |
18 | | //! let datetime_julian = DateTime::new_from_iso(datetime_iso, Julian); |
19 | | //! |
20 | | //! // `Date` checks |
21 | | //! assert_eq!(date_julian.year().number, 1969); |
22 | | //! assert_eq!(date_julian.month().ordinal, 12); |
23 | | //! assert_eq!(date_julian.day_of_month().0, 20); |
24 | | //! |
25 | | //! // `DateTime` type |
26 | | //! assert_eq!(datetime_julian.date.year().number, 1969); |
27 | | //! assert_eq!(datetime_julian.date.month().ordinal, 12); |
28 | | //! assert_eq!(datetime_julian.date.day_of_month().0, 20); |
29 | | //! assert_eq!(datetime_julian.time.hour.number(), 13); |
30 | | //! assert_eq!(datetime_julian.time.minute.number(), 1); |
31 | | //! assert_eq!(datetime_julian.time.second.number(), 0); |
32 | | //! ``` |
33 | | |
34 | | use crate::any_calendar::AnyCalendarKind; |
35 | | use crate::calendar_arithmetic::{ArithmeticDate, CalendarArithmetic}; |
36 | | use crate::gregorian::year_as_gregorian; |
37 | | use crate::iso::Iso; |
38 | | use crate::{types, Calendar, CalendarError, Date, DateDuration, DateDurationUnit, DateTime, Time}; |
39 | | use calendrical_calculations::helpers::I32CastError; |
40 | | use calendrical_calculations::rata_die::RataDie; |
41 | | use tinystr::tinystr; |
42 | | |
43 | | /// The [Julian Calendar] |
44 | | /// |
45 | | /// The [Julian calendar] is a solar calendar that was used commonly historically, with twelve months. |
46 | | /// |
47 | | /// This type can be used with [`Date`] or [`DateTime`] to represent dates in this calendar. |
48 | | /// |
49 | | /// [Julian calendar]: https://en.wikipedia.org/wiki/Julian_calendar |
50 | | /// |
51 | | /// # Era codes |
52 | | /// |
53 | | /// This calendar supports two era codes: `"bce"`, and `"ce"`, corresponding to the BCE/BC and CE/AD eras |
54 | | /// |
55 | | /// # Month codes |
56 | | /// |
57 | | /// This calendar supports 12 solar month codes (`"M01" - "M12"`) |
58 | | #[derive(Copy, Clone, Debug, Hash, Default, Eq, PartialEq, PartialOrd, Ord)] |
59 | | #[allow(clippy::exhaustive_structs)] // this type is stable |
60 | | pub struct Julian; |
61 | | |
62 | | /// The inner date type used for representing [`Date`]s of [`Julian`]. See [`Date`] and [`Julian`] for more details. |
63 | | #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] |
64 | | // The inner date type used for representing Date<Julian> |
65 | | pub struct JulianDateInner(pub(crate) ArithmeticDate<Julian>); |
66 | | |
67 | | impl CalendarArithmetic for Julian { |
68 | | type YearInfo = (); |
69 | | |
70 | 0 | fn month_days(year: i32, month: u8, _data: ()) -> u8 { |
71 | 0 | match month { |
72 | 0 | 4 | 6 | 9 | 11 => 30, |
73 | 0 | 2 if Self::is_leap_year(year, ()) => 29, |
74 | 0 | 2 => 28, |
75 | 0 | 1 | 3 | 5 | 7 | 8 | 10 | 12 => 31, |
76 | 0 | _ => 0, |
77 | | } |
78 | 0 | } |
79 | | |
80 | 0 | fn months_for_every_year(_: i32, _data: ()) -> u8 { |
81 | 0 | 12 |
82 | 0 | } |
83 | | |
84 | 0 | fn is_leap_year(year: i32, _data: ()) -> bool { |
85 | 0 | calendrical_calculations::julian::is_leap_year(year) |
86 | 0 | } |
87 | | |
88 | 0 | fn last_month_day_in_year(_year: i32, _data: ()) -> (u8, u8) { |
89 | 0 | (12, 31) |
90 | 0 | } |
91 | | |
92 | 0 | fn days_in_provided_year(year: i32, _data: ()) -> u16 { |
93 | 0 | if Self::is_leap_year(year, ()) { |
94 | 0 | 366 |
95 | | } else { |
96 | 0 | 365 |
97 | | } |
98 | 0 | } |
99 | | } |
100 | | |
101 | | impl Calendar for Julian { |
102 | | type DateInner = JulianDateInner; |
103 | 0 | fn date_from_codes( |
104 | 0 | &self, |
105 | 0 | era: types::Era, |
106 | 0 | year: i32, |
107 | 0 | month_code: types::MonthCode, |
108 | 0 | day: u8, |
109 | 0 | ) -> Result<Self::DateInner, CalendarError> { |
110 | 0 | let year = if era.0 == tinystr!(16, "ce") { |
111 | 0 | if year <= 0 { |
112 | 0 | return Err(CalendarError::OutOfRange); |
113 | 0 | } |
114 | 0 | year |
115 | 0 | } else if era.0 == tinystr!(16, "bce") { |
116 | 0 | if year <= 0 { |
117 | 0 | return Err(CalendarError::OutOfRange); |
118 | 0 | } |
119 | 0 | 1 - year |
120 | | } else { |
121 | 0 | return Err(CalendarError::UnknownEra(era.0, self.debug_name())); |
122 | | }; |
123 | | |
124 | 0 | ArithmeticDate::new_from_codes(self, year, month_code, day).map(JulianDateInner) |
125 | 0 | } |
126 | 0 | fn date_from_iso(&self, iso: Date<Iso>) -> JulianDateInner { |
127 | 0 | let fixed_iso = Iso::fixed_from_iso(*iso.inner()); |
128 | 0 | Self::julian_from_fixed(fixed_iso) |
129 | 0 | } |
130 | | |
131 | 0 | fn date_to_iso(&self, date: &Self::DateInner) -> Date<Iso> { |
132 | 0 | let fixed_julian = Julian::fixed_from_julian(date.0); |
133 | 0 | Iso::iso_from_fixed(fixed_julian) |
134 | 0 | } |
135 | | |
136 | 0 | fn months_in_year(&self, date: &Self::DateInner) -> u8 { |
137 | 0 | date.0.months_in_year() |
138 | 0 | } |
139 | | |
140 | 0 | fn days_in_year(&self, date: &Self::DateInner) -> u16 { |
141 | 0 | date.0.days_in_year() |
142 | 0 | } |
143 | | |
144 | 0 | fn days_in_month(&self, date: &Self::DateInner) -> u8 { |
145 | 0 | date.0.days_in_month() |
146 | 0 | } |
147 | | |
148 | 0 | fn day_of_week(&self, date: &Self::DateInner) -> types::IsoWeekday { |
149 | 0 | Iso.day_of_week(Julian.date_to_iso(date).inner()) |
150 | 0 | } |
151 | | |
152 | 0 | fn offset_date(&self, date: &mut Self::DateInner, offset: DateDuration<Self>) { |
153 | 0 | date.0.offset_date(offset, &()); |
154 | 0 | } |
155 | | |
156 | | #[allow(clippy::field_reassign_with_default)] |
157 | 0 | fn until( |
158 | 0 | &self, |
159 | 0 | date1: &Self::DateInner, |
160 | 0 | date2: &Self::DateInner, |
161 | 0 | _calendar2: &Self, |
162 | 0 | _largest_unit: DateDurationUnit, |
163 | 0 | _smallest_unit: DateDurationUnit, |
164 | 0 | ) -> DateDuration<Self> { |
165 | 0 | date1.0.until(date2.0, _largest_unit, _smallest_unit) |
166 | 0 | } |
167 | | |
168 | | /// The calendar-specific year represented by `date` |
169 | | /// Julian has the same era scheme as Gregorian |
170 | 0 | fn year(&self, date: &Self::DateInner) -> types::FormattableYear { |
171 | 0 | year_as_gregorian(date.0.year) |
172 | 0 | } |
173 | | |
174 | 0 | fn is_in_leap_year(&self, date: &Self::DateInner) -> bool { |
175 | 0 | Self::is_leap_year(date.0.year, ()) |
176 | 0 | } |
177 | | |
178 | | /// The calendar-specific month represented by `date` |
179 | 0 | fn month(&self, date: &Self::DateInner) -> types::FormattableMonth { |
180 | 0 | date.0.month() |
181 | 0 | } |
182 | | |
183 | | /// The calendar-specific day-of-month represented by `date` |
184 | 0 | fn day_of_month(&self, date: &Self::DateInner) -> types::DayOfMonth { |
185 | 0 | date.0.day_of_month() |
186 | 0 | } |
187 | | |
188 | 0 | fn day_of_year_info(&self, date: &Self::DateInner) -> types::DayOfYearInfo { |
189 | 0 | let prev_year = date.0.year - 1; |
190 | 0 | let next_year = date.0.year + 1; |
191 | 0 | types::DayOfYearInfo { |
192 | 0 | day_of_year: date.0.day_of_year(), |
193 | 0 | days_in_year: date.0.days_in_year(), |
194 | 0 | prev_year: crate::gregorian::year_as_gregorian(prev_year), |
195 | 0 | days_in_prev_year: Julian::days_in_year_direct(prev_year), |
196 | 0 | next_year: crate::gregorian::year_as_gregorian(next_year), |
197 | 0 | } |
198 | 0 | } |
199 | | |
200 | 0 | fn debug_name(&self) -> &'static str { |
201 | 0 | "Julian" |
202 | 0 | } |
203 | | |
204 | 0 | fn any_calendar_kind(&self) -> Option<AnyCalendarKind> { |
205 | 0 | None |
206 | 0 | } |
207 | | } |
208 | | |
209 | | impl Julian { |
210 | | /// Construct a new Julian Calendar |
211 | 0 | pub fn new() -> Self { |
212 | 0 | Self |
213 | 0 | } |
214 | | |
215 | | // "Fixed" is a day count representation of calendars staring from Jan 1st of year 1 of the Georgian Calendar. |
216 | 0 | pub(crate) const fn fixed_from_julian(date: ArithmeticDate<Julian>) -> RataDie { |
217 | 0 | calendrical_calculations::julian::fixed_from_julian(date.year, date.month, date.day) |
218 | 0 | } |
219 | | |
220 | | /// Convenience function so we can call days_in_year without |
221 | | /// needing to construct a full ArithmeticDate |
222 | 0 | fn days_in_year_direct(year: i32) -> u16 { |
223 | 0 | if Julian::is_leap_year(year, ()) { |
224 | 0 | 366 |
225 | | } else { |
226 | 0 | 365 |
227 | | } |
228 | 0 | } |
229 | | |
230 | 0 | fn julian_from_fixed(date: RataDie) -> JulianDateInner { |
231 | 0 | let (year, month, day) = match calendrical_calculations::julian::julian_from_fixed(date) { |
232 | 0 | Err(I32CastError::BelowMin) => return JulianDateInner(ArithmeticDate::min_date()), |
233 | 0 | Err(I32CastError::AboveMax) => return JulianDateInner(ArithmeticDate::max_date()), |
234 | 0 | Ok(ymd) => ymd, |
235 | | }; |
236 | 0 | JulianDateInner(ArithmeticDate::new_unchecked(year, month, day)) |
237 | 0 | } |
238 | | } |
239 | | |
240 | | impl Date<Julian> { |
241 | | /// Construct new Julian Date. |
242 | | /// |
243 | | /// Years are arithmetic, meaning there is a year 0. Zero and negative years are in BC, with year 0 = 1 BC |
244 | | /// |
245 | | /// ```rust |
246 | | /// use icu::calendar::Date; |
247 | | /// |
248 | | /// let date_julian = Date::try_new_julian_date(1969, 12, 20) |
249 | | /// .expect("Failed to initialize Julian Date instance."); |
250 | | /// |
251 | | /// assert_eq!(date_julian.year().number, 1969); |
252 | | /// assert_eq!(date_julian.month().ordinal, 12); |
253 | | /// assert_eq!(date_julian.day_of_month().0, 20); |
254 | | /// ``` |
255 | 0 | pub fn try_new_julian_date( |
256 | 0 | year: i32, |
257 | 0 | month: u8, |
258 | 0 | day: u8, |
259 | 0 | ) -> Result<Date<Julian>, CalendarError> { |
260 | 0 | ArithmeticDate::new_from_ordinals(year, month, day) |
261 | 0 | .map(JulianDateInner) |
262 | 0 | .map(|inner| Date::from_raw(inner, Julian)) |
263 | 0 | } |
264 | | } |
265 | | |
266 | | impl DateTime<Julian> { |
267 | | /// Construct a new Julian datetime from integers. |
268 | | /// |
269 | | /// Years are arithmetic, meaning there is a year 0. Zero and negative years are in BC, with year 0 = 1 BC |
270 | | /// |
271 | | /// ```rust |
272 | | /// use icu::calendar::DateTime; |
273 | | /// |
274 | | /// let datetime_julian = |
275 | | /// DateTime::try_new_julian_datetime(1969, 12, 20, 13, 1, 0) |
276 | | /// .expect("Failed to initialize Julian DateTime instance."); |
277 | | /// |
278 | | /// assert_eq!(datetime_julian.date.year().number, 1969); |
279 | | /// assert_eq!(datetime_julian.date.month().ordinal, 12); |
280 | | /// assert_eq!(datetime_julian.date.day_of_month().0, 20); |
281 | | /// assert_eq!(datetime_julian.time.hour.number(), 13); |
282 | | /// assert_eq!(datetime_julian.time.minute.number(), 1); |
283 | | /// assert_eq!(datetime_julian.time.second.number(), 0); |
284 | | /// ``` |
285 | 0 | pub fn try_new_julian_datetime( |
286 | 0 | year: i32, |
287 | 0 | month: u8, |
288 | 0 | day: u8, |
289 | 0 | hour: u8, |
290 | 0 | minute: u8, |
291 | 0 | second: u8, |
292 | 0 | ) -> Result<DateTime<Julian>, CalendarError> { |
293 | | Ok(DateTime { |
294 | 0 | date: Date::try_new_julian_date(year, month, day)?, |
295 | 0 | time: Time::try_new(hour, minute, second, 0)?, |
296 | | }) |
297 | 0 | } |
298 | | } |
299 | | |
300 | | #[cfg(test)] |
301 | | mod test { |
302 | | use super::*; |
303 | | use types::Era; |
304 | | |
305 | | #[test] |
306 | | fn test_day_iso_to_julian() { |
307 | | // March 1st 200 is same on both calendars |
308 | | let iso_date = Date::try_new_iso_date(200, 3, 1).unwrap(); |
309 | | let julian_date = Julian.date_from_iso(iso_date); |
310 | | assert_eq!(julian_date.0.year, 200); |
311 | | assert_eq!(julian_date.0.month, 3); |
312 | | assert_eq!(julian_date.0.day, 1); |
313 | | |
314 | | // Feb 28th, 200 (iso) = Feb 29th, 200 (julian) |
315 | | let iso_date = Date::try_new_iso_date(200, 2, 28).unwrap(); |
316 | | let julian_date = Julian.date_from_iso(iso_date); |
317 | | assert_eq!(julian_date.0.year, 200); |
318 | | assert_eq!(julian_date.0.month, 2); |
319 | | assert_eq!(julian_date.0.day, 29); |
320 | | |
321 | | // March 1st 400 (iso) = Feb 29th, 400 (julian) |
322 | | let iso_date = Date::try_new_iso_date(400, 3, 1).unwrap(); |
323 | | let julian_date = Julian.date_from_iso(iso_date); |
324 | | assert_eq!(julian_date.0.year, 400); |
325 | | assert_eq!(julian_date.0.month, 2); |
326 | | assert_eq!(julian_date.0.day, 29); |
327 | | |
328 | | // Jan 1st, 2022 (iso) = Dec 19, 2021 (julian) |
329 | | let iso_date = Date::try_new_iso_date(2022, 1, 1).unwrap(); |
330 | | let julian_date = Julian.date_from_iso(iso_date); |
331 | | assert_eq!(julian_date.0.year, 2021); |
332 | | assert_eq!(julian_date.0.month, 12); |
333 | | assert_eq!(julian_date.0.day, 19); |
334 | | } |
335 | | |
336 | | #[test] |
337 | | fn test_day_julian_to_iso() { |
338 | | // March 1st 200 is same on both calendars |
339 | | let julian_date = Date::try_new_julian_date(200, 3, 1).unwrap(); |
340 | | let iso_date = Julian.date_to_iso(julian_date.inner()); |
341 | | let iso_expected_date = Date::try_new_iso_date(200, 3, 1).unwrap(); |
342 | | assert_eq!(iso_date, iso_expected_date); |
343 | | |
344 | | // Feb 28th, 200 (iso) = Feb 29th, 200 (julian) |
345 | | let julian_date = Date::try_new_julian_date(200, 2, 29).unwrap(); |
346 | | let iso_date = Julian.date_to_iso(julian_date.inner()); |
347 | | let iso_expected_date = Date::try_new_iso_date(200, 2, 28).unwrap(); |
348 | | assert_eq!(iso_date, iso_expected_date); |
349 | | |
350 | | // March 1st 400 (iso) = Feb 29th, 400 (julian) |
351 | | let julian_date = Date::try_new_julian_date(400, 2, 29).unwrap(); |
352 | | let iso_date = Julian.date_to_iso(julian_date.inner()); |
353 | | let iso_expected_date = Date::try_new_iso_date(400, 3, 1).unwrap(); |
354 | | assert_eq!(iso_date, iso_expected_date); |
355 | | |
356 | | // Jan 1st, 2022 (iso) = Dec 19, 2021 (julian) |
357 | | let julian_date = Date::try_new_julian_date(2021, 12, 19).unwrap(); |
358 | | let iso_date = Julian.date_to_iso(julian_date.inner()); |
359 | | let iso_expected_date = Date::try_new_iso_date(2022, 1, 1).unwrap(); |
360 | | assert_eq!(iso_date, iso_expected_date); |
361 | | |
362 | | // March 1st, 2022 (iso) = Feb 16, 2022 (julian) |
363 | | let julian_date = Date::try_new_julian_date(2022, 2, 16).unwrap(); |
364 | | let iso_date = Julian.date_to_iso(julian_date.inner()); |
365 | | let iso_expected_date = Date::try_new_iso_date(2022, 3, 1).unwrap(); |
366 | | assert_eq!(iso_date, iso_expected_date); |
367 | | } |
368 | | |
369 | | #[test] |
370 | | fn test_roundtrip_negative() { |
371 | | // https://github.com/unicode-org/icu4x/issues/2254 |
372 | | let iso_date = Date::try_new_iso_date(-1000, 3, 3).unwrap(); |
373 | | let julian = iso_date.to_calendar(Julian::new()); |
374 | | let recovered_iso = julian.to_iso(); |
375 | | assert_eq!(iso_date, recovered_iso); |
376 | | } |
377 | | |
378 | | #[test] |
379 | | fn test_julian_near_era_change() { |
380 | | // Tests that the Julian calendar gives the correct expected |
381 | | // day, month, and year for positive years (CE) |
382 | | |
383 | | #[derive(Debug)] |
384 | | struct TestCase { |
385 | | fixed_date: i64, |
386 | | iso_year: i32, |
387 | | iso_month: u8, |
388 | | iso_day: u8, |
389 | | expected_year: i32, |
390 | | expected_era: Era, |
391 | | expected_month: u32, |
392 | | expected_day: u32, |
393 | | } |
394 | | |
395 | | let cases = [ |
396 | | TestCase { |
397 | | fixed_date: 1, |
398 | | iso_year: 1, |
399 | | iso_month: 1, |
400 | | iso_day: 1, |
401 | | expected_year: 1, |
402 | | expected_era: Era(tinystr!(16, "ce")), |
403 | | expected_month: 1, |
404 | | expected_day: 3, |
405 | | }, |
406 | | TestCase { |
407 | | fixed_date: 0, |
408 | | iso_year: 0, |
409 | | iso_month: 12, |
410 | | iso_day: 31, |
411 | | expected_year: 1, |
412 | | expected_era: Era(tinystr!(16, "ce")), |
413 | | expected_month: 1, |
414 | | expected_day: 2, |
415 | | }, |
416 | | TestCase { |
417 | | fixed_date: -1, |
418 | | iso_year: 0, |
419 | | iso_month: 12, |
420 | | iso_day: 30, |
421 | | expected_year: 1, |
422 | | expected_era: Era(tinystr!(16, "ce")), |
423 | | expected_month: 1, |
424 | | expected_day: 1, |
425 | | }, |
426 | | TestCase { |
427 | | fixed_date: -2, |
428 | | iso_year: 0, |
429 | | iso_month: 12, |
430 | | iso_day: 29, |
431 | | expected_year: 1, |
432 | | expected_era: Era(tinystr!(16, "bce")), |
433 | | expected_month: 12, |
434 | | expected_day: 31, |
435 | | }, |
436 | | TestCase { |
437 | | fixed_date: -3, |
438 | | iso_year: 0, |
439 | | iso_month: 12, |
440 | | iso_day: 28, |
441 | | expected_year: 1, |
442 | | expected_era: Era(tinystr!(16, "bce")), |
443 | | expected_month: 12, |
444 | | expected_day: 30, |
445 | | }, |
446 | | TestCase { |
447 | | fixed_date: -367, |
448 | | iso_year: -1, |
449 | | iso_month: 12, |
450 | | iso_day: 30, |
451 | | expected_year: 1, |
452 | | expected_era: Era(tinystr!(16, "bce")), |
453 | | expected_month: 1, |
454 | | expected_day: 1, |
455 | | }, |
456 | | TestCase { |
457 | | fixed_date: -368, |
458 | | iso_year: -1, |
459 | | iso_month: 12, |
460 | | iso_day: 29, |
461 | | expected_year: 2, |
462 | | expected_era: Era(tinystr!(16, "bce")), |
463 | | expected_month: 12, |
464 | | expected_day: 31, |
465 | | }, |
466 | | TestCase { |
467 | | fixed_date: -1462, |
468 | | iso_year: -4, |
469 | | iso_month: 12, |
470 | | iso_day: 30, |
471 | | expected_year: 4, |
472 | | expected_era: Era(tinystr!(16, "bce")), |
473 | | expected_month: 1, |
474 | | expected_day: 1, |
475 | | }, |
476 | | TestCase { |
477 | | fixed_date: -1463, |
478 | | iso_year: -4, |
479 | | iso_month: 12, |
480 | | iso_day: 29, |
481 | | expected_year: 5, |
482 | | expected_era: Era(tinystr!(16, "bce")), |
483 | | expected_month: 12, |
484 | | expected_day: 31, |
485 | | }, |
486 | | ]; |
487 | | |
488 | | for case in cases { |
489 | | let iso_from_fixed: Date<Iso> = Iso::iso_from_fixed(RataDie::new(case.fixed_date)); |
490 | | let julian_from_fixed: Date<Julian> = Date::new_from_iso(iso_from_fixed, Julian); |
491 | | assert_eq!(julian_from_fixed.year().number, case.expected_year, |
492 | | "Failed year check from fixed: {case:?}\nISO: {iso_from_fixed:?}\nJulian: {julian_from_fixed:?}"); |
493 | | assert_eq!(julian_from_fixed.year().era, case.expected_era, |
494 | | "Failed era check from fixed: {case:?}\nISO: {iso_from_fixed:?}\nJulian: {julian_from_fixed:?}"); |
495 | | assert_eq!(julian_from_fixed.month().ordinal, case.expected_month, |
496 | | "Failed month check from fixed: {case:?}\nISO: {iso_from_fixed:?}\nJulian: {julian_from_fixed:?}"); |
497 | | assert_eq!(julian_from_fixed.day_of_month().0, case.expected_day, |
498 | | "Failed day check from fixed: {case:?}\nISO: {iso_from_fixed:?}\nJulian: {julian_from_fixed:?}"); |
499 | | |
500 | | let iso_date_man: Date<Iso> = |
501 | | Date::try_new_iso_date(case.iso_year, case.iso_month, case.iso_day) |
502 | | .expect("Failed to initialize ISO date for {case:?}"); |
503 | | let julian_date_man: Date<Julian> = Date::new_from_iso(iso_date_man, Julian); |
504 | | assert_eq!(iso_from_fixed, iso_date_man, |
505 | | "ISO from fixed not equal to ISO generated from manually-input ymd\nCase: {case:?}\nFixed: {iso_from_fixed:?}\nMan: {iso_date_man:?}"); |
506 | | assert_eq!(julian_from_fixed, julian_date_man, |
507 | | "Julian from fixed not equal to Julian generated from manually-input ymd\nCase: {case:?}\nFixed: {julian_from_fixed:?}\nMan: {julian_date_man:?}"); |
508 | | } |
509 | | } |
510 | | |
511 | | #[test] |
512 | | fn test_julian_fixed_date_conversion() { |
513 | | // Tests that converting from fixed date to Julian then |
514 | | // back to fixed date yields the same fixed date |
515 | | for i in -10000..=10000 { |
516 | | let fixed = RataDie::new(i); |
517 | | let julian = Julian::julian_from_fixed(fixed); |
518 | | let new_fixed = Julian::fixed_from_julian(julian.0); |
519 | | assert_eq!(fixed, new_fixed); |
520 | | } |
521 | | } |
522 | | |
523 | | #[test] |
524 | | fn test_julian_directionality() { |
525 | | // Tests that for a large range of fixed dates, if a fixed date |
526 | | // is less than another, the corresponding YMD should also be less |
527 | | // than the other, without exception. |
528 | | for i in -100..=100 { |
529 | | for j in -100..=100 { |
530 | | let julian_i = Julian::julian_from_fixed(RataDie::new(i)).0; |
531 | | let julian_j = Julian::julian_from_fixed(RataDie::new(j)).0; |
532 | | |
533 | | assert_eq!( |
534 | | i.cmp(&j), |
535 | | julian_i.cmp(&julian_j), |
536 | | "Julian directionality inconsistent with directionality for i: {i}, j: {j}" |
537 | | ); |
538 | | } |
539 | | } |
540 | | } |
541 | | |
542 | | #[test] |
543 | | fn test_hebrew_epoch() { |
544 | | assert_eq!( |
545 | | calendrical_calculations::julian::fixed_from_julian_book_version(-3761, 10, 7), |
546 | | RataDie::new(-1373427) |
547 | | ); |
548 | | } |
549 | | |
550 | | #[test] |
551 | | fn test_julian_leap_years() { |
552 | | assert!(Julian::is_leap_year(4, ())); |
553 | | assert!(Julian::is_leap_year(0, ())); |
554 | | assert!(Julian::is_leap_year(-4, ())); |
555 | | |
556 | | Date::try_new_julian_date(2020, 2, 29).unwrap(); |
557 | | } |
558 | | } |