1use crate::any_calendar::{AnyCalendar, IntoAnyCalendar};
6use crate::calendar_arithmetic::CalendarArithmetic;
7use crate::error::DateError;
8use crate::types::{CyclicYear, EraYear, IsoWeekOfYear};
9use crate::week::{RelativeUnit, WeekCalculator, WeekOf};
10use crate::{types, Calendar, DateDuration, DateDurationUnit, Iso};
11#[cfg(feature = "alloc")]
12use alloc::rc::Rc;
13#[cfg(feature = "alloc")]
14use alloc::sync::Arc;
15use calendrical_calculations::rata_die::RataDie;
16use core::fmt;
17use core::ops::Deref;
18
19pub trait AsCalendar {
24    type Calendar: Calendar;
26    fn as_calendar(&self) -> &Self::Calendar;
28}
29
30impl<C: Calendar> AsCalendar for C {
31    type Calendar = C;
32    #[inline]
33    fn as_calendar(&self) -> &Self {
34        self
35    }
36}
37
38#[cfg(feature = "alloc")]
39impl<C: AsCalendar> AsCalendar for Rc<C> {
40    type Calendar = C::Calendar;
41    #[inline]
42    fn as_calendar(&self) -> &Self::Calendar {
43        self.as_ref().as_calendar()
44    }
45}
46
47#[cfg(feature = "alloc")]
48impl<C: AsCalendar> AsCalendar for Arc<C> {
49    type Calendar = C::Calendar;
50    #[inline]
51    fn as_calendar(&self) -> &Self::Calendar {
52        self.as_ref().as_calendar()
53    }
54}
55
56#[allow(clippy::exhaustive_structs)] #[derive(PartialEq, Eq, Debug)]
67pub struct Ref<'a, C>(pub &'a C);
68
69impl<C> Copy for Ref<'_, C> {}
70
71impl<C> Clone for Ref<'_, C> {
72    fn clone(&self) -> Self {
73        *self
74    }
75}
76
77impl<C: AsCalendar> AsCalendar for Ref<'_, C> {
78    type Calendar = C::Calendar;
79    #[inline]
80    fn as_calendar(&self) -> &Self::Calendar {
81        self.0.as_calendar()
82    }
83}
84
85impl<C> Deref for Ref<'_, C> {
86    type Target = C;
87    fn deref(&self) -> &C {
88        self.0
89    }
90}
91
92pub struct Date<A: AsCalendar> {
115    pub(crate) inner: <A::Calendar as Calendar>::DateInner,
116    pub(crate) calendar: A,
117}
118
119impl<A: AsCalendar> Date<A> {
120    #[inline]
124    pub fn try_new_from_codes(
125        era: Option<&str>,
126        year: i32,
127        month_code: types::MonthCode,
128        day: u8,
129        calendar: A,
130    ) -> Result<Self, DateError> {
131        let inner = calendar
132            .as_calendar()
133            .from_codes(era, year, month_code, day)?;
134        Ok(Date { inner, calendar })
135    }
136
137    #[inline]
139    pub fn from_rata_die(rd: RataDie, calendar: A) -> Self {
140        Date {
141            inner: calendar.as_calendar().from_rata_die(rd),
142            calendar,
143        }
144    }
145
146    #[inline]
148    pub fn to_rata_die(&self) -> RataDie {
149        self.calendar.as_calendar().to_rata_die(self.inner())
150    }
151
152    #[inline]
154    pub fn new_from_iso(iso: Date<Iso>, calendar: A) -> Self {
155        let inner = calendar.as_calendar().from_iso(iso.inner);
156        Date { inner, calendar }
157    }
158
159    #[inline]
161    pub fn to_iso(&self) -> Date<Iso> {
162        Date::from_raw(self.calendar.as_calendar().to_iso(self.inner()), Iso)
163    }
164
165    #[inline]
167    pub fn to_calendar<A2: AsCalendar>(&self, calendar: A2) -> Date<A2> {
168        Date::new_from_iso(self.to_iso(), calendar)
169    }
170
171    #[inline]
173    pub fn months_in_year(&self) -> u8 {
174        self.calendar.as_calendar().months_in_year(self.inner())
175    }
176
177    #[inline]
179    pub fn days_in_year(&self) -> u16 {
180        self.calendar.as_calendar().days_in_year(self.inner())
181    }
182
183    #[inline]
185    pub fn days_in_month(&self) -> u8 {
186        self.calendar.as_calendar().days_in_month(self.inner())
187    }
188
189    #[inline]
191    pub fn day_of_week(&self) -> types::Weekday {
192        self.to_rata_die().into()
193    }
194
195    #[doc(hidden)] #[inline]
198    pub fn add(&mut self, duration: DateDuration<A::Calendar>) {
199        self.calendar
200            .as_calendar()
201            .offset_date(&mut self.inner, duration)
202    }
203
204    #[doc(hidden)] #[inline]
207    pub fn added(mut self, duration: DateDuration<A::Calendar>) -> Self {
208        self.add(duration);
209        self
210    }
211
212    #[doc(hidden)] #[inline]
215    pub fn until<B: AsCalendar<Calendar = A::Calendar>>(
216        &self,
217        other: &Date<B>,
218        largest_unit: DateDurationUnit,
219        smallest_unit: DateDurationUnit,
220    ) -> DateDuration<A::Calendar> {
221        self.calendar.as_calendar().until(
222            self.inner(),
223            other.inner(),
224            other.calendar.as_calendar(),
225            largest_unit,
226            smallest_unit,
227        )
228    }
229
230    #[inline]
235    pub fn year(&self) -> types::YearInfo {
236        self.calendar.as_calendar().year_info(&self.inner).into()
237    }
238
239    #[inline]
244    pub fn extended_year(&self) -> i32 {
245        self.calendar.as_calendar().extended_year(&self.inner)
246    }
247
248    #[inline]
250    pub fn is_in_leap_year(&self) -> bool {
251        self.calendar.as_calendar().is_in_leap_year(&self.inner)
252    }
253
254    #[inline]
256    pub fn month(&self) -> types::MonthInfo {
257        self.calendar.as_calendar().month(&self.inner)
258    }
259
260    #[inline]
262    pub fn day_of_month(&self) -> types::DayOfMonth {
263        self.calendar.as_calendar().day_of_month(&self.inner)
264    }
265
266    #[inline]
268    pub fn day_of_year(&self) -> types::DayOfYear {
269        self.calendar.as_calendar().day_of_year(&self.inner)
270    }
271
272    #[inline]
281    pub fn from_raw(inner: <A::Calendar as Calendar>::DateInner, calendar: A) -> Self {
282        Self { inner, calendar }
283    }
284
285    #[inline]
287    pub fn inner(&self) -> &<A::Calendar as Calendar>::DateInner {
288        &self.inner
289    }
290
291    #[inline]
293    pub fn calendar(&self) -> &A::Calendar {
294        self.calendar.as_calendar()
295    }
296
297    #[inline]
301    pub fn calendar_wrapper(&self) -> &A {
302        &self.calendar
303    }
304}
305
306impl<A: AsCalendar<Calendar = C>, C: Calendar<Year = EraYear>> Date<A> {
307    pub fn era_year(&self) -> EraYear {
309        self.calendar.as_calendar().year_info(self.inner())
310    }
311}
312
313impl<A: AsCalendar<Calendar = C>, C: Calendar<Year = CyclicYear>> Date<A> {
314    pub fn cyclic_year(&self) -> CyclicYear {
316        self.calendar.as_calendar().year_info(self.inner())
317    }
318}
319
320impl Date<Iso> {
321    pub fn week_of_year(&self) -> IsoWeekOfYear {
340        let week_of = WeekCalculator::ISO
341            .week_of(
342                Iso::days_in_provided_year(self.inner.0.year.saturating_sub(1)),
343                self.days_in_year(),
344                self.day_of_year().0,
345                self.day_of_week(),
346            )
347            .unwrap_or_else(|_| {
348                debug_assert!(false);
350                WeekOf {
351                    week: 1,
352                    unit: crate::week::RelativeUnit::Current,
353                }
354            });
355
356        IsoWeekOfYear {
357            week_number: week_of.week,
358            iso_year: match week_of.unit {
359                RelativeUnit::Current => self.inner.0.year,
360                RelativeUnit::Next => self.inner.0.year.saturating_add(1),
361                RelativeUnit::Previous => self.inner.0.year.saturating_sub(1),
362            },
363        }
364    }
365}
366
367impl<C: IntoAnyCalendar> Date<C> {
368    pub fn to_any(self) -> Date<AnyCalendar> {
370        Date::from_raw(
371            self.calendar.date_to_any(&self.inner),
372            self.calendar.to_any(),
373        )
374    }
375}
376
377impl<A: AsCalendar> Date<A> {
378    #[cfg(feature = "alloc")]
382    pub fn into_ref_counted(self) -> Date<Rc<A>> {
383        Date::from_raw(self.inner, Rc::new(self.calendar))
384    }
385
386    #[cfg(feature = "alloc")]
390    pub fn into_atomic_ref_counted(self) -> Date<Arc<A>> {
391        Date::from_raw(self.inner, Arc::new(self.calendar))
392    }
393
394    pub fn as_borrowed(&self) -> Date<Ref<A>> {
399        Date::from_raw(self.inner, Ref(&self.calendar))
400    }
401}
402
403impl<C, A, B> PartialEq<Date<B>> for Date<A>
404where
405    C: Calendar,
406    A: AsCalendar<Calendar = C>,
407    B: AsCalendar<Calendar = C>,
408{
409    fn eq(&self, other: &Date<B>) -> bool {
410        self.inner.eq(&other.inner)
411    }
412}
413
414impl<A: AsCalendar> Eq for Date<A> {}
415
416impl<C, A, B> PartialOrd<Date<B>> for Date<A>
417where
418    C: Calendar,
419    C::DateInner: PartialOrd,
420    A: AsCalendar<Calendar = C>,
421    B: AsCalendar<Calendar = C>,
422{
423    fn partial_cmp(&self, other: &Date<B>) -> Option<core::cmp::Ordering> {
424        self.inner.partial_cmp(&other.inner)
425    }
426}
427
428impl<C, A> Ord for Date<A>
429where
430    C: Calendar,
431    C::DateInner: Ord,
432    A: AsCalendar<Calendar = C>,
433{
434    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
435        self.inner.cmp(&other.inner)
436    }
437}
438
439impl<A: AsCalendar> fmt::Debug for Date<A> {
440    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
441        let month = self.month().ordinal;
442        let day = self.day_of_month().0;
443        let calendar = self.calendar.as_calendar().debug_name();
444        match self.year() {
445            types::YearInfo::Era(EraYear { year, era, .. }) => {
446                write!(
447                    f,
448                    "Date({year}-{month}-{day}, {era} era, for calendar {calendar})"
449                )
450            }
451            types::YearInfo::Cyclic(CyclicYear { year, related_iso }) => {
452                write!(
453                    f,
454                    "Date({year}-{month}-{day}, ISO year {related_iso}, for calendar {calendar})"
455                )
456            }
457        }
458    }
459}
460
461impl<A: AsCalendar + Clone> Clone for Date<A> {
462    fn clone(&self) -> Self {
463        Self {
464            inner: self.inner,
465            calendar: self.calendar.clone(),
466        }
467    }
468}
469
470impl<A> Copy for Date<A> where A: AsCalendar + Copy {}
471
472#[cfg(test)]
473mod tests {
474    use super::*;
475    use crate::types::Weekday;
476
477    #[test]
478    fn test_ord() {
479        let dates_in_order = [
480            Date::try_new_iso(-10, 1, 1).unwrap(),
481            Date::try_new_iso(-10, 1, 2).unwrap(),
482            Date::try_new_iso(-10, 2, 1).unwrap(),
483            Date::try_new_iso(-1, 1, 1).unwrap(),
484            Date::try_new_iso(-1, 1, 2).unwrap(),
485            Date::try_new_iso(-1, 2, 1).unwrap(),
486            Date::try_new_iso(0, 1, 1).unwrap(),
487            Date::try_new_iso(0, 1, 2).unwrap(),
488            Date::try_new_iso(0, 2, 1).unwrap(),
489            Date::try_new_iso(1, 1, 1).unwrap(),
490            Date::try_new_iso(1, 1, 2).unwrap(),
491            Date::try_new_iso(1, 2, 1).unwrap(),
492            Date::try_new_iso(10, 1, 1).unwrap(),
493            Date::try_new_iso(10, 1, 2).unwrap(),
494            Date::try_new_iso(10, 2, 1).unwrap(),
495        ];
496        for (i, i_date) in dates_in_order.iter().enumerate() {
497            for (j, j_date) in dates_in_order.iter().enumerate() {
498                let result1 = i_date.cmp(j_date);
499                let result2 = j_date.cmp(i_date);
500                assert_eq!(result1.reverse(), result2);
501                assert_eq!(i.cmp(&j), i_date.cmp(j_date));
502            }
503        }
504    }
505
506    #[test]
507    fn test_day_of_week() {
508        assert_eq!(
510            Date::try_new_iso(2021, 6, 23).unwrap().day_of_week(),
511            Weekday::Wednesday,
512        );
513        assert_eq!(
515            Date::try_new_iso(1983, 2, 2).unwrap().day_of_week(),
516            Weekday::Wednesday,
517        );
518        assert_eq!(
520            Date::try_new_iso(2020, 1, 21).unwrap().day_of_week(),
521            Weekday::Tuesday,
522        );
523    }
524}