Skip to content

Commit ca0313b

Browse files
Expose Date to/from RataDie (#6369)
Currently we use ISO dates as the "exchange format". For example, when converting between calendars, we convert through ISO. Most calendars implement ISO conversion through Rata Die, so we should skip that step. It's also useful to expose this publicly. Right now we expose to/from fixed for ISO only, but the code is there to do this for every calendar.
1 parent 48b04cb commit ca0313b

36 files changed

+1007
-752
lines changed

components/calendar/src/any_calendar.rs

Lines changed: 67 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
//! Module for working with multiple calendars at once
66
77
use crate::cal::hijri::HijriObservationalLocation;
8+
use crate::cal::iso::IsoDateInner;
89
use crate::cal::{
910
Buddhist, Chinese, Coptic, Dangi, Ethiopian, EthiopianEraStyle, Gregorian, Hebrew, HijriCivil,
1011
HijriObservational, HijriTabular, HijriUmmAlQura, Indian, Iso, Japanese, JapaneseExtended,
@@ -194,92 +195,56 @@ macro_rules! match_cal_and_date {
194195
};
195196
}
196197

198+
macro_rules! match_cal {
199+
(match $cal:ident: ($cal_matched:ident) => $e:expr) => {
200+
match $cal {
201+
&Self::Buddhist(ref $cal_matched) => AnyDateInner::Buddhist($e),
202+
&Self::Chinese(ref $cal_matched) => AnyDateInner::Chinese($e),
203+
&Self::Coptic(ref $cal_matched) => AnyDateInner::Coptic($e),
204+
&Self::Dangi(ref $cal_matched) => AnyDateInner::Dangi($e),
205+
&Self::Ethiopian(ref $cal_matched) => AnyDateInner::Ethiopian($e),
206+
&Self::Gregorian(ref $cal_matched) => AnyDateInner::Gregorian($e),
207+
&Self::Hebrew(ref $cal_matched) => AnyDateInner::Hebrew($e),
208+
&Self::Indian(ref $cal_matched) => AnyDateInner::Indian($e),
209+
&Self::HijriCivil(ref $cal_matched) => AnyDateInner::HijriCivil($e),
210+
&Self::HijriObservational(ref $cal_matched) => AnyDateInner::HijriObservational($e),
211+
&Self::HijriTabular(ref $cal_matched) => AnyDateInner::HijriTabular($e),
212+
&Self::HijriUmmAlQura(ref $cal_matched) => AnyDateInner::HijriUmmAlQura($e),
213+
&Self::Iso(ref $cal_matched) => AnyDateInner::Iso($e),
214+
&Self::Japanese(ref $cal_matched) => AnyDateInner::Japanese($e),
215+
&Self::JapaneseExtended(ref $cal_matched) => AnyDateInner::JapaneseExtended($e),
216+
&Self::Persian(ref $cal_matched) => AnyDateInner::Persian($e),
217+
&Self::Roc(ref $cal_matched) => AnyDateInner::Roc($e),
218+
}
219+
};
220+
}
221+
197222
impl Calendar for AnyCalendar {
198223
type DateInner = AnyDateInner;
199-
fn date_from_codes(
224+
fn from_codes(
200225
&self,
201226
era: Option<&str>,
202227
year: i32,
203228
month_code: types::MonthCode,
204229
day: u8,
205230
) -> Result<Self::DateInner, DateError> {
206-
let ret = match *self {
207-
Self::Buddhist(ref c) => {
208-
AnyDateInner::Buddhist(c.date_from_codes(era, year, month_code, day)?)
209-
}
210-
Self::Chinese(ref c) => {
211-
AnyDateInner::Chinese(c.date_from_codes(era, year, month_code, day)?)
212-
}
213-
Self::Coptic(ref c) => {
214-
AnyDateInner::Coptic(c.date_from_codes(era, year, month_code, day)?)
215-
}
216-
Self::Dangi(ref c) => {
217-
AnyDateInner::Dangi(c.date_from_codes(era, year, month_code, day)?)
218-
}
219-
Self::Ethiopian(ref c) => {
220-
AnyDateInner::Ethiopian(c.date_from_codes(era, year, month_code, day)?)
221-
}
222-
Self::Gregorian(ref c) => {
223-
AnyDateInner::Gregorian(c.date_from_codes(era, year, month_code, day)?)
224-
}
225-
Self::Hebrew(ref c) => {
226-
AnyDateInner::Hebrew(c.date_from_codes(era, year, month_code, day)?)
227-
}
228-
Self::Indian(ref c) => {
229-
AnyDateInner::Indian(c.date_from_codes(era, year, month_code, day)?)
230-
}
231-
Self::HijriCivil(ref c) => {
232-
AnyDateInner::HijriCivil(c.date_from_codes(era, year, month_code, day)?)
233-
}
234-
Self::HijriObservational(ref c) => {
235-
AnyDateInner::HijriObservational(c.date_from_codes(era, year, month_code, day)?)
236-
}
237-
Self::HijriTabular(ref c) => {
238-
AnyDateInner::HijriTabular(c.date_from_codes(era, year, month_code, day)?)
239-
}
240-
Self::HijriUmmAlQura(ref c) => {
241-
AnyDateInner::HijriUmmAlQura(c.date_from_codes(era, year, month_code, day)?)
242-
}
243-
Self::Iso(ref c) => AnyDateInner::Iso(c.date_from_codes(era, year, month_code, day)?),
244-
Self::Japanese(ref c) => {
245-
AnyDateInner::Japanese(c.date_from_codes(era, year, month_code, day)?)
246-
}
247-
Self::JapaneseExtended(ref c) => {
248-
AnyDateInner::JapaneseExtended(c.date_from_codes(era, year, month_code, day)?)
249-
}
250-
Self::Persian(ref c) => {
251-
AnyDateInner::Persian(c.date_from_codes(era, year, month_code, day)?)
252-
}
253-
Self::Roc(ref c) => AnyDateInner::Roc(c.date_from_codes(era, year, month_code, day)?),
254-
};
255-
Ok(ret)
231+
Ok(match_cal!(match self: (c) => c.from_codes(era, year, month_code, day)?))
256232
}
257-
fn date_from_iso(&self, iso: Date<Iso>) -> AnyDateInner {
258-
match *self {
259-
Self::Buddhist(ref c) => AnyDateInner::Buddhist(c.date_from_iso(iso)),
260-
Self::Chinese(ref c) => AnyDateInner::Chinese(c.date_from_iso(iso)),
261-
Self::Coptic(ref c) => AnyDateInner::Coptic(c.date_from_iso(iso)),
262-
Self::Dangi(ref c) => AnyDateInner::Dangi(c.date_from_iso(iso)),
263-
Self::Ethiopian(ref c) => AnyDateInner::Ethiopian(c.date_from_iso(iso)),
264-
Self::Gregorian(ref c) => AnyDateInner::Gregorian(c.date_from_iso(iso)),
265-
Self::Hebrew(ref c) => AnyDateInner::Hebrew(c.date_from_iso(iso)),
266-
Self::Indian(ref c) => AnyDateInner::Indian(c.date_from_iso(iso)),
267-
Self::HijriCivil(ref c) => AnyDateInner::HijriCivil(c.date_from_iso(iso)),
268-
Self::HijriObservational(ref c) => {
269-
AnyDateInner::HijriObservational(c.date_from_iso(iso))
270-
}
271-
Self::HijriTabular(ref c) => AnyDateInner::HijriTabular(c.date_from_iso(iso)),
272-
Self::HijriUmmAlQura(ref c) => AnyDateInner::HijriUmmAlQura(c.date_from_iso(iso)),
273-
Self::Iso(ref c) => AnyDateInner::Iso(c.date_from_iso(iso)),
274-
Self::Japanese(ref c) => AnyDateInner::Japanese(c.date_from_iso(iso)),
275-
Self::JapaneseExtended(ref c) => AnyDateInner::JapaneseExtended(c.date_from_iso(iso)),
276-
Self::Persian(ref c) => AnyDateInner::Persian(c.date_from_iso(iso)),
277-
Self::Roc(ref c) => AnyDateInner::Roc(c.date_from_iso(iso)),
278-
}
233+
234+
fn from_iso(&self, iso: IsoDateInner) -> AnyDateInner {
235+
match_cal!(match self: (c) => c.from_iso(iso))
236+
}
237+
238+
fn from_rata_die(&self, rd: calendrical_calculations::rata_die::RataDie) -> Self::DateInner {
239+
match_cal!(match self: (c) => c.from_rata_die(rd))
240+
}
241+
242+
fn to_rata_die(&self, date: &Self::DateInner) -> calendrical_calculations::rata_die::RataDie {
243+
match_cal_and_date!(match (self, date): (c, d) => c.to_rata_die(d))
279244
}
280245

281-
fn date_to_iso(&self, date: &Self::DateInner) -> Date<Iso> {
282-
match_cal_and_date!(match (self, date): (c, d) => c.date_to_iso(d))
246+
fn to_iso(&self, date: &Self::DateInner) -> IsoDateInner {
247+
match_cal_and_date!(match (self, date): (c, d) => c.to_iso(d))
283248
}
284249

285250
fn months_in_year(&self, date: &Self::DateInner) -> u8 {
@@ -296,57 +261,53 @@ impl Calendar for AnyCalendar {
296261

297262
fn offset_date(&self, date: &mut Self::DateInner, offset: DateDuration<Self>) {
298263
match (self, date) {
299-
(Self::Buddhist(c), &mut AnyDateInner::Buddhist(ref mut d)) => {
300-
c.offset_date(d, offset.cast_unit())
301-
}
302-
(Self::Chinese(c), &mut AnyDateInner::Chinese(ref mut d)) => {
303-
c.offset_date(d, offset.cast_unit())
304-
}
305-
(Self::Coptic(c), &mut AnyDateInner::Coptic(ref mut d)) => {
264+
(Self::Buddhist(c), AnyDateInner::Buddhist(ref mut d)) => {
306265
c.offset_date(d, offset.cast_unit())
307266
}
308-
(Self::Dangi(c), &mut AnyDateInner::Dangi(ref mut d)) => {
267+
(Self::Chinese(c), AnyDateInner::Chinese(ref mut d)) => {
309268
c.offset_date(d, offset.cast_unit())
310269
}
311-
(Self::Ethiopian(c), &mut AnyDateInner::Ethiopian(ref mut d)) => {
270+
(Self::Coptic(c), AnyDateInner::Coptic(ref mut d)) => {
312271
c.offset_date(d, offset.cast_unit())
313272
}
314-
(Self::Gregorian(c), &mut AnyDateInner::Gregorian(ref mut d)) => {
273+
(Self::Dangi(c), AnyDateInner::Dangi(ref mut d)) => {
315274
c.offset_date(d, offset.cast_unit())
316275
}
317-
(Self::Hebrew(c), &mut AnyDateInner::Hebrew(ref mut d)) => {
276+
(Self::Ethiopian(c), AnyDateInner::Ethiopian(ref mut d)) => {
318277
c.offset_date(d, offset.cast_unit())
319278
}
320-
(Self::Indian(c), &mut AnyDateInner::Indian(ref mut d)) => {
279+
(Self::Gregorian(c), AnyDateInner::Gregorian(ref mut d)) => {
321280
c.offset_date(d, offset.cast_unit())
322281
}
323-
(Self::HijriCivil(c), &mut AnyDateInner::HijriCivil(ref mut d)) => {
282+
(Self::Hebrew(c), AnyDateInner::Hebrew(ref mut d)) => {
324283
c.offset_date(d, offset.cast_unit())
325284
}
326-
(Self::HijriObservational(c), &mut AnyDateInner::HijriObservational(ref mut d)) => {
285+
(Self::Indian(c), AnyDateInner::Indian(ref mut d)) => {
327286
c.offset_date(d, offset.cast_unit())
328287
}
329-
(Self::HijriTabular(c), &mut AnyDateInner::HijriTabular(ref mut d)) => {
288+
(Self::HijriCivil(c), AnyDateInner::HijriCivil(ref mut d)) => {
330289
c.offset_date(d, offset.cast_unit())
331290
}
332-
(Self::HijriUmmAlQura(c), &mut AnyDateInner::HijriUmmAlQura(ref mut d)) => {
291+
(Self::HijriObservational(c), AnyDateInner::HijriObservational(ref mut d)) => {
333292
c.offset_date(d, offset.cast_unit())
334293
}
335-
(Self::Iso(c), &mut AnyDateInner::Iso(ref mut d)) => {
294+
(Self::HijriTabular(c), AnyDateInner::HijriTabular(ref mut d)) => {
336295
c.offset_date(d, offset.cast_unit())
337296
}
338-
(Self::Japanese(c), &mut AnyDateInner::Japanese(ref mut d)) => {
297+
(Self::HijriUmmAlQura(c), AnyDateInner::HijriUmmAlQura(ref mut d)) => {
339298
c.offset_date(d, offset.cast_unit())
340299
}
341-
(Self::JapaneseExtended(c), &mut AnyDateInner::JapaneseExtended(ref mut d)) => {
300+
(Self::Iso(c), AnyDateInner::Iso(ref mut d)) => c.offset_date(d, offset.cast_unit()),
301+
(Self::Japanese(c), AnyDateInner::Japanese(ref mut d)) => {
342302
c.offset_date(d, offset.cast_unit())
343303
}
344-
(Self::Persian(c), &mut AnyDateInner::Persian(ref mut d)) => {
304+
(Self::JapaneseExtended(c), AnyDateInner::JapaneseExtended(ref mut d)) => {
345305
c.offset_date(d, offset.cast_unit())
346306
}
347-
(Self::Roc(c), &mut AnyDateInner::Roc(ref mut d)) => {
307+
(Self::Persian(c), AnyDateInner::Persian(ref mut d)) => {
348308
c.offset_date(d, offset.cast_unit())
349309
}
310+
(Self::Roc(c), AnyDateInner::Roc(ref mut d)) => c.offset_date(d, offset.cast_unit()),
350311
// This is only reached from misuse of from_raw, a semi-internal api
351312
#[allow(clippy::panic)]
352313
(_, d) => panic!(
@@ -494,11 +455,11 @@ impl Calendar for AnyCalendar {
494455
.cast_unit(),
495456
_ => {
496457
// attempt to convert
497-
let iso = calendar2.date_to_iso(date2);
458+
let iso = calendar2.to_iso(date2);
498459

499460
match_cal_and_date!(match (self, date1):
500461
(c1, d1) => {
501-
let d2 = c1.date_from_iso(iso);
462+
let d2 = c1.from_iso(iso);
502463
let until = c1.until(d1, &d2, c1, largest_unit, smallest_unit);
503464
until.cast_unit::<AnyCalendar>()
504465
}
@@ -709,19 +670,17 @@ impl AnyCalendar {
709670
Self::Roc(_) => AnyCalendarKind::Roc,
710671
}
711672
}
673+
}
712674

713-
/// Given an AnyCalendar date, convert that date to another AnyCalendar date in this calendar,
714-
/// if conversion is needed
715-
pub fn convert_any_date<'a>(
716-
&'a self,
717-
date: &Date<impl AsCalendar<Calendar = AnyCalendar>>,
718-
) -> Date<Ref<'a, AnyCalendar>> {
719-
if self.kind() != date.calendar.as_calendar().kind() {
720-
Date::new_from_iso(date.to_iso(), Ref(self))
675+
impl<C: AsCalendar<Calendar = AnyCalendar>> Date<C> {
676+
/// Convert this `Date<AnyCalendar>` to another `AnyCalendar`, if conversion is needed
677+
pub fn convert_any<'a>(&self, calendar: &'a AnyCalendar) -> Date<Ref<'a, AnyCalendar>> {
678+
if calendar.kind() != self.calendar.as_calendar().kind() {
679+
Date::new_from_iso(self.to_iso(), Ref(calendar))
721680
} else {
722681
Date {
723-
inner: date.inner,
724-
calendar: Ref(self),
682+
inner: self.inner,
683+
calendar: Ref(calendar),
725684
}
726685
}
727686
}

components/calendar/src/cal/buddhist.rs

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use crate::cal::iso::{Iso, IsoDateInner};
2121
use crate::calendar_arithmetic::ArithmeticDate;
2222
use crate::error::DateError;
2323
use crate::{types, Calendar, Date, DateDuration, DateDurationUnit, RangeError};
24+
use calendrical_calculations::rata_die::RataDie;
2425
use tinystr::tinystr;
2526

2627
/// The number of years the Buddhist Era is ahead of C.E. by
@@ -52,7 +53,7 @@ pub struct Buddhist;
5253
impl Calendar for Buddhist {
5354
type DateInner = IsoDateInner;
5455

55-
fn date_from_codes(
56+
fn from_codes(
5657
&self,
5758
era: Option<&str>,
5859
year: i32,
@@ -67,12 +68,21 @@ impl Calendar for Buddhist {
6768

6869
ArithmeticDate::new_from_codes(self, year, month_code, day).map(IsoDateInner)
6970
}
70-
fn date_from_iso(&self, iso: Date<Iso>) -> IsoDateInner {
71-
*iso.inner()
71+
72+
fn from_iso(&self, iso: IsoDateInner) -> Self::DateInner {
73+
iso
74+
}
75+
76+
fn to_iso(&self, date: &Self::DateInner) -> IsoDateInner {
77+
*date
78+
}
79+
80+
fn from_rata_die(&self, rd: RataDie) -> Self::DateInner {
81+
Iso.from_rata_die(rd)
7282
}
7383

74-
fn date_to_iso(&self, date: &Self::DateInner) -> Date<Iso> {
75-
Date::from_raw(*date, Iso)
84+
fn to_rata_die(&self, date: &Self::DateInner) -> RataDie {
85+
Iso.to_rata_die(date)
7686
}
7787

7888
fn months_in_year(&self, date: &Self::DateInner) -> u8 {
@@ -177,10 +187,10 @@ mod test {
177187
fn test_buddhist_roundtrip_near_rd_zero() {
178188
for i in -10000..=10000 {
179189
let rd = RataDie::new(i);
180-
let iso1 = Iso::from_fixed(rd);
190+
let iso1 = Date::from_rata_die(rd, Iso);
181191
let buddhist = iso1.to_calendar(Buddhist);
182192
let iso2 = buddhist.to_calendar(Iso);
183-
let result = Iso::to_fixed(iso2);
193+
let result = iso2.to_rata_die();
184194
assert_eq!(rd, result);
185195
}
186196
}
@@ -190,10 +200,10 @@ mod test {
190200
// Buddhist epoch start RD: -198326
191201
for i in -208326..=-188326 {
192202
let rd = RataDie::new(i);
193-
let iso1 = Iso::from_fixed(rd);
203+
let iso1 = Date::from_rata_die(rd, Iso);
194204
let buddhist = iso1.to_calendar(Buddhist);
195205
let iso2 = buddhist.to_calendar(Iso);
196-
let result = Iso::to_fixed(iso2);
206+
let result = iso2.to_rata_die();
197207
assert_eq!(rd, result);
198208
}
199209
}
@@ -202,8 +212,8 @@ mod test {
202212
fn test_buddhist_directionality_near_rd_zero() {
203213
for i in -100..=100 {
204214
for j in -100..=100 {
205-
let iso_i = Iso::from_fixed(RataDie::new(i));
206-
let iso_j = Iso::from_fixed(RataDie::new(j));
215+
let iso_i = Date::from_rata_die(RataDie::new(i), Iso);
216+
let iso_j = Date::from_rata_die(RataDie::new(j), Iso);
207217

208218
let buddhist_i = Date::new_from_iso(iso_i, Buddhist);
209219
let buddhist_j = Date::new_from_iso(iso_j, Buddhist);
@@ -228,8 +238,8 @@ mod test {
228238
// Buddhist epoch start RD: -198326
229239
for i in -198426..=-198226 {
230240
for j in -198426..=-198226 {
231-
let iso_i = Iso::from_fixed(RataDie::new(i));
232-
let iso_j = Iso::from_fixed(RataDie::new(j));
241+
let iso_i = Date::from_rata_die(RataDie::new(i), Iso);
242+
let iso_j = Date::from_rata_die(RataDie::new(j), Iso);
233243

234244
let buddhist_i = Date::new_from_iso(iso_i, Buddhist);
235245
let buddhist_j = Date::new_from_iso(iso_j, Buddhist);

0 commit comments

Comments
 (0)