@@ -8,8 +8,9 @@ use crate::cal::iso::IsoDateInner;
88use crate :: cal:: * ;
99use crate :: error:: DateError ;
1010use crate :: options:: DateFromFieldsOptions ;
11+ use crate :: options:: { DateAddOptions , DateDifferenceOptions } ;
1112use crate :: types:: { DateFields , YearInfo } ;
12- use crate :: { types, AsCalendar , Calendar , Date , DateDuration , DateDurationUnit , Ref } ;
13+ use crate :: { types, AsCalendar , Calendar , Date , Ref } ;
1314
1415use crate :: preferences:: { CalendarAlgorithm , HijriCalendarAlgorithm } ;
1516use icu_locale_core:: preferences:: define_preferences;
@@ -211,10 +212,45 @@ macro_rules! match_cal {
211212 } ;
212213}
213214
215+ /// Error returned when comparing two [`Date`]s with [`AnyCalendar`].
216+ #[ derive( Clone , Copy , PartialEq , Debug ) ]
217+ #[ non_exhaustive]
218+ #[ doc( hidden) ] // unstable, not yet graduated
219+ pub enum AnyCalendarDifferenceError {
220+ /// The calendars of the two dates being compared are not equal.
221+ ///
222+ /// To compare dates in different calendars, convert them to the same calendar first.
223+ ///
224+ /// # Examples
225+ ///
226+ /// ```
227+ /// use icu::calendar::Date;
228+ /// use icu::calendar::cal::AnyCalendarDifferenceError;
229+ ///
230+ /// let d1 = Date::try_new_gregorian(2000, 1, 1).unwrap().to_any();
231+ /// let d2 = Date::try_new_hebrew(5780, 1, 1).unwrap().to_any();
232+ ///
233+ /// assert!(matches!(
234+ /// d1.try_until_with_options(&d2, Default::default()),
235+ /// Err(AnyCalendarDifferenceError::MismatchedCalendars),
236+ /// ));
237+ ///
238+ /// // To compare the dates, convert them to the same calendar,
239+ /// // such as ISO.
240+ ///
241+ /// assert!(matches!(
242+ /// d1.to_iso().try_until_with_options(&d2.to_iso(), Default::default()),
243+ /// Ok(_)
244+ /// ));
245+ /// ```
246+ MismatchedCalendars ,
247+ }
248+
214249impl crate :: cal:: scaffold:: UnstableSealed for AnyCalendar { }
215250impl Calendar for AnyCalendar {
216251 type DateInner = AnyDateInner ;
217252 type Year = YearInfo ;
253+ type DifferenceError = AnyCalendarDifferenceError ;
218254
219255 fn from_fields (
220256 & self ,
@@ -252,34 +288,58 @@ impl Calendar for AnyCalendar {
252288 match_cal_and_date ! ( match ( self , date) : ( c, d) => c. days_in_month( d) )
253289 }
254290
255- fn offset_date ( & self , date : & mut Self :: DateInner , offset : DateDuration ) {
256- match ( self , date) {
257- ( Self :: Buddhist ( c) , AnyDateInner :: Buddhist ( ref mut d) ) => c. offset_date ( d, offset) ,
258- ( Self :: Chinese ( c) , AnyDateInner :: Chinese ( ref mut d) ) => c. offset_date ( d, offset) ,
259- ( Self :: Coptic ( c) , AnyDateInner :: Coptic ( ref mut d) ) => c. offset_date ( d, offset) ,
260- ( Self :: Dangi ( c) , AnyDateInner :: Dangi ( ref mut d) ) => c. offset_date ( d, offset) ,
261- ( Self :: Ethiopian ( c) , AnyDateInner :: Ethiopian ( ref mut d) ) => c. offset_date ( d, offset) ,
262- ( Self :: Gregorian ( c) , AnyDateInner :: Gregorian ( ref mut d) ) => c. offset_date ( d, offset) ,
263- ( Self :: Hebrew ( c) , AnyDateInner :: Hebrew ( ref mut d) ) => c. offset_date ( d, offset) ,
264- ( Self :: Indian ( c) , AnyDateInner :: Indian ( ref mut d) ) => c. offset_date ( d, offset) ,
265- ( Self :: HijriTabular ( c) , & mut AnyDateInner :: HijriTabular ( ref mut d, sighting) )
266- if c. 0 == sighting =>
291+ fn add (
292+ & self ,
293+ date : & Self :: DateInner ,
294+ duration : types:: DateDuration ,
295+ options : DateAddOptions ,
296+ ) -> Result < Self :: DateInner , DateError > {
297+ let mut date = * date;
298+ match ( self , & mut date) {
299+ ( Self :: Buddhist ( c) , AnyDateInner :: Buddhist ( ref mut d) ) => {
300+ * d = c. add ( d, duration, options) ?
301+ }
302+ ( Self :: Chinese ( c) , AnyDateInner :: Chinese ( ref mut d) ) => {
303+ * d = c. add ( d, duration, options) ?
304+ }
305+ ( Self :: Coptic ( c) , AnyDateInner :: Coptic ( ref mut d) ) => {
306+ * d = c. add ( d, duration, options) ?
307+ }
308+ ( Self :: Dangi ( c) , AnyDateInner :: Dangi ( ref mut d) ) => * d = c. add ( d, duration, options) ?,
309+ ( Self :: Ethiopian ( c) , AnyDateInner :: Ethiopian ( ref mut d) ) => {
310+ * d = c. add ( d, duration, options) ?
311+ }
312+ ( Self :: Gregorian ( c) , AnyDateInner :: Gregorian ( ref mut d) ) => {
313+ * d = c. add ( d, duration, options) ?
314+ }
315+ ( Self :: Hebrew ( c) , AnyDateInner :: Hebrew ( ref mut d) ) => {
316+ * d = c. add ( d, duration, options) ?
317+ }
318+ ( Self :: Indian ( c) , AnyDateInner :: Indian ( ref mut d) ) => {
319+ * d = c. add ( d, duration, options) ?
320+ }
321+ ( Self :: HijriTabular ( c) , AnyDateInner :: HijriTabular ( ref mut d, sighting) )
322+ if c. 0 == * sighting =>
267323 {
268- c . offset_date ( d, offset )
324+ * d = c . add ( d, duration , options ) ?
269325 }
270326 ( Self :: HijriSimulated ( c) , AnyDateInner :: HijriSimulated ( ref mut d) ) => {
271- c . offset_date ( d, offset )
327+ * d = c . add ( d, duration , options ) ?
272328 }
273329 ( Self :: HijriUmmAlQura ( c) , AnyDateInner :: HijriUmmAlQura ( ref mut d) ) => {
274- c. offset_date ( d, offset)
330+ * d = c. add ( d, duration, options) ?
331+ }
332+ ( Self :: Iso ( c) , AnyDateInner :: Iso ( ref mut d) ) => * d = c. add ( d, duration, options) ?,
333+ ( Self :: Japanese ( c) , AnyDateInner :: Japanese ( ref mut d) ) => {
334+ * d = c. add ( d, duration, options) ?
275335 }
276- ( Self :: Iso ( c) , AnyDateInner :: Iso ( ref mut d) ) => c. offset_date ( d, offset) ,
277- ( Self :: Japanese ( c) , AnyDateInner :: Japanese ( ref mut d) ) => c. offset_date ( d, offset) ,
278336 ( Self :: JapaneseExtended ( c) , AnyDateInner :: JapaneseExtended ( ref mut d) ) => {
279- c . offset_date ( d, offset )
337+ * d = c . add ( d, duration , options ) ?
280338 }
281- ( Self :: Persian ( c) , AnyDateInner :: Persian ( ref mut d) ) => c. offset_date ( d, offset) ,
282- ( Self :: Roc ( c) , AnyDateInner :: Roc ( ref mut d) ) => c. offset_date ( d, offset) ,
339+ ( Self :: Persian ( c) , AnyDateInner :: Persian ( ref mut d) ) => {
340+ * d = c. add ( d, duration, options) ?
341+ }
342+ ( Self :: Roc ( c) , AnyDateInner :: Roc ( ref mut d) ) => * d = c. add ( d, duration, options) ?,
283343 // This is only reached from misuse of from_raw, a semi-internal api
284344 #[ expect( clippy:: panic) ]
285345 ( _, d) => panic ! (
@@ -288,121 +348,77 @@ impl Calendar for AnyCalendar {
288348 d. kind( ) . debug_name( )
289349 ) ,
290350 }
351+ Ok ( date)
291352 }
292353
293354 fn until (
294355 & self ,
295356 date1 : & Self :: DateInner ,
296357 date2 : & Self :: DateInner ,
297- calendar2 : & Self ,
298- largest_unit : DateDurationUnit ,
299- smallest_unit : DateDurationUnit ,
300- ) -> DateDuration {
301- match ( self , calendar2, date1, date2) {
302- (
303- Self :: Buddhist ( c1) ,
304- Self :: Buddhist ( c2) ,
305- AnyDateInner :: Buddhist ( d1) ,
306- AnyDateInner :: Buddhist ( d2) ,
307- ) => c1. until ( d1, d2, c2, largest_unit, smallest_unit) ,
308- (
309- Self :: Chinese ( c1) ,
310- Self :: Chinese ( c2) ,
311- AnyDateInner :: Chinese ( d1) ,
312- AnyDateInner :: Chinese ( d2) ,
313- ) => c1. until ( d1, d2, c2, largest_unit, smallest_unit) ,
314- (
315- Self :: Coptic ( c1) ,
316- Self :: Coptic ( c2) ,
317- AnyDateInner :: Coptic ( d1) ,
318- AnyDateInner :: Coptic ( d2) ,
319- ) => c1. until ( d1, d2, c2, largest_unit, smallest_unit) ,
320- (
321- Self :: Dangi ( c1) ,
322- Self :: Dangi ( c2) ,
323- AnyDateInner :: Dangi ( d1) ,
324- AnyDateInner :: Dangi ( d2) ,
325- ) => c1. until ( d1, d2, c2, largest_unit, smallest_unit) ,
326- (
327- Self :: Ethiopian ( c1) ,
328- Self :: Ethiopian ( c2) ,
329- AnyDateInner :: Ethiopian ( d1) ,
330- AnyDateInner :: Ethiopian ( d2) ,
331- ) => c1. until ( d1, d2, c2, largest_unit, smallest_unit) ,
332- (
333- Self :: Gregorian ( c1) ,
334- Self :: Gregorian ( c2) ,
335- AnyDateInner :: Gregorian ( d1) ,
336- AnyDateInner :: Gregorian ( d2) ,
337- ) => c1. until ( d1, d2, c2, largest_unit, smallest_unit) ,
338- (
339- Self :: Hebrew ( c1) ,
340- Self :: Hebrew ( c2) ,
341- AnyDateInner :: Hebrew ( d1) ,
342- AnyDateInner :: Hebrew ( d2) ,
343- ) => c1. until ( d1, d2, c2, largest_unit, smallest_unit) ,
344- (
345- Self :: Indian ( c1) ,
346- Self :: Indian ( c2) ,
347- AnyDateInner :: Indian ( d1) ,
348- AnyDateInner :: Indian ( d2) ,
349- ) => c1. until ( d1, d2, c2, largest_unit, smallest_unit) ,
358+ options : DateDifferenceOptions ,
359+ ) -> Result < types:: DateDuration , Self :: DifferenceError > {
360+ let Ok ( r) = match ( self , date1, date2) {
361+ ( Self :: Buddhist ( c1) , AnyDateInner :: Buddhist ( d1) , AnyDateInner :: Buddhist ( d2) ) => {
362+ c1. until ( d1, d2, options)
363+ }
364+ ( Self :: Chinese ( c1) , AnyDateInner :: Chinese ( d1) , AnyDateInner :: Chinese ( d2) ) => {
365+ c1. until ( d1, d2, options)
366+ }
367+ ( Self :: Coptic ( c1) , AnyDateInner :: Coptic ( d1) , AnyDateInner :: Coptic ( d2) ) => {
368+ c1. until ( d1, d2, options)
369+ }
370+ ( Self :: Dangi ( c1) , AnyDateInner :: Dangi ( d1) , AnyDateInner :: Dangi ( d2) ) => {
371+ c1. until ( d1, d2, options)
372+ }
373+ ( Self :: Ethiopian ( c1) , AnyDateInner :: Ethiopian ( d1) , AnyDateInner :: Ethiopian ( d2) ) => {
374+ c1. until ( d1, d2, options)
375+ }
376+ ( Self :: Gregorian ( c1) , AnyDateInner :: Gregorian ( d1) , AnyDateInner :: Gregorian ( d2) ) => {
377+ c1. until ( d1, d2, options)
378+ }
379+ ( Self :: Hebrew ( c1) , AnyDateInner :: Hebrew ( d1) , AnyDateInner :: Hebrew ( d2) ) => {
380+ c1. until ( d1, d2, options)
381+ }
382+ ( Self :: Indian ( c1) , AnyDateInner :: Indian ( d1) , AnyDateInner :: Indian ( d2) ) => {
383+ c1. until ( d1, d2, options)
384+ }
350385 (
351386 Self :: HijriTabular ( c1) ,
352- Self :: HijriTabular ( c2) ,
353387 & AnyDateInner :: HijriTabular ( ref d1, s1) ,
354388 & AnyDateInner :: HijriTabular ( ref d2, s2) ,
355- ) if c1. 0 == c2. 0 && c2. 0 == s1 && s1 == s2 => {
356- c1. until ( d1, d2, c2, largest_unit, smallest_unit)
357- }
389+ ) if c1. 0 == s1 && s1 == s2 => c1. until ( d1, d2, options) ,
358390 (
359391 Self :: HijriSimulated ( c1) ,
360- Self :: HijriSimulated ( c2) ,
361392 AnyDateInner :: HijriSimulated ( d1) ,
362393 AnyDateInner :: HijriSimulated ( d2) ,
363- ) => c1. until ( d1, d2, c2 , largest_unit , smallest_unit ) ,
394+ ) => c1. until ( d1, d2, options ) ,
364395 (
365396 Self :: HijriUmmAlQura ( c1) ,
366- Self :: HijriUmmAlQura ( c2) ,
367397 AnyDateInner :: HijriUmmAlQura ( d1) ,
368398 AnyDateInner :: HijriUmmAlQura ( d2) ,
369- ) => c1. until ( d1, d2, c2, largest_unit, smallest_unit) ,
370- ( Self :: Iso ( c1) , Self :: Iso ( c2) , AnyDateInner :: Iso ( d1) , AnyDateInner :: Iso ( d2) ) => {
371- c1. until ( d1, d2, c2, largest_unit, smallest_unit)
399+ ) => c1. until ( d1, d2, options) ,
400+ ( Self :: Iso ( c1) , AnyDateInner :: Iso ( d1) , AnyDateInner :: Iso ( d2) ) => {
401+ c1. until ( d1, d2, options)
402+ }
403+ ( Self :: Japanese ( c1) , AnyDateInner :: Japanese ( d1) , AnyDateInner :: Japanese ( d2) ) => {
404+ c1. until ( d1, d2, options)
372405 }
373- (
374- Self :: Japanese ( c1) ,
375- Self :: Japanese ( c2) ,
376- AnyDateInner :: Japanese ( d1) ,
377- AnyDateInner :: Japanese ( d2) ,
378- ) => c1. until ( d1, d2, c2, largest_unit, smallest_unit) ,
379406 (
380407 Self :: JapaneseExtended ( c1) ,
381- Self :: JapaneseExtended ( c2) ,
382408 AnyDateInner :: JapaneseExtended ( d1) ,
383409 AnyDateInner :: JapaneseExtended ( d2) ,
384- ) => c1. until ( d1, d2, c2, largest_unit, smallest_unit) ,
385- (
386- Self :: Persian ( c1) ,
387- Self :: Persian ( c2) ,
388- AnyDateInner :: Persian ( d1) ,
389- AnyDateInner :: Persian ( d2) ,
390- ) => c1. until ( d1, d2, c2, largest_unit, smallest_unit) ,
391- ( Self :: Roc ( c1) , Self :: Roc ( c2) , AnyDateInner :: Roc ( d1) , AnyDateInner :: Roc ( d2) ) => {
392- c1. until ( d1, d2, c2, largest_unit, smallest_unit)
410+ ) => c1. until ( d1, d2, options) ,
411+ ( Self :: Persian ( c1) , AnyDateInner :: Persian ( d1) , AnyDateInner :: Persian ( d2) ) => {
412+ c1. until ( d1, d2, options)
413+ }
414+ ( Self :: Roc ( c1) , AnyDateInner :: Roc ( d1) , AnyDateInner :: Roc ( d2) ) => {
415+ c1. until ( d1, d2, options)
393416 }
394417 _ => {
395- // attempt to convert
396- let iso = calendar2. to_iso ( date2) ;
397-
398- match_cal_and_date ! ( match ( self , date1) :
399- ( c1, d1) => {
400- let d2 = c1. from_iso( iso) ;
401- c1. until( d1, & d2, c1, largest_unit, smallest_unit)
402- }
403- )
418+ return Err ( AnyCalendarDifferenceError :: MismatchedCalendars ) ;
404419 }
405- }
420+ } ;
421+ Ok ( r)
406422 }
407423
408424 fn year_info ( & self , date : & Self :: DateInner ) -> types:: YearInfo {
0 commit comments