Skip to content

Commit bca9957

Browse files
authored
Add GetNamedTimeZoneTransition method to TimeZoneProvider trait (#203)
This PR adds the stubbed out method to the `TimeZoneProvider` trait, and implements the baseline logic for `ZonedDateTime::get_time_zone_transition`. This PR also adds the `TransitionDirection` option that lives in the provider module.
1 parent 91e8262 commit bca9957

File tree

4 files changed

+95
-9
lines changed

4 files changed

+95
-9
lines changed

src/builtins/compiled/zoneddatetime.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::builtins::TZ_PROVIDER;
2+
use crate::provider::TransitionDirection;
23
use crate::ZonedDateTime;
34
use crate::{
45
options::{
@@ -269,7 +270,10 @@ impl ZonedDateTime {
269270
}
270271

271272
// TODO: Update direction to correct option
272-
pub fn get_time_zone_transition(&self, direction: bool) -> TemporalResult<Self> {
273+
pub fn get_time_zone_transition(
274+
&self,
275+
direction: TransitionDirection,
276+
) -> TemporalResult<Option<Self>> {
273277
let provider = TZ_PROVIDER
274278
.lock()
275279
.map_err(|_| TemporalError::general("Unable to acquire lock"))?;

src/builtins/core/zoneddatetime.rs

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use crate::{
2323
self, parse_offset, FormattableOffset, FormattableTime, IxdtfStringBuilder, Precision,
2424
},
2525
partial::{PartialDate, PartialTime},
26-
provider::TimeZoneProvider,
26+
provider::{TimeZoneProvider, TransitionDirection},
2727
rounding::{IncrementRounder, Round},
2828
temporal_assert,
2929
time::EpochNanoseconds,
@@ -480,13 +480,31 @@ impl ZonedDateTime {
480480
// ==== HoursInDay accessor method implementation ====
481481

482482
impl ZonedDateTime {
483-
// TODO: Add direction parameter to either zoneddatetime.rs or option.rs
483+
// TODO: implement and stabalize
484484
pub fn get_time_zone_transition_with_provider(
485485
&self,
486-
_direction: bool,
487-
_provider: &impl TimeZoneProvider,
488-
) -> TemporalResult<Self> {
489-
Err(TemporalError::general("Not yet implemented"))
486+
direction: TransitionDirection,
487+
provider: &impl TimeZoneProvider,
488+
) -> TemporalResult<Option<Self>> {
489+
// 8. If IsOffsetTimeZoneIdentifier(timeZone) is true, return null.
490+
let TimeZone::IanaIdentifier(identifier) = &self.tz else {
491+
return Ok(None);
492+
};
493+
// 9. If direction is next, then
494+
// a. Let transition be GetNamedTimeZoneNextTransition(timeZone, zonedDateTime.[[EpochNanoseconds]]).
495+
// 10. Else,
496+
// a. Assert: direction is previous.
497+
// b. Let transition be GetNamedTimeZonePreviousTransition(timeZone, zonedDateTime.[[EpochNanoseconds]]).
498+
let transition =
499+
provider.get_named_tz_transition(identifier, self.epoch_nanoseconds(), direction)?;
500+
501+
// 11. If transition is null, return null.
502+
// 12. Return ! CreateTemporalZonedDateTime(transition, timeZone, zonedDateTime.[[Calendar]]).
503+
let result = transition
504+
.map(|t| ZonedDateTime::try_new(t.0, self.calendar().clone(), self.tz.clone()))
505+
.transpose()?;
506+
507+
Ok(result)
490508
}
491509

492510
pub fn hours_in_day_with_provider(

src/provider.rs

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
//! The `TimeZoneProvider` trait.
22
3+
use core::str::FromStr;
4+
35
use crate::{iso::IsoDateTime, time::EpochNanoseconds, TemporalResult};
46
use alloc::vec::Vec;
57

@@ -12,6 +14,42 @@ pub struct TimeZoneOffset {
1214
pub offset: i64,
1315
}
1416

17+
#[derive(Debug, Clone, Copy, PartialEq)]
18+
pub enum TransitionDirection {
19+
Next,
20+
Previous,
21+
}
22+
23+
#[derive(Debug, Clone, Copy)]
24+
pub struct ParseDirectionError;
25+
26+
impl core::fmt::Display for ParseDirectionError {
27+
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
28+
f.write_str("provided string was not a valid direction.")
29+
}
30+
}
31+
32+
impl FromStr for TransitionDirection {
33+
type Err = ParseDirectionError;
34+
fn from_str(s: &str) -> Result<Self, Self::Err> {
35+
match s {
36+
"next" => Ok(Self::Next),
37+
"previous" => Ok(Self::Previous),
38+
_ => Err(ParseDirectionError),
39+
}
40+
}
41+
}
42+
43+
impl core::fmt::Display for TransitionDirection {
44+
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
45+
match self {
46+
Self::Next => "next",
47+
Self::Previous => "previous",
48+
}
49+
.fmt(f)
50+
}
51+
}
52+
1553
// NOTE: It may be a good idea to eventually move this into it's
1654
// own individual crate rather than having it tied directly into `temporal_rs`
1755
/// The `TimeZoneProvider` trait provides methods required for a provider
@@ -28,8 +66,16 @@ pub trait TimeZoneProvider {
2866
fn get_named_tz_offset_nanoseconds(
2967
&self,
3068
identifier: &str,
31-
utc_epoch: i128,
69+
epoch_nanoseconds: i128,
3270
) -> TemporalResult<TimeZoneOffset>;
71+
72+
// TODO: implement and stabalize
73+
fn get_named_tz_transition(
74+
&self,
75+
identifier: &str,
76+
epoch_nanoseconds: i128,
77+
direction: TransitionDirection,
78+
) -> TemporalResult<Option<EpochNanoseconds>>;
3379
}
3480

3581
pub struct NeverProvider;
@@ -50,4 +96,13 @@ impl TimeZoneProvider for NeverProvider {
5096
fn get_named_tz_offset_nanoseconds(&self, _: &str, _: i128) -> TemporalResult<TimeZoneOffset> {
5197
unimplemented!()
5298
}
99+
100+
fn get_named_tz_transition(
101+
&self,
102+
_: &str,
103+
_: i128,
104+
_: TransitionDirection,
105+
) -> TemporalResult<Option<EpochNanoseconds>> {
106+
unimplemented!()
107+
}
53108
}

src/tzdb.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ use tzif::{
4949

5050
use crate::{
5151
iso::IsoDateTime,
52-
provider::{TimeZoneOffset, TimeZoneProvider},
52+
provider::{TimeZoneOffset, TimeZoneProvider, TransitionDirection},
5353
time::EpochNanoseconds,
5454
utils, TemporalError, TemporalResult,
5555
};
@@ -679,6 +679,15 @@ impl TimeZoneProvider for FsTzdbProvider {
679679
let seconds = (utc_epoch / 1_000_000_000) as i64;
680680
tzif.get(&Seconds(seconds))
681681
}
682+
683+
fn get_named_tz_transition(
684+
&self,
685+
_identifier: &str,
686+
_epoch_nanoseconds: i128,
687+
_direction: TransitionDirection,
688+
) -> TemporalResult<Option<EpochNanoseconds>> {
689+
Err(TemporalError::general("Not yet implemented."))
690+
}
682691
}
683692

684693
#[inline]

0 commit comments

Comments
 (0)