diff --git a/Cargo.lock b/Cargo.lock index 7c421eeaa..562a0ca82 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1308,13 +1308,12 @@ dependencies = [ [[package]] name = "zoneinfo64" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecb05a4021a0c67056a78c948c7d320a4e549126c3dc53f3f206e1a1e43a5c56" +checksum = "6916519e4a1cff59d49e0b902caed549d85dbbbf623a95af5c8320d5c08c6e13" dependencies = [ "calendrical_calculations", "icu_locale_core", - "icu_time", "potential_utf", "resb", "serde", diff --git a/Cargo.toml b/Cargo.toml index 1a350bd9b..b21db11dd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,7 +48,7 @@ jiff-tzdb = "0.1.4" combine = "4.6.7" web-time = "1.1.0" zerovec = "0.11.4" -zoneinfo64 = "0.1.0" +zoneinfo64 = "0.2.0" [package] name = "temporal_rs" diff --git a/provider/Cargo.toml b/provider/Cargo.toml index 6851f6bbd..b0e346bc5 100644 --- a/provider/Cargo.toml +++ b/provider/Cargo.toml @@ -17,6 +17,8 @@ include = [ ] [features] +# Allow people to use default-features = false +default = [] datagen = [ "std", "dep:serde", diff --git a/provider/src/zoneinfo64.rs b/provider/src/zoneinfo64.rs index 909ff4376..0a439a8b9 100644 --- a/provider/src/zoneinfo64.rs +++ b/provider/src/zoneinfo64.rs @@ -11,17 +11,29 @@ use crate::{ epoch_nanoseconds::{seconds_to_nanoseconds, EpochNanoseconds, NS_IN_S}, TimeZoneProviderError, }; -use icu_time::zone::UtcOffset; +use zoneinfo64::UtcOffset; impl From for UtcOffsetSeconds { fn from(other: UtcOffset) -> Self { - Self(i64::from(other.to_seconds())) + Self(i64::from(other.seconds())) } } +pub use zoneinfo64::ZONEINFO64_RES_FOR_TESTING; + /// A TimeZoneProvider that works using ICU4C zoneinfo64.res data pub type ZoneInfo64TzdbProvider<'a> = NormalizerAndResolver>; +impl ZoneInfo64TzdbProvider<'_> { + /// Produces a zoneinfo64 provider using the builtin zoneinfo64 data, + /// for testing use only. We do not provide strong guarantees for which version of zoneinfo64 + /// this will be. + pub fn zoneinfo64_provider_for_testing() -> Option { + let zi_data = zoneinfo64::ZoneInfo64::try_from_u32s(ZONEINFO64_RES_FOR_TESTING).ok()?; + Some(ZoneInfo64TzdbProvider::new(zi_data)) + } +} + fn get<'a>(zi: &'a ZoneInfo64<'a>, id: ResolvedId) -> TimeZoneProviderResult> { let id = u16::try_from(id.0) .map_err(|_| TimeZoneProviderError::Range("Unknown timezone identifier"))?; @@ -55,53 +67,40 @@ impl TimeZoneResolver for ZoneInfo64<'_> { local_datetime.second, ); - const FIVE_DAYS_NANOS: i128 = 5 * 24 * 60 * 60 * 1_000_000_000; let result = match possible_offset { - // TODO(Manishearth) This is wrong. It mostly works: we do not have any transitions with gaps that last - // longer than 5 days, and for the purpose of calculating an offset when you are that far away from a transition - // treating local datetime as epoch time works fine. - // Can be fixed once we have https://github.com/unicode-org/icu4x/pull/6913 - PossibleOffset::None => CandidateEpochNanoseconds::Zero(GapEntryOffsets { - offset_before: self.transition_nanoseconds_for_utc_epoch_nanoseconds( - identifier, - epoch_nanos.0 - FIVE_DAYS_NANOS, - )?, - offset_after: self.transition_nanoseconds_for_utc_epoch_nanoseconds( - identifier, - epoch_nanos.0 + FIVE_DAYS_NANOS, - )?, - transition_epoch: self - .get_time_zone_transition( - identifier, - epoch_nanos.0 - FIVE_DAYS_NANOS, - TransitionDirection::Next, - )? - .unwrap_or_default(), + PossibleOffset::None { + before, + after, + transition, + } => CandidateEpochNanoseconds::Zero(GapEntryOffsets { + offset_before: before.offset.into(), + offset_after: after.offset.into(), + transition_epoch: EpochNanoseconds::from(seconds_to_nanoseconds(transition)), }), PossibleOffset::Single(o) => { let epoch_ns = EpochNanoseconds::from( - epoch_nanos.0 - seconds_to_nanoseconds(i64::from(o.offset.to_seconds())), + epoch_nanos.0 - seconds_to_nanoseconds(i64::from(o.offset.seconds())), ); CandidateEpochNanoseconds::One(EpochNanosecondsAndOffset { ns: epoch_ns, offset: o.offset.into(), }) } - PossibleOffset::Ambiguous(first, second) => { + PossibleOffset::Ambiguous { before, after, .. } => { let first_epoch_ns = EpochNanoseconds::from( - epoch_nanos.0 - seconds_to_nanoseconds(i64::from(first.offset.to_seconds())), + epoch_nanos.0 - seconds_to_nanoseconds(i64::from(before.offset.seconds())), ); let second_epoch_ns = EpochNanoseconds::from( - epoch_nanos.0 - seconds_to_nanoseconds(i64::from(second.offset.to_seconds())), + epoch_nanos.0 - seconds_to_nanoseconds(i64::from(after.offset.seconds())), ); CandidateEpochNanoseconds::Two([ EpochNanosecondsAndOffset { ns: first_epoch_ns, - offset: first.offset.into(), + offset: before.offset.into(), }, EpochNanosecondsAndOffset { ns: second_epoch_ns, - offset: second.offset.into(), + offset: after.offset.into(), }, ]) } diff --git a/src/builtins/core/zoneddatetime/tests.rs b/src/builtins/core/zoneddatetime/tests.rs index 29ebee9ca..47bb54cb8 100644 --- a/src/builtins/core/zoneddatetime/tests.rs +++ b/src/builtins/core/zoneddatetime/tests.rs @@ -12,11 +12,9 @@ use crate::{ }; use alloc::string::ToString; use core::str::FromStr; +use timezone_provider::zoneinfo64::ZONEINFO64_RES_FOR_TESTING; use tinystr::tinystr; -pub const ZONEINFO64_RES_FOR_TESTING: &[u32] = - resb::include_bytes_as_u32!("../../../../tests/data/zoneinfo64.res"); - macro_rules! test_all_providers { ($(#[cfg_for_fs($cfg_fs:meta)])? $(#[cfg_for_zi64($cfg_zi:meta)])? $provider:ident: $b:block) => {{ #[cfg(feature = "compiled_data")] diff --git a/temporal_capi/Cargo.toml b/temporal_capi/Cargo.toml index decdae197..08ae1deb8 100644 --- a/temporal_capi/Cargo.toml +++ b/temporal_capi/Cargo.toml @@ -27,7 +27,7 @@ icu_calendar = { version = "2.0.2", default-features = false } icu_locale = { version = "2.0.0" } writeable = "0.6.1" yoke = { version = "0.8.0", optional = true } -zoneinfo64 = { workspace = true, optional = true, default-features = false } +zoneinfo64 = { workspace = true, optional = true } [features] compiled_data = ["temporal_rs/compiled_data"] diff --git a/tests/data/zoneinfo64.res b/tests/data/zoneinfo64.res deleted file mode 100644 index 9b7a5b35a..000000000 Binary files a/tests/data/zoneinfo64.res and /dev/null differ