Skip to content

Commit adbe1ed

Browse files
authored
Merge branch 'main' into stateful-surpasses
2 parents 7dc6469 + a572320 commit adbe1ed

File tree

18 files changed

+381
-707
lines changed

18 files changed

+381
-707
lines changed

Cargo.toml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -407,9 +407,11 @@ rust.unused_qualifications = "warn"
407407
# rust.unsafe_op_in_unsafe_fn = "forbid"
408408

409409
[workspace.metadata.cargo-semver-checks.lints]
410-
type_method_marked_deprecated.level = "allow" # allow deprecation in patch releases
411-
trait_method_marked_deprecated.level = "allow" # allow deprecation in patch releases
412-
type_marked_deprecated.level = "allow" # allow deprecation in patch releases
410+
copy_impl_added = "allow"
411+
enum_no_repr_variant_discriminant_changed = "allow" # we don't consider this breaking https://github.com/obi1kenobi/cargo-semver-checks/issues/1376
412+
enum_variant_marked_deprecated = "allow"
413413
struct_field_marked_deprecated = "allow" # allow deprecation in patch releases
414+
trait_method_marked_deprecated = "allow" # allow deprecation in patch releases
414415
type_associated_const_marked_deprecated = "allow" # allow deprecation in patch releases
415-
enum_no_repr_variant_discriminant_changed = "allow" # we don't consider this breaking https://github.com/obi1kenobi/cargo-semver-checks/issues/1376
416+
type_marked_deprecated = "allow" # allow deprecation in patch releases
417+
type_method_marked_deprecated = "allow" # allow deprecation in patch releases

components/calendar/src/any_calendar.rs

Lines changed: 118 additions & 661 deletions
Large diffs are not rendered by default.

components/calendar/src/date.rs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -423,13 +423,19 @@ impl<A: AsCalendar> Date<A> {
423423
Ok(self)
424424
}
425425

426-
/// Calculating the duration between `other - self`
426+
/// Calculating the duration between `other - self`, counting from `self`
427427
///
428428
/// Although this returns a [`Result`], with most fixed calendars, this operation can't fail.
429429
/// In such cases, the error type is [`Infallible`], and the inner value can be safely
430430
/// unwrapped using [`Result::into_ok()`], which is available in nightly Rust as of this
431431
/// writing. In stable Rust, the value can be unwrapped using [pattern matching].
432432
///
433+
/// Note that `a.try_until_with_options(b, ..)` is not necessarily the same as
434+
/// `-b.try_until_with_options(a, ..)`. `a.try_until_with_options(b, ..)`
435+
/// computes a duration starting at `a` by adding years, months, sometimes weeks, and days in order
436+
/// (based on the options) until it reaches `b`. So, `(Sep 30).until(Oct 31)` with `largest_unit = DateDurationUnit::Months`
437+
/// will be a duration of 1 month and 1 day, but `(Oct 31).until(Sep 30)` will be a duration of -1 months.
438+
///
433439
/// # Examples
434440
///
435441
/// ```
@@ -446,6 +452,25 @@ impl<A: AsCalendar> Date<A> {
446452
/// assert_eq!(duration, DateDuration::for_days(2101));
447453
/// ```
448454
///
455+
/// Reversing the order of parameters does not necessarily produce the inverse result:
456+
///
457+
/// ```
458+
/// use icu::calendar::types::DateDuration;
459+
/// use icu::calendar::options::{DateDifferenceOptions, DateDurationUnit};
460+
/// use icu::calendar::Date;
461+
///
462+
/// let d1 = Date::try_new_iso(2025, 9, 30).unwrap();
463+
/// let d2 = Date::try_new_iso(2025, 10, 31).unwrap();
464+
/// let mut options = DateDifferenceOptions::default();
465+
/// options.largest_unit = Some(DateDurationUnit::Months);
466+
///
467+
/// let Ok(duration_forward) = d1.try_until_with_options(&d2, options);
468+
/// let Ok(duration_backward) = d2.try_until_with_options(&d1, options);
469+
///
470+
/// assert_eq!(duration_forward, DateDuration {months: 1, days: 1, ..Default::default()});
471+
/// assert_eq!(duration_backward, DateDuration::for_months(-1));
472+
/// ```
473+
///
449474
/// [`Infallible`]: core::convert::Infallible
450475
/// [pattern matching]: https://doc.rust-lang.org/book/ch19-03-pattern-syntax.html
451476
///

components/datetime/src/scaffold/calendar.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,13 @@ impl FormattableAnyCalendarKind {
352352

353353
#[test]
354354
fn test_calendar_fallback() {
355+
#[allow(non_local_definitions)] // only used in this test
356+
impl PartialEq for FormattableAnyCalendar {
357+
fn eq(&self, other: &Self) -> bool {
358+
self.any_calendar.kind() == other.any_calendar.kind()
359+
}
360+
}
361+
355362
use icu_locale_core::{locale, Locale};
356363
assert_eq!(
357364
FormattableAnyCalendar::try_new(locale!("en-TH-u-ca-iso8601").into()),
@@ -380,7 +387,7 @@ fn test_calendar_fallback() {
380387
}
381388

382389
/// A version of [`AnyCalendar`] for the calendars supported in the any-calendar formatter.
383-
#[derive(Debug, Clone, PartialEq)]
390+
#[derive(Debug, Clone)]
384391
pub(crate) struct FormattableAnyCalendar {
385392
any_calendar: AnyCalendar,
386393
}

components/datetime/src/time_crate.rs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -265,12 +265,7 @@ impl GetField<Option<UtcOffset>> for time::OffsetDateTime {
265265
impl GetField<ZoneNameTimestamp> for time::OffsetDateTime {
266266
#[inline]
267267
fn get_field(&self) -> ZoneNameTimestamp {
268-
ZoneNameTimestamp::from_zoned_date_time_iso(
269-
ZonedDateTime::from_epoch_milliseconds_and_utc_offset(
270-
self.unix_timestamp(),
271-
UtcOffset::zero(),
272-
),
273-
)
268+
ZoneNameTimestamp::from_epoch_seconds(self.unix_timestamp())
274269
}
275270
}
276271

components/time/src/types.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,7 @@ where
312312

313313
const UNIX_EPOCH: RataDie = calendrical_calculations::gregorian::fixed_from_gregorian(1970, 1, 1);
314314

315-
impl Ord for ZonedDateTime<Iso, UtcOffset> {
315+
impl<A: AsCalendar> Ord for ZonedDateTime<A, UtcOffset> {
316316
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
317317
let mut srd = self.date.to_rata_die();
318318
let mut ord = other.date.to_rata_die();
@@ -357,8 +357,13 @@ impl Ord for ZonedDateTime<Iso, UtcOffset> {
357357
.then(self.time.subsecond.cmp(&other.time.subsecond))
358358
}
359359
}
360-
impl PartialOrd for ZonedDateTime<Iso, UtcOffset> {
361-
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
360+
361+
impl<A> PartialOrd<ZonedDateTime<A, UtcOffset>> for ZonedDateTime<A, UtcOffset>
362+
where
363+
A: AsCalendar,
364+
Date<A>: PartialEq<Date<A>>,
365+
{
366+
fn partial_cmp(&self, other: &ZonedDateTime<A, UtcOffset>) -> Option<core::cmp::Ordering> {
362367
Some(self.cmp(other))
363368
}
364369
}

components/time/src/zone/mod.rs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ pub mod windows;
5353
mod zone_name_timestamp;
5454

5555
use icu_calendar::types::RataDie;
56+
use icu_calendar::AsCalendar;
5657
#[cfg(feature = "compiled_data")]
5758
use icu_locale_core::subtags::Region;
5859
#[doc(inline)]
@@ -285,8 +286,8 @@ impl<'a> zerovec::maps::ZeroMapKV<'a> for TimeZone {
285286
/// );
286287
///
287288
/// // ... or by adding a local time
288-
/// let time_zone_at_time = time_zone.at_date_time_iso(DateTime {
289-
/// date: Date::try_new_iso(2023, 12, 2).unwrap(),
289+
/// let time_zone_at_time = time_zone.at_date_time(DateTime {
290+
/// date: Date::try_new_coptic(1996, 12, 2).unwrap(),
290291
/// time: Time::start_of_day(),
291292
/// });
292293
/// ```
@@ -451,16 +452,25 @@ impl TimeZoneInfo<models::Base> {
451452

452453
/// Sets the [`ZoneNameTimestamp`] to the given datetime.
453454
///
454-
/// If the offset is knonw, the datetime is interpreted as a local time,
455+
/// If the offset is known, the datetime is interpreted as a local time,
455456
/// otherwise as UTC. This produces correct results for the vast majority
456457
/// of cases, however close to metazone changes (Eastern Time -> Central Time)
457458
/// it might be incorrect if the offset is not known.
458459
///
459460
/// Also see [`Self::with_zone_name_timestamp`].
460-
pub fn at_date_time_iso(self, date_time: DateTime<Iso>) -> TimeZoneInfo<models::AtTime> {
461+
pub fn at_date_time<C: AsCalendar>(
462+
self,
463+
date_time: DateTime<C>,
464+
) -> TimeZoneInfo<models::AtTime> {
461465
self.at_rd_time(date_time.date.to_rata_die(), date_time.time)
462466
}
463467

468+
/// Use [`Self::at_date_time`].
469+
#[deprecated(since = "2.2.0", note = "use `Self::at_date_time`")]
470+
pub fn at_date_time_iso(self, date_time: DateTime<Iso>) -> TimeZoneInfo<models::AtTime> {
471+
self.at_date_time(date_time)
472+
}
473+
464474
pub(crate) fn at_rd_time(self, rd: RataDie, time: Time) -> TimeZoneInfo<models::AtTime> {
465475
self.with_zone_name_timestamp(ZoneNameTimestamp::from_rd_time_zone(
466476
rd,

components/time/src/zone/zone_name_timestamp.rs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
use core::fmt;
66

77
use icu_calendar::types::RataDie;
8-
use icu_calendar::Iso;
8+
use icu_calendar::{AsCalendar, Iso};
99
use zerovec::ule::AsULE;
1010

1111
use crate::Time;
@@ -84,7 +84,7 @@ impl ZoneNameTimestamp {
8484
/// zone: UtcOffset::zero(),
8585
/// };
8686
///
87-
/// let zone_name_timestamp = ZoneNameTimestamp::from_zoned_date_time_iso(zoned_date_time);
87+
/// let zone_name_timestamp = ZoneNameTimestamp::from_zoned_date_time(zoned_date_time);
8888
///
8989
/// let recovered_zoned_date_time = zone_name_timestamp.to_zoned_date_time_iso();
9090
///
@@ -106,14 +106,22 @@ impl ZoneNameTimestamp {
106106
}
107107

108108
/// Creates an instance of [`ZoneNameTimestamp`] from a [`ZonedDateTime`] with an explicit [`UtcOffset`].
109-
pub fn from_zoned_date_time_iso(zoned_date_time: ZonedDateTime<Iso, UtcOffset>) -> Self {
109+
pub fn from_zoned_date_time<C: AsCalendar>(
110+
zoned_date_time: ZonedDateTime<C, UtcOffset>,
111+
) -> Self {
110112
Self::from_rd_time_zone(
111113
zoned_date_time.date.to_rata_die(),
112114
zoned_date_time.time,
113115
zoned_date_time.zone,
114116
)
115117
}
116118

119+
/// Use [`Self::from_zoned_date_time`].
120+
#[deprecated(since = "2.2.0", note = "use `Self::from_zoned_date_time`")]
121+
pub fn from_zoned_date_time_iso(zoned_date_time: ZonedDateTime<Iso, UtcOffset>) -> Self {
122+
Self::from_zoned_date_time(zoned_date_time)
123+
}
124+
117125
pub(crate) fn from_rd_time_zone(rd: RataDie, time: Time, zone: UtcOffset) -> Self {
118126
Self::from_epoch_seconds(
119127
(rd - RD_EPOCH) * 24 * 60 * 60 + time.seconds_since_midnight() as i64
@@ -186,7 +194,7 @@ impl ZoneNameTimestamp {
186194
note = "implicitly interprets the DateTime as UTC. Use `from_zoned_date_time_iso` instead."
187195
)]
188196
pub fn from_date_time_iso(DateTime { date, time }: DateTime<Iso>) -> Self {
189-
Self::from_zoned_date_time_iso(ZonedDateTime {
197+
Self::from_zoned_date_time(ZonedDateTime {
190198
date,
191199
time,
192200
zone: UtcOffset::zero(),
@@ -280,7 +288,7 @@ impl<'de> serde::Deserialize<'de> for ZoneNameTimestamp {
280288
let day = parts[8..10].parse::<u8>().map_err(e1)?;
281289
let hour = parts[11..13].parse::<u8>().map_err(e1)?;
282290
let minute = parts[14..16].parse::<u8>().map_err(e1)?;
283-
return Ok(Self::from_zoned_date_time_iso(ZonedDateTime {
291+
return Ok(Self::from_zoned_date_time(ZonedDateTime {
284292
date: icu_calendar::Date::try_new_iso(year, month, day).map_err(e2)?,
285293
time: Time::try_new(hour, minute, 0, 0).map_err(e3)?,
286294
zone: UtcOffset::zero(),
@@ -360,7 +368,7 @@ mod test {
360368
output: "2025-04-30T15:15Z",
361369
},
362370
] {
363-
let znt = ZoneNameTimestamp::from_zoned_date_time_iso(
371+
let znt = ZoneNameTimestamp::from_zoned_date_time(
364372
ZonedDateTime::try_offset_only_from_str(test_case.input, Iso).unwrap(),
365373
);
366374
let actual = znt.to_zoned_date_time_iso();

ffi/capi/bindings/c/TimeZoneInfo.h

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ffi/capi/bindings/cpp/icu4x/TimeZoneInfo.d.hpp

Lines changed: 20 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)