1+ use crate :: p2:: bindings:: clocks:: timezone:: TimezoneDisplay ;
12use cap_std:: time:: { Duration , Instant , SystemClock , SystemTime } ;
23use cap_std:: { AmbientAuthority , ambient_authority} ;
34use cap_time_ext:: { MonotonicClockExt as _, SystemClockExt as _} ;
5+ use chrono:: { DateTime , TimeZone } ;
6+ use chrono_tz:: { OffsetComponents , TZ_VARIANTS , Tz } ;
47use wasmtime:: component:: { HasData , ResourceTable } ;
58
69pub ( crate ) struct WasiClocks ;
@@ -12,13 +15,15 @@ impl HasData for WasiClocks {
1215pub struct WasiClocksCtx {
1316 pub wall_clock : Box < dyn HostWallClock + Send > ,
1417 pub monotonic_clock : Box < dyn HostMonotonicClock + Send > ,
18+ pub timezone : Box < dyn HostTimezone + Send > ,
1519}
1620
1721impl Default for WasiClocksCtx {
1822 fn default ( ) -> Self {
1923 Self {
2024 wall_clock : wall_clock ( ) ,
2125 monotonic_clock : monotonic_clock ( ) ,
26+ timezone : timezone ( ) ,
2227 }
2328 }
2429}
@@ -42,6 +47,11 @@ pub trait HostMonotonicClock: Send {
4247 fn now ( & self ) -> u64 ;
4348}
4449
50+ pub trait HostTimezone : Send {
51+ fn display ( & self , datetime : Duration ) -> TimezoneDisplay ;
52+ fn utc_offset ( & self , datetime : Duration ) -> i32 ;
53+ }
54+
4555pub struct WallClock {
4656 /// The underlying system clock.
4757 clock : cap_std:: time:: SystemClock ,
@@ -123,6 +133,10 @@ pub fn wall_clock() -> Box<dyn HostWallClock + Send> {
123133 Box :: new ( WallClock :: default ( ) )
124134}
125135
136+ pub fn timezone ( ) -> Box < dyn HostTimezone + Send > {
137+ Box :: new ( Timezone :: default ( ) )
138+ }
139+
126140pub ( crate ) struct Datetime {
127141 pub seconds : u64 ,
128142 pub nanoseconds : u32 ,
@@ -141,3 +155,56 @@ impl TryFrom<SystemTime> for Datetime {
141155 } )
142156 }
143157}
158+
159+ pub struct Timezone {
160+ // The underlying system timezone.
161+ timezone : cap_time_ext:: Timezone ,
162+ }
163+
164+ impl Default for Timezone {
165+ fn default ( ) -> Self {
166+ Self :: new ( ambient_authority ( ) )
167+ }
168+ }
169+
170+ impl Timezone {
171+ pub fn new ( ambient_authority : AmbientAuthority ) -> Self {
172+ Self {
173+ timezone : cap_time_ext:: Timezone :: new ( ambient_authority) ,
174+ }
175+ }
176+
177+ fn timezone_from_duration ( & self , datetime : Duration ) -> Option < TimezoneDisplay > {
178+ let name = self . timezone . timezone_name ( ) . ok ( ) ?;
179+ let tz: Tz = TZ_VARIANTS . into_iter ( ) . find ( |tz| tz. to_string ( ) == name) ?;
180+ let naive_datetime = DateTime :: from_timestamp ( datetime. as_secs ( ) as i64 , 0 ) ?. naive_utc ( ) ;
181+ let tz_offset = tz. offset_from_local_datetime ( & naive_datetime) . single ( ) ?;
182+ let utc_offset = tz_offset. base_utc_offset ( ) . num_hours ( ) as i32 ;
183+ let in_daylight_saving_time = !tz_offset. dst_offset ( ) . is_zero ( ) ;
184+ Some ( TimezoneDisplay {
185+ utc_offset,
186+ name,
187+ in_daylight_saving_time,
188+ } )
189+ }
190+ }
191+
192+ impl HostTimezone for Timezone {
193+ fn display ( & self , datetime : Duration ) -> TimezoneDisplay {
194+ match self . timezone_from_duration ( datetime) {
195+ None => TimezoneDisplay {
196+ utc_offset : 0 ,
197+ name : "UTC" . to_string ( ) ,
198+ in_daylight_saving_time : false ,
199+ } ,
200+ Some ( timezone_display) => timezone_display,
201+ }
202+ }
203+
204+ fn utc_offset ( & self , datetime : Duration ) -> i32 {
205+ match self . timezone_from_duration ( datetime) {
206+ None => 0 ,
207+ Some ( timezone_display) => timezone_display. utc_offset ,
208+ }
209+ }
210+ }
0 commit comments