Skip to content

Commit e19d586

Browse files
committed
Switch compiled_data APIs to new CompiledTzdbProvider
1 parent 44632b0 commit e19d586

File tree

4 files changed

+166
-52
lines changed

4 files changed

+166
-52
lines changed

src/builtins/compiled/duration/tests.rs

Lines changed: 0 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
use std::string::ToString;
2-
31
use crate::{
42
options::{
53
OffsetDisambiguation, RelativeTo, RoundingIncrement, RoundingMode, RoundingOptions, Unit,
@@ -508,55 +506,6 @@ fn round_relative_to_zoned_datetime() {
508506
assert_eq!(result.hours(), 1);
509507
}
510508

511-
#[test]
512-
fn test_duration_compare() {
513-
// TODO(#199): fix this on Windows
514-
if cfg!(not(windows)) {
515-
let one = Duration::from_partial_duration(PartialDuration {
516-
hours: Some(79),
517-
minutes: Some(10),
518-
..Default::default()
519-
})
520-
.unwrap();
521-
let two = Duration::from_partial_duration(PartialDuration {
522-
days: Some(3),
523-
hours: Some(7),
524-
seconds: Some(630),
525-
..Default::default()
526-
})
527-
.unwrap();
528-
let three = Duration::from_partial_duration(PartialDuration {
529-
days: Some(3),
530-
hours: Some(6),
531-
minutes: Some(50),
532-
..Default::default()
533-
})
534-
.unwrap();
535-
536-
let mut arr = [&one, &two, &three];
537-
arr.sort_by(|a, b| Duration::compare(a, b, None).unwrap());
538-
assert_eq!(
539-
arr.map(ToString::to_string),
540-
[&three, &one, &two].map(ToString::to_string)
541-
);
542-
543-
// Sorting relative to a date, taking DST changes into account:
544-
let zdt = ZonedDateTime::from_str(
545-
"2020-11-01T00:00-07:00[America/Los_Angeles]",
546-
Default::default(),
547-
OffsetDisambiguation::Reject,
548-
)
549-
.unwrap();
550-
arr.sort_by(|a, b| {
551-
Duration::compare(a, b, Some(RelativeTo::ZonedDateTime(zdt.clone()))).unwrap()
552-
});
553-
assert_eq!(
554-
arr.map(ToString::to_string),
555-
[&one, &three, &two].map(ToString::to_string)
556-
)
557-
}
558-
}
559-
560509
#[test]
561510
fn test_duration_total() {
562511
let d1 = Duration::from_partial_duration(PartialDuration {

src/builtins/core/duration/tests.rs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,67 @@ fn duration_round_negative() {
264264
assert_eq!(result.days(), -3);
265265
}
266266

267+
#[test]
268+
#[cfg(feature = "compiled_data")]
269+
fn test_duration_compare() {
270+
use crate::builtins::FS_TZ_PROVIDER;
271+
use crate::options::{OffsetDisambiguation, RelativeTo};
272+
use crate::ZonedDateTime;
273+
use alloc::string::ToString;
274+
// TODO(#199): Make this work with Windows
275+
// This should also ideally use the compiled data APIs and live under builtins/compiled
276+
if cfg!(not(windows)) {
277+
let one = Duration::from_partial_duration(PartialDuration {
278+
hours: Some(79),
279+
minutes: Some(10),
280+
..Default::default()
281+
})
282+
.unwrap();
283+
let two = Duration::from_partial_duration(PartialDuration {
284+
days: Some(3),
285+
hours: Some(7),
286+
seconds: Some(630),
287+
..Default::default()
288+
})
289+
.unwrap();
290+
let three = Duration::from_partial_duration(PartialDuration {
291+
days: Some(3),
292+
hours: Some(6),
293+
minutes: Some(50),
294+
..Default::default()
295+
})
296+
.unwrap();
297+
298+
let mut arr = [&one, &two, &three];
299+
arr.sort_by(|a, b| Duration::compare_with_provider(a, b, None, &*FS_TZ_PROVIDER).unwrap());
300+
assert_eq!(
301+
arr.map(ToString::to_string),
302+
[&three, &one, &two].map(ToString::to_string)
303+
);
304+
305+
// Sorting relative to a date, taking DST changes into account:
306+
let zdt = ZonedDateTime::from_str_with_provider(
307+
"2020-11-01T00:00-07:00[America/Los_Angeles]",
308+
Default::default(),
309+
OffsetDisambiguation::Reject,
310+
&*FS_TZ_PROVIDER,
311+
)
312+
.unwrap();
313+
arr.sort_by(|a, b| {
314+
Duration::compare_with_provider(
315+
a,
316+
b,
317+
Some(RelativeTo::ZonedDateTime(zdt.clone())),
318+
&*FS_TZ_PROVIDER,
319+
)
320+
.unwrap()
321+
});
322+
assert_eq!(
323+
arr.map(ToString::to_string),
324+
[&one, &three, &two].map(ToString::to_string)
325+
)
326+
}
327+
}
267328
/*
268329
TODO: Uncomment
269330

src/builtins/mod.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,15 @@ pub mod core;
77
pub use core::*;
88

99
#[cfg(feature = "compiled_data")]
10+
use crate::tzdb::CompiledTzdbProvider;
11+
#[cfg(all(test, feature = "compiled_data"))]
1012
use crate::tzdb::FsTzdbProvider;
1113
#[cfg(feature = "compiled_data")]
1214
use std::sync::LazyLock;
1315

1416
#[cfg(feature = "compiled_data")]
15-
pub static TZ_PROVIDER: LazyLock<FsTzdbProvider> = LazyLock::new(FsTzdbProvider::default);
17+
pub static TZ_PROVIDER: LazyLock<CompiledTzdbProvider> =
18+
LazyLock::new(CompiledTzdbProvider::default);
19+
20+
#[cfg(all(test, feature = "compiled_data"))]
21+
pub(crate) static FS_TZ_PROVIDER: LazyLock<FsTzdbProvider> = LazyLock::new(FsTzdbProvider::default);

src/tzdb.rs

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -610,6 +610,104 @@ fn offset_range(offset_one: i64, offset_two: i64) -> core::ops::Range<i64> {
610610
offset_two..offset_one
611611
}
612612

613+
/// Timezone provider that uses compiled data.
614+
///
615+
/// Currently uses jiff_tzdb and performs parsing; will eventually
616+
/// use pure compiled data (<https://github.com/boa-dev/temporal/pull/264>)
617+
#[derive(Debug, Default)]
618+
pub struct CompiledTzdbProvider {
619+
cache: RwLock<BTreeMap<String, Tzif>>,
620+
}
621+
622+
impl CompiledTzdbProvider {
623+
/// Get timezone data for a single identifier
624+
pub fn get(&self, identifier: &str) -> TemporalResult<Tzif> {
625+
if let Some(tzif) = self
626+
.cache
627+
.read()
628+
.map_err(|_| TemporalError::general("poisoned RWLock"))?
629+
.get(identifier)
630+
{
631+
return Ok(tzif.clone());
632+
}
633+
634+
let (identifier, tzif) = {
635+
let Some((canonical_name, data)) = jiff_tzdb::get(identifier) else {
636+
return Err(
637+
TemporalError::range().with_message("Time zone identifier does not exist.")
638+
);
639+
};
640+
(canonical_name, Tzif::from_bytes(data)?)
641+
};
642+
643+
Ok(self
644+
.cache
645+
.write()
646+
.map_err(|_| TemporalError::general("poisoned RWLock"))?
647+
.entry(identifier.into())
648+
.or_insert(tzif)
649+
.clone())
650+
}
651+
}
652+
653+
impl TimeZoneProvider for CompiledTzdbProvider {
654+
fn check_identifier(&self, identifier: &str) -> bool {
655+
if let Some(index) = SINGLETON_IANA_NORMALIZER.available_id_index.get(identifier) {
656+
return SINGLETON_IANA_NORMALIZER
657+
.normalized_identifiers
658+
.get(index)
659+
.is_some();
660+
}
661+
false
662+
}
663+
664+
fn get_named_tz_epoch_nanoseconds(
665+
&self,
666+
identifier: &str,
667+
iso_datetime: IsoDateTime,
668+
) -> TemporalResult<Vec<EpochNanoseconds>> {
669+
let epoch_nanos = iso_datetime.as_nanoseconds()?;
670+
let seconds = (epoch_nanos.0 / 1_000_000_000) as i64;
671+
let tzif = self.get(identifier)?;
672+
let local_time_record_result = tzif.v2_estimate_tz_pair(&Seconds(seconds))?;
673+
let result = match local_time_record_result {
674+
LocalTimeRecordResult::Empty => Vec::default(),
675+
LocalTimeRecordResult::Single(r) => {
676+
let epoch_ns =
677+
EpochNanoseconds::try_from(epoch_nanos.0 - seconds_to_nanoseconds(r.offset))?;
678+
vec![epoch_ns]
679+
}
680+
LocalTimeRecordResult::Ambiguous { std, dst } => {
681+
let std_epoch_ns =
682+
EpochNanoseconds::try_from(epoch_nanos.0 - seconds_to_nanoseconds(std.offset))?;
683+
let dst_epoch_ns =
684+
EpochNanoseconds::try_from(epoch_nanos.0 - seconds_to_nanoseconds(dst.offset))?;
685+
vec![std_epoch_ns, dst_epoch_ns]
686+
}
687+
};
688+
Ok(result)
689+
}
690+
691+
fn get_named_tz_offset_nanoseconds(
692+
&self,
693+
identifier: &str,
694+
utc_epoch: i128,
695+
) -> TemporalResult<TimeZoneOffset> {
696+
let tzif = self.get(identifier)?;
697+
let seconds = (utc_epoch / 1_000_000_000) as i64;
698+
tzif.get(&Seconds(seconds))
699+
}
700+
701+
fn get_named_tz_transition(
702+
&self,
703+
_identifier: &str,
704+
_epoch_nanoseconds: i128,
705+
_direction: TransitionDirection,
706+
) -> TemporalResult<Option<EpochNanoseconds>> {
707+
Err(TemporalError::general("Not yet implemented."))
708+
}
709+
}
710+
613711
#[derive(Debug, Default)]
614712
pub struct FsTzdbProvider {
615713
cache: RwLock<BTreeMap<String, Tzif>>,

0 commit comments

Comments
 (0)