1
1
//! This module implements the Temporal `TimeZone` and components.
2
2
3
- use alloc:: borrow:: ToOwned ;
4
3
use alloc:: borrow:: ToOwned ;
5
4
use alloc:: string:: String ;
6
5
use alloc:: vec:: Vec ;
7
6
use core:: { iter:: Peekable , str:: Chars } ;
8
7
9
- use core:: { iter:: Peekable , str:: Chars } ;
10
-
11
8
use num_traits:: ToPrimitive ;
12
9
13
10
use crate :: { components:: Instant , iso:: IsoDateTime , TemporalError , TemporalResult } ;
@@ -24,16 +21,16 @@ pub static TZ_PROVIDER: LazyLock<Mutex<FsTzdbProvider>> =
24
21
use super :: ZonedDateTime ;
25
22
26
23
pub trait TzProvider {
27
- fn check_identifier ( & mut self , identifier : & str ) -> bool ;
24
+ fn check_identifier ( & self , identifier : & str ) -> bool ;
28
25
29
26
fn get_named_tz_epoch_nanoseconds (
30
- & mut self ,
27
+ & self ,
31
28
identifier : & str ,
32
29
iso_datetime : IsoDateTime ,
33
30
) -> TemporalResult < Vec < i128 > > ;
34
31
35
32
fn get_named_tz_offset_nanoseconds (
36
- & mut self ,
33
+ & self ,
37
34
identifier : & str ,
38
35
epoch_nanoseconds : i128 ,
39
36
) -> TemporalResult < i128 > ;
@@ -76,61 +73,17 @@ impl From<String> for TimeZone {
76
73
}
77
74
}
78
75
79
- impl From < & str > for TimeZone {
80
- fn from ( value : & str ) -> Self {
81
- Self ( value. to_owned ( ) )
82
- }
83
- pub enum ParsedTimeZone < ' a > {
84
- IanaIdentifier { identifier : & ' a str } ,
85
- Offset { minutes : i16 } ,
86
- }
87
-
88
- impl < ' a > ParsedTimeZone < ' a > {
89
- pub fn from_str ( s : & ' a str , provider : & mut impl TzProvider ) -> TemporalResult < Self > {
90
- if s == "Z" {
91
- return Ok ( Self :: Offset { minutes : 0 } ) ;
92
- }
93
- let mut cursor = s. chars ( ) . peekable ( ) ;
94
- if cursor. peek ( ) . map_or ( false , is_ascii_sign) {
95
- return parse_offset ( & mut cursor) ;
96
- } else if provider. check_identifier ( s) {
97
- return Ok ( Self :: IanaIdentifier { identifier : s } ) ;
98
- }
99
- Err ( TemporalError :: range ( ) . with_message ( "Valid time zone was not provided." ) )
100
- }
101
- }
102
-
103
- #[ derive( Debug , Clone , PartialEq , Eq ) ]
104
- pub struct TimeZone ( pub String ) ;
105
-
106
- impl From < & ZonedDateTime > for TimeZone {
107
- fn from ( value : & ZonedDateTime ) -> Self {
108
- value. tz ( ) . clone ( )
109
- }
110
- }
111
-
112
- impl From < String > for TimeZone {
113
- fn from ( value : String ) -> Self {
114
- Self ( value)
115
- }
116
- }
117
-
118
76
impl From < & str > for TimeZone {
119
77
fn from ( value : & str ) -> Self {
120
78
Self ( value. to_owned ( ) )
121
79
}
122
80
}
123
81
124
82
impl TimeZone {
125
- pub ( crate ) fn get_iso_datetime_for(
126
83
pub ( crate ) fn get_iso_datetime_for (
127
84
& self ,
128
85
instant : & Instant ,
129
86
provider : & mut impl TzProvider ,
130
- ) -> TemporalResult < IsoDateTime > {
131
- let nanos = self . get_offset_nanos_for( instant. epoch_nanos, provider) ?;
132
- IsoDateTime :: from_epoch_nanos ( & instant. epoch_nanos , nanos. to_f64( ) . unwrap_or( 0.0 ) )
133
- provider : & mut impl TzProvider ,
134
87
) -> TemporalResult < IsoDateTime > {
135
88
let nanos = self . get_offset_nanos_for ( instant. epoch_nanos , provider) ?;
136
89
IsoDateTime :: from_epoch_nanos ( & instant. epoch_nanos , nanos. to_f64 ( ) . unwrap_or ( 0.0 ) )
@@ -139,21 +92,6 @@ impl TimeZone {
139
92
140
93
impl TimeZone {
141
94
/// Get the offset for this current `TimeZoneSlot`.
142
- pub fn get_offset_nanos_for (
143
- & self ,
144
- epoch_ns : i128 ,
145
- provider : & mut impl TzProvider ,
146
- ) -> TemporalResult < i128 > {
147
- // 1. Let parseResult be ! ParseTimeZoneIdentifier(timeZone).
148
- let parsed = ParsedTimeZone :: from_str ( & self . 0 , provider ) ?;
149
- match parsed {
150
- // 2. If parseResult.[[OffsetMinutes]] is not empty, return parseResult.[[OffsetMinutes]] × (60 × 10**9).
151
- ParsedTimeZone : : Offset { minutes } => Ok ( i128:: from( minutes) * 60_000_000_000i128 ) ,
152
- // 3. Return GetNamedTimeZoneOffsetNanoseconds(parseResult.[[Name]], epochNs).
153
- ParsedTimeZone : : IanaIdentifier { identifier } => {
154
- provider. get_named_tz_offset_nanoseconds( identifier, epoch_ns)
155
- }
156
- }
157
95
pub fn get_offset_nanos_for (
158
96
& self ,
159
97
epoch_ns : i128 ,
@@ -243,65 +181,3 @@ fn non_ascii_digit() -> TemporalError {
243
181
fn is_ascii_sign ( ch : & char ) -> bool {
244
182
* ch == '+' || * ch == '-'
245
183
}
246
-
247
- #[ inline]
248
- fn parse_offset < ' a > ( chars: & mut Peekable < Chars < ' _ > > ) -> TemporalResult < ParsedTimeZone < ' a > > {
249
- let sign = chars. next( ) . map_or( 1 , |c| if c == '+' { 1 } else { -1 } ) ;
250
- // First offset portion
251
- let hours = parse_digit_pair( chars) ?;
252
-
253
- let sep = chars. peek( ) . map_or( false , |ch| * ch == ':' ) ;
254
- if sep {
255
- let _ = chars. next( ) ;
256
- }
257
-
258
- let digit_peek = chars. peek( ) . map( |ch| ch. is_ascii_digit( ) ) ;
259
-
260
- let minutes = match digit_peek {
261
- Some ( true ) => parse_digit_pair( chars) ?,
262
- Some ( false) => return Err ( non_ascii_digit( ) ) ,
263
- None => 0 ,
264
- } ;
265
-
266
- Ok ( ParsedTimeZone :: Offset {
267
- minutes : ( hours * 60 + minutes) * sign,
268
- } )
269
- }
270
-
271
- fn parse_digit_pair( chars: & mut Peekable < Chars < ' _ > > ) -> TemporalResult < i16 > {
272
- let valid = chars
273
- . peek( )
274
- . map_or( Err ( abrupt_end( ) ) , |ch| Ok ( ch. is_ascii_digit( ) ) ) ?;
275
- let first = if valid {
276
- chars. next( ) . expect( "validated." )
277
- } else {
278
- return Err ( non_ascii_digit( ) ) ;
279
- } ;
280
- let valid = chars
281
- . peek( )
282
- . map_or( Err ( abrupt_end( ) ) , |ch| Ok ( ch. is_ascii_digit( ) ) ) ?;
283
- let second = if valid {
284
- chars. next( ) . expect( "validated." )
285
- } else {
286
- return Err ( non_ascii_digit( ) ) ;
287
- } ;
288
-
289
- let tens = ( first. to_digit( 10 ) . expect( "validated" ) * 10 ) as i16;
290
- let ones = second. to_digit( 10 ) . expect( "validated" ) as i16;
291
-
292
- Ok ( tens + ones)
293
- }
294
-
295
- // NOTE: Spec calls for throwing a RangeError when parse node is a list of errors for timezone.
296
-
297
- fn abrupt_end( ) -> TemporalError {
298
- TemporalError : : range( ) . with_message( "Abrupt end while parsing offset string" )
299
- }
300
-
301
- fn non_ascii_digit( ) -> TemporalError {
302
- TemporalError : : range( ) . with_message( "Non ascii digit found while parsing offset string" )
303
- }
304
-
305
- fn is_ascii_sign( ch: & char) -> bool {
306
- * ch == '+' || * ch == '-'
307
- }
0 commit comments