icu_calendar/date.rs
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
5use crate::any_calendar::{AnyCalendar, IntoAnyCalendar};
6use crate::error::{DateError, DateFromFieldsError};
7use crate::options::DateFromFieldsOptions;
8use crate::options::{DateAddOptions, DateDifferenceOptions};
9use crate::types::{CyclicYear, EraYear, IsoWeekOfYear};
10use crate::week::{RelativeUnit, WeekCalculator, WeekOf};
11use crate::{types, Calendar, Iso};
12#[cfg(feature = "alloc")]
13use alloc::rc::Rc;
14#[cfg(feature = "alloc")]
15use alloc::sync::Arc;
16use calendrical_calculations::rata_die::RataDie;
17use core::fmt;
18use core::ops::Deref;
19
20/// Types that contain a calendar
21///
22/// This allows one to use [`Date`] with wrappers around calendars,
23/// e.g. reference counted calendars.
24pub trait AsCalendar {
25 /// The calendar being wrapped
26 type Calendar: Calendar;
27 /// Obtain the inner calendar
28 fn as_calendar(&self) -> &Self::Calendar;
29}
30
31impl<C: Calendar> AsCalendar for C {
32 type Calendar = C;
33 #[inline]
34 fn as_calendar(&self) -> &Self {
35 self
36 }
37}
38
39#[cfg(feature = "alloc")]
40/// ✨ *Enabled with the `alloc` Cargo feature.*
41impl<C: AsCalendar> AsCalendar for Rc<C> {
42 type Calendar = C::Calendar;
43 #[inline]
44 fn as_calendar(&self) -> &Self::Calendar {
45 self.as_ref().as_calendar()
46 }
47}
48
49#[cfg(feature = "alloc")]
50/// ✨ *Enabled with the `alloc` Cargo feature.*
51impl<C: AsCalendar> AsCalendar for Arc<C> {
52 type Calendar = C::Calendar;
53 #[inline]
54 fn as_calendar(&self) -> &Self::Calendar {
55 self.as_ref().as_calendar()
56 }
57}
58
59/// This exists as a wrapper around `&'a T` so that
60/// `Date<&'a C>` is possible for calendar `C`.
61///
62/// Unfortunately,
63/// [`AsCalendar`] cannot be implemented on `&'a T` directly because
64/// `&'a T` is `#[fundamental]` and the impl would clash with the one above with
65/// `AsCalendar` for `C: Calendar`.
66///
67/// Use `Date<Ref<'a, C>>` where you would use `Date<&'a C>`
68#[allow(clippy::exhaustive_structs)] // newtype
69#[derive(PartialEq, Eq, Debug)]
70pub struct Ref<'a, C>(pub &'a C);
71
72impl<C> Copy for Ref<'_, C> {}
73
74impl<C> Clone for Ref<'_, C> {
75 fn clone(&self) -> Self {
76 *self
77 }
78}
79
80impl<C: AsCalendar> AsCalendar for Ref<'_, C> {
81 type Calendar = C::Calendar;
82 #[inline]
83 fn as_calendar(&self) -> &Self::Calendar {
84 self.0.as_calendar()
85 }
86}
87
88impl<C> Deref for Ref<'_, C> {
89 type Target = C;
90 fn deref(&self) -> &C {
91 self.0
92 }
93}
94
95/// A date for a given calendar.
96///
97/// **The primary definition of this type is in the [`icu_calendar`](https://docs.rs/icu_calendar) crate. Other ICU4X crates re-export it for convenience.**
98///
99/// This can work with wrappers around [`Calendar`] types,
100/// e.g. `Rc<C>`, via the [`AsCalendar`] trait.
101///
102/// This can be constructed constructed
103/// from its fields via [`Self::try_new_from_codes()`], or can be constructed with one of the
104/// `new_<calendar>_date()` per-calendar methods (and then freely converted between calendars).
105///
106/// ```rust
107/// use icu::calendar::Date;
108///
109/// // Example: creation of ISO date from integers.
110/// let date_iso = Date::try_new_iso(1970, 1, 2)
111/// .expect("Failed to initialize ISO Date instance.");
112///
113/// assert_eq!(date_iso.era_year().year, 1970);
114/// assert_eq!(date_iso.month().ordinal, 1);
115/// assert_eq!(date_iso.day_of_month().0, 2);
116/// ```
117pub struct Date<A: AsCalendar> {
118 pub(crate) inner: <A::Calendar as Calendar>::DateInner,
119 pub(crate) calendar: A,
120}
121
122impl<A: AsCalendar> Date<A> {
123 /// Construct a date from from era/month codes and fields, and some calendar representation
124 ///
125 /// The year is `extended_year` if no era is provided.
126 ///
127 /// This function will not accept year/extended_year values that are outside of the range `[-2²⁷, 2²⁷]`,
128 /// regardless of the calendar, instead returning a [`DateError::Range`]. See [`Date::try_from_fields()`] for more
129 /// information.
130 #[inline]
131 pub fn try_new_from_codes(
132 era: Option<&str>,
133 year: i32,
134 month_code: types::MonthCode,
135 day: u8,
136 calendar: A,
137 ) -> Result<Self, DateError> {
138 let inner = calendar
139 .as_calendar()
140 .from_codes(era, year, month_code, day)?;
141 Ok(Date { inner, calendar })
142 }
143
144 /// Construct a date from from a bag of fields.
145 ///
146 /// This function allows specifying the year as either extended year or era + era year,
147 /// and the month as either ordinal or month code. It can constrain out-of-bounds values
148 /// and fill in missing fields. See [`DateFromFieldsOptions`] for more information.
149 ///
150 /// This function will not accept year/extended_year values that are outside of the range `[-2²⁷, 2²⁷]`,
151 /// regardless of the calendar, instead returning a [`DateFromFieldsError::Range`]. This allows us to to keep
152 /// all operations on [`Date`]s infallible by staying clear of integer limits.
153 /// Currently, calendar-specific `Date::try_new_calendarname()` constructors
154 /// do not do this, and it is possible to obtain such extreme dates via calendar conversion or arithmetic,
155 /// though [we may change that behavior in the future](https://github.com/unicode-org/icu4x/issues/7076).
156 ///
157 /// # Examples
158 ///
159 /// ```
160 /// use icu::calendar::cal::Gregorian;
161 /// use icu::calendar::types::DateFields;
162 /// use icu::calendar::Date;
163 ///
164 /// let mut fields = DateFields::default();
165 /// fields.extended_year = Some(2000);
166 /// fields.ordinal_month = Some(1);
167 /// fields.day = Some(1);
168 ///
169 /// let d1 = Date::try_from_fields(fields, Default::default(), Gregorian)
170 /// .expect("Jan 1 in year 2000");
171 ///
172 /// let d2 = Date::try_new_gregorian(2000, 1, 1).unwrap();
173 /// assert_eq!(d1, d2);
174 /// ```
175 ///
176 /// See [`DateFromFieldsError`] for examples of error conditions.
177 ///
178 /// <div class="stab unstable">
179 /// 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways,
180 /// including in SemVer minor releases. Do not use this type unless you are prepared for things to occasionally break.
181 ///
182 /// Graduation tracking issue: [issue #7161](https://github.com/unicode-org/icu4x/issues/7161).
183 /// </div>
184 ///
185 /// ✨ *Enabled with the `unstable` Cargo feature.*
186 #[cfg(feature = "unstable")]
187 #[inline]
188 pub fn try_from_fields(
189 fields: types::DateFields,
190 options: DateFromFieldsOptions,
191 calendar: A,
192 ) -> Result<Self, DateFromFieldsError> {
193 let inner = calendar.as_calendar().from_fields(fields, options)?;
194 Ok(Date { inner, calendar })
195 }
196
197 /// Construct a date from a [`RataDie`] and some calendar representation
198 #[inline]
199 pub fn from_rata_die(rd: RataDie, calendar: A) -> Self {
200 Date {
201 inner: calendar.as_calendar().from_rata_die(rd),
202 calendar,
203 }
204 }
205
206 /// Convert the date to a [`RataDie`]
207 #[inline]
208 pub fn to_rata_die(&self) -> RataDie {
209 self.calendar.as_calendar().to_rata_die(self.inner())
210 }
211
212 /// Construct a date from an ISO date and some calendar representation
213 #[inline]
214 pub fn new_from_iso(iso: Date<Iso>, calendar: A) -> Self {
215 iso.to_calendar(calendar)
216 }
217
218 /// Convert the Date to an ISO Date
219 #[inline]
220 pub fn to_iso(&self) -> Date<Iso> {
221 self.to_calendar(Iso)
222 }
223
224 /// Convert the Date to a date in a different calendar
225 #[inline]
226 pub fn to_calendar<A2: AsCalendar>(&self, calendar: A2) -> Date<A2> {
227 let c1 = self.calendar.as_calendar();
228 let c2 = calendar.as_calendar();
229 let inner = if c1.has_cheap_iso_conversion() && c2.has_cheap_iso_conversion() {
230 c2.from_iso(c1.to_iso(self.inner()))
231 } else {
232 c2.from_rata_die(c1.to_rata_die(self.inner()))
233 };
234 Date { inner, calendar }
235 }
236
237 /// The number of months in the year of this date
238 #[inline]
239 pub fn months_in_year(&self) -> u8 {
240 self.calendar.as_calendar().months_in_year(self.inner())
241 }
242
243 /// The number of days in the year of this date
244 #[inline]
245 pub fn days_in_year(&self) -> u16 {
246 self.calendar.as_calendar().days_in_year(self.inner())
247 }
248
249 /// The number of days in the month of this date
250 #[inline]
251 pub fn days_in_month(&self) -> u8 {
252 self.calendar.as_calendar().days_in_month(self.inner())
253 }
254
255 /// The day of the week for this date
256 #[inline]
257 pub fn day_of_week(&self) -> types::Weekday {
258 self.to_rata_die().into()
259 }
260
261 /// Add a `duration` to this date, mutating it
262 ///
263 /// <div class="stab unstable">
264 /// 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways,
265 /// including in SemVer minor releases. Do not use this type unless you are prepared for things to occasionally break.
266 ///
267 /// Graduation tracking issue: [issue #3964](https://github.com/unicode-org/icu4x/issues/3964).
268 /// </div>
269 ///
270 /// ✨ *Enabled with the `unstable` Cargo feature.*
271 #[cfg(feature = "unstable")]
272 #[inline]
273 pub fn try_add_with_options(
274 &mut self,
275 duration: types::DateDuration,
276 options: DateAddOptions,
277 ) -> Result<(), DateError> {
278 let inner = self
279 .calendar
280 .as_calendar()
281 .add(&self.inner, duration, options)?;
282 self.inner = inner;
283 Ok(())
284 }
285
286 /// Add a `duration` to this date, returning the new one
287 ///
288 /// <div class="stab unstable">
289 /// 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways,
290 /// including in SemVer minor releases. Do not use this type unless you are prepared for things to occasionally break.
291 ///
292 /// Graduation tracking issue: [issue #3964](https://github.com/unicode-org/icu4x/issues/3964).
293 /// </div>
294 ///
295 /// ✨ *Enabled with the `unstable` Cargo feature.*
296 #[cfg(feature = "unstable")]
297 #[inline]
298 pub fn try_added_with_options(
299 mut self,
300 duration: types::DateDuration,
301 options: DateAddOptions,
302 ) -> Result<Self, DateError> {
303 self.try_add_with_options(duration, options)?;
304 Ok(self)
305 }
306
307 /// Calculating the duration between `other - self`
308 ///
309 /// Although this returns a [`Result`], with most fixed calendars, this operation can't fail.
310 /// In such cases, the error type is [`Infallible`], and the inner value can be safely
311 /// unwrapped using [`Result::into_ok()`], which is available in nightly Rust as of this
312 /// writing. In stable Rust, the value can be unwrapped using [pattern matching].
313 ///
314 /// # Examples
315 ///
316 /// ```
317 /// use icu::calendar::types::DateDuration;
318 /// use icu::calendar::Date;
319 ///
320 /// let d1 = Date::try_new_iso(2020, 1, 1).unwrap();
321 /// let d2 = Date::try_new_iso(2025, 10, 2).unwrap();
322 /// let options = Default::default();
323 ///
324 /// // The value can be unwrapped with destructuring syntax:
325 /// let Ok(duration) = d1.try_until_with_options(&d2, options);
326 ///
327 /// assert_eq!(duration, DateDuration::for_days(2101));
328 /// ```
329 ///
330 /// [`Infallible`]: core::convert::Infallible
331 /// [pattern matching]: https://doc.rust-lang.org/book/ch19-03-pattern-syntax.html
332 ///
333 /// <div class="stab unstable">
334 /// 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways,
335 /// including in SemVer minor releases. Do not use this type unless you are prepared for things to occasionally break.
336 ///
337 /// Graduation tracking issue: [issue #3964](https://github.com/unicode-org/icu4x/issues/3964).
338 /// </div>
339 ///
340 /// ✨ *Enabled with the `unstable` Cargo feature.*
341 #[cfg(feature = "unstable")]
342 #[inline]
343 pub fn try_until_with_options<B: AsCalendar<Calendar = A::Calendar>>(
344 &self,
345 other: &Date<B>,
346 options: DateDifferenceOptions,
347 ) -> Result<types::DateDuration, <A::Calendar as Calendar>::DifferenceError> {
348 self.calendar
349 .as_calendar()
350 .until(self.inner(), other.inner(), options)
351 }
352
353 /// The calendar-specific year-info.
354 ///
355 /// This returns an enum, see [`Date::era_year()`] and [`Date::cyclic_year()`] which are available
356 /// for concrete calendar types and return concrete types.
357 #[inline]
358 pub fn year(&self) -> types::YearInfo {
359 self.calendar.as_calendar().year_info(&self.inner).into()
360 }
361
362 /// The "extended year".
363 ///
364 /// This year number can be used when you need a simple numeric representation
365 /// of the year, and can be meaningfully compared with extended years from other
366 /// eras or used in arithmetic.
367 ///
368 /// For calendars defined in Temporal, this will match the "arithmetic year"
369 /// as defined in <https://tc39.es/proposal-intl-era-monthcode/>.
370 /// This is typically anchored with year 1 as the year 1 of either the most modern or
371 /// otherwise some "major" era for the calendar.
372 ///
373 /// See [`Self::year()`] for more information about the year.
374 #[inline]
375 pub fn extended_year(&self) -> i32 {
376 self.year().extended_year()
377 }
378
379 /// Returns whether `self` is in a calendar-specific leap year
380 #[inline]
381 pub fn is_in_leap_year(&self) -> bool {
382 self.calendar.as_calendar().is_in_leap_year(&self.inner)
383 }
384
385 /// The calendar-specific month represented by `self`
386 #[inline]
387 pub fn month(&self) -> types::MonthInfo {
388 self.calendar.as_calendar().month(&self.inner)
389 }
390
391 /// The calendar-specific day-of-month represented by `self`
392 #[inline]
393 pub fn day_of_month(&self) -> types::DayOfMonth {
394 self.calendar.as_calendar().day_of_month(&self.inner)
395 }
396
397 /// The calendar-specific day-of-month represented by `self`
398 #[inline]
399 pub fn day_of_year(&self) -> types::DayOfYear {
400 self.calendar.as_calendar().day_of_year(&self.inner)
401 }
402
403 /// Construct a date from raw values for a given calendar. This does not check any
404 /// invariants for the date and calendar, and should only be called by calendar implementations.
405 ///
406 /// Calling this outside of calendar implementations is sound, but calendar implementations are not
407 /// expected to do anything sensible with such invalid dates.
408 ///
409 /// AnyCalendar *will* panic if AnyCalendar [`Date`] objects with mismatching
410 /// date and calendar types are constructed
411 #[inline]
412 pub fn from_raw(inner: <A::Calendar as Calendar>::DateInner, calendar: A) -> Self {
413 Self { inner, calendar }
414 }
415
416 /// Get the inner date implementation. Should not be called outside of calendar implementations
417 #[inline]
418 pub fn inner(&self) -> &<A::Calendar as Calendar>::DateInner {
419 &self.inner
420 }
421
422 /// Get a reference to the contained calendar
423 #[inline]
424 pub fn calendar(&self) -> &A::Calendar {
425 self.calendar.as_calendar()
426 }
427
428 /// Get a reference to the contained calendar wrapper
429 ///
430 /// (Useful in case the user wishes to e.g. clone an Rc)
431 #[inline]
432 pub fn calendar_wrapper(&self) -> &A {
433 &self.calendar
434 }
435}
436
437impl<A: AsCalendar<Calendar = C>, C: Calendar<Year = EraYear>> Date<A> {
438 /// Returns information about the era for calendars using eras.
439 pub fn era_year(&self) -> EraYear {
440 self.calendar.as_calendar().year_info(self.inner())
441 }
442}
443
444impl<A: AsCalendar<Calendar = C>, C: Calendar<Year = CyclicYear>> Date<A> {
445 /// Returns information about the year cycle, for cyclic calendars.
446 pub fn cyclic_year(&self) -> CyclicYear {
447 self.calendar.as_calendar().year_info(self.inner())
448 }
449}
450
451impl Date<Iso> {
452 /// The ISO week of the year containing this date.
453 ///
454 /// # Examples
455 ///
456 /// ```
457 /// use icu::calendar::types::IsoWeekOfYear;
458 /// use icu::calendar::Date;
459 ///
460 /// let date = Date::try_new_iso(2022, 8, 26).unwrap();
461 ///
462 /// assert_eq!(
463 /// date.week_of_year(),
464 /// IsoWeekOfYear {
465 /// week_number: 34,
466 /// iso_year: 2022,
467 /// }
468 /// );
469 /// ```
470 pub fn week_of_year(&self) -> IsoWeekOfYear {
471 let week_of = WeekCalculator::ISO
472 .week_of(
473 365 + calendrical_calculations::gregorian::is_leap_year(self.inner.0.year - 1)
474 as u16,
475 self.days_in_year(),
476 self.day_of_year().0,
477 self.day_of_week(),
478 )
479 .unwrap_or_else(|_| {
480 // ISO calendar has more than 14 days per year
481 debug_assert!(false);
482 WeekOf {
483 week: 1,
484 unit: crate::week::RelativeUnit::Current,
485 }
486 });
487
488 IsoWeekOfYear {
489 week_number: week_of.week,
490 iso_year: match week_of.unit {
491 RelativeUnit::Current => self.inner.0.year,
492 RelativeUnit::Next => self.inner.0.year + 1,
493 RelativeUnit::Previous => self.inner.0.year - 1,
494 },
495 }
496 }
497}
498
499impl<C: IntoAnyCalendar> Date<C> {
500 /// Type-erase the date, converting it to a date for [`AnyCalendar`]
501 pub fn to_any(self) -> Date<AnyCalendar> {
502 Date::from_raw(
503 self.calendar.date_to_any(&self.inner),
504 self.calendar.to_any(),
505 )
506 }
507}
508
509impl<A: AsCalendar> Date<A> {
510 /// Wrap the contained calendar type in `Rc<T>`, making it cheaper to clone.
511 ///
512 /// Useful when paired with [`Self::to_any()`] to obtain a `Date<Rc<AnyCalendar>>`
513 ///
514 /// ✨ *Enabled with the `alloc` Cargo feature.*
515 #[cfg(feature = "alloc")]
516 pub fn into_ref_counted(self) -> Date<Rc<A>> {
517 Date::from_raw(self.inner, Rc::new(self.calendar))
518 }
519
520 /// Wrap the contained calendar type in `Arc<T>`, making it cheaper to clone in a thread-safe manner.
521 ///
522 /// Useful when paired with [`Self::to_any()`] to obtain a `Date<Arc<AnyCalendar>>`
523 ///
524 /// ✨ *Enabled with the `alloc` Cargo feature.*
525 #[cfg(feature = "alloc")]
526 pub fn into_atomic_ref_counted(self) -> Date<Arc<A>> {
527 Date::from_raw(self.inner, Arc::new(self.calendar))
528 }
529
530 /// Wrap the calendar type in `Ref<T>`, making it cheaper to clone (by introducing a borrow)
531 ///
532 /// Useful for converting a `&Date<C>` into an equivalent `Date<D>` without cloning
533 /// the calendar.
534 pub fn as_borrowed(&self) -> Date<Ref<'_, A>> {
535 Date::from_raw(self.inner, Ref(&self.calendar))
536 }
537}
538
539impl<C, A, B> PartialEq<Date<B>> for Date<A>
540where
541 C: Calendar,
542 A: AsCalendar<Calendar = C>,
543 B: AsCalendar<Calendar = C>,
544{
545 fn eq(&self, other: &Date<B>) -> bool {
546 self.inner.eq(&other.inner)
547 }
548}
549
550impl<A: AsCalendar> Eq for Date<A> {}
551
552impl<C, A, B> PartialOrd<Date<B>> for Date<A>
553where
554 C: Calendar,
555 A: AsCalendar<Calendar = C>,
556 B: AsCalendar<Calendar = C>,
557{
558 fn partial_cmp(&self, other: &Date<B>) -> Option<core::cmp::Ordering> {
559 self.inner.partial_cmp(&other.inner)
560 }
561}
562
563impl<C, A> Ord for Date<A>
564where
565 C: Calendar,
566 C::DateInner: Ord,
567 A: AsCalendar<Calendar = C>,
568{
569 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
570 self.inner.cmp(&other.inner)
571 }
572}
573
574impl<A: AsCalendar> fmt::Debug for Date<A> {
575 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
576 let month = self.month().ordinal;
577 let day = self.day_of_month().0;
578 let calendar = self.calendar.as_calendar().debug_name();
579 match self.year() {
580 types::YearInfo::Era(EraYear { year, era, .. }) => {
581 write!(
582 f,
583 "Date({year}-{month}-{day}, {era} era, for calendar {calendar})"
584 )
585 }
586 types::YearInfo::Cyclic(CyclicYear { year, related_iso }) => {
587 write!(
588 f,
589 "Date({year}-{month}-{day}, ISO year {related_iso}, for calendar {calendar})"
590 )
591 }
592 }
593 }
594}
595
596impl<A: AsCalendar + Clone> Clone for Date<A> {
597 fn clone(&self) -> Self {
598 Self {
599 inner: self.inner,
600 calendar: self.calendar.clone(),
601 }
602 }
603}
604
605impl<A> Copy for Date<A> where A: AsCalendar + Copy {}
606
607#[cfg(test)]
608mod tests {
609 use super::*;
610 use crate::types::Weekday;
611
612 #[test]
613 fn test_ord() {
614 let dates_in_order = [
615 Date::try_new_iso(-10, 1, 1).unwrap(),
616 Date::try_new_iso(-10, 1, 2).unwrap(),
617 Date::try_new_iso(-10, 2, 1).unwrap(),
618 Date::try_new_iso(-1, 1, 1).unwrap(),
619 Date::try_new_iso(-1, 1, 2).unwrap(),
620 Date::try_new_iso(-1, 2, 1).unwrap(),
621 Date::try_new_iso(0, 1, 1).unwrap(),
622 Date::try_new_iso(0, 1, 2).unwrap(),
623 Date::try_new_iso(0, 2, 1).unwrap(),
624 Date::try_new_iso(1, 1, 1).unwrap(),
625 Date::try_new_iso(1, 1, 2).unwrap(),
626 Date::try_new_iso(1, 2, 1).unwrap(),
627 Date::try_new_iso(10, 1, 1).unwrap(),
628 Date::try_new_iso(10, 1, 2).unwrap(),
629 Date::try_new_iso(10, 2, 1).unwrap(),
630 ];
631 for (i, i_date) in dates_in_order.iter().enumerate() {
632 for (j, j_date) in dates_in_order.iter().enumerate() {
633 let result1 = i_date.cmp(j_date);
634 let result2 = j_date.cmp(i_date);
635 assert_eq!(result1.reverse(), result2);
636 assert_eq!(i.cmp(&j), i_date.cmp(j_date));
637 }
638 }
639 }
640
641 #[test]
642 fn test_day_of_week() {
643 // June 23, 2021 is a Wednesday
644 assert_eq!(
645 Date::try_new_iso(2021, 6, 23).unwrap().day_of_week(),
646 Weekday::Wednesday,
647 );
648 // Feb 2, 1983 was a Wednesday
649 assert_eq!(
650 Date::try_new_iso(1983, 2, 2).unwrap().day_of_week(),
651 Weekday::Wednesday,
652 );
653 // Jan 21, 2021 was a Tuesday
654 assert_eq!(
655 Date::try_new_iso(2020, 1, 21).unwrap().day_of_week(),
656 Weekday::Tuesday,
657 );
658 }
659}