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}