Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
2 changes: 2 additions & 0 deletions provider/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ include = [
]

[features]
# Allow people to use default-features = false
default = []
datagen = [
"std",
"dep:serde",
Expand Down
57 changes: 28 additions & 29 deletions provider/src/zoneinfo64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<UtcOffset> 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<CompiledNormalizer, ZoneInfo64<'a>>;

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<Self> {
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<Zone<'a>> {
let id = u16::try_from(id.0)
.map_err(|_| TimeZoneProviderError::Range("Unknown timezone identifier"))?;
Expand Down Expand Up @@ -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(),
},
])
}
Expand Down
4 changes: 1 addition & 3 deletions src/builtins/core/zoneddatetime/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")]
Expand Down
2 changes: 1 addition & 1 deletion temporal_capi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
Expand Down
Binary file removed tests/data/zoneinfo64.res
Binary file not shown.
Loading