Skip to content

Commit f31f73d

Browse files
committed
Only implement the offset_from_ methods on Local
1 parent eb910be commit f31f73d

File tree

5 files changed

+116
-360
lines changed

5 files changed

+116
-360
lines changed

src/offset/local/mod.rs

Lines changed: 15 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,11 @@ use rkyv::{Archive, Deserialize, Serialize};
1111

1212
use super::fixed::FixedOffset;
1313
use super::{LocalResult, TimeZone};
14-
use crate::naive::{NaiveDate, NaiveDateTime};
14+
use crate::naive::{NaiveDate, NaiveDateTime, NaiveTime};
1515
#[allow(deprecated)]
1616
use crate::Date;
1717
use crate::{DateTime, Utc};
1818

19-
// we don't want `stub.rs` when the target_os is not wasi or emscripten
20-
// as we use js-sys to get the date instead
2119
#[cfg(all(
2220
not(unix),
2321
not(windows),
@@ -38,6 +36,14 @@ mod inner;
3836
#[path = "windows.rs"]
3937
mod inner;
4038

39+
#[cfg(all(
40+
target_arch = "wasm32",
41+
feature = "wasmbind",
42+
not(any(target_os = "emscripten", target_os = "wasi"))
43+
))]
44+
#[path = "wasmbind.rs"]
45+
mod inner;
46+
4147
#[cfg(unix)]
4248
mod tz_info;
4349

@@ -106,87 +112,24 @@ impl TimeZone for Local {
106112
Local
107113
}
108114

109-
// they are easier to define in terms of the finished date and time unlike other offsets
110115
#[allow(deprecated)]
111116
fn offset_from_local_date(&self, local: &NaiveDate) -> LocalResult<FixedOffset> {
112-
self.from_local_date(local).map(|date| *date.offset())
117+
// Get the offset at local midnight.
118+
self.offset_from_local_datetime(&local.and_time(NaiveTime::MIN))
113119
}
114120

115121
fn offset_from_local_datetime(&self, local: &NaiveDateTime) -> LocalResult<FixedOffset> {
116-
self.from_local_datetime(local).map(|datetime| *datetime.offset())
122+
inner::offset_from_local_datetime(local)
117123
}
118124

119125
#[allow(deprecated)]
120126
fn offset_from_utc_date(&self, utc: &NaiveDate) -> FixedOffset {
121-
*self.from_utc_date(utc).offset()
127+
// Get the offset at midnight.
128+
self.offset_from_utc_datetime(&utc.and_time(NaiveTime::MIN))
122129
}
123130

124131
fn offset_from_utc_datetime(&self, utc: &NaiveDateTime) -> FixedOffset {
125-
*self.from_utc_datetime(utc).offset()
126-
}
127-
128-
// override them for avoiding redundant works
129-
#[allow(deprecated)]
130-
fn from_local_date(&self, local: &NaiveDate) -> LocalResult<Date<Local>> {
131-
// this sounds very strange, but required for keeping `TimeZone::ymd` sane.
132-
// in the other words, we use the offset at the local midnight
133-
// but keep the actual date unaltered (much like `FixedOffset`).
134-
let midnight = self.from_local_datetime(&local.and_hms_opt(0, 0, 0).unwrap());
135-
midnight.map(|datetime| Date::from_utc(*local, *datetime.offset()))
136-
}
137-
138-
#[cfg(all(
139-
target_arch = "wasm32",
140-
feature = "wasmbind",
141-
not(any(target_os = "emscripten", target_os = "wasi"))
142-
))]
143-
fn from_local_datetime(&self, local: &NaiveDateTime) -> LocalResult<DateTime<Local>> {
144-
let mut local = local.clone();
145-
// Get the offset from the js runtime
146-
let offset =
147-
FixedOffset::west_opt((js_sys::Date::new_0().get_timezone_offset() as i32) * 60)
148-
.unwrap();
149-
local -= crate::Duration::seconds(offset.local_minus_utc() as i64);
150-
LocalResult::Single(DateTime::from_utc(local, offset))
151-
}
152-
153-
#[cfg(not(all(
154-
target_arch = "wasm32",
155-
feature = "wasmbind",
156-
not(any(target_os = "emscripten", target_os = "wasi"))
157-
)))]
158-
fn from_local_datetime(&self, local: &NaiveDateTime) -> LocalResult<DateTime<Local>> {
159-
inner::naive_to_local(local, true)
160-
}
161-
162-
#[allow(deprecated)]
163-
fn from_utc_date(&self, utc: &NaiveDate) -> Date<Local> {
164-
let midnight = self.from_utc_datetime(&utc.and_hms_opt(0, 0, 0).unwrap());
165-
Date::from_utc(*utc, *midnight.offset())
166-
}
167-
168-
#[cfg(all(
169-
target_arch = "wasm32",
170-
feature = "wasmbind",
171-
not(any(target_os = "emscripten", target_os = "wasi"))
172-
))]
173-
fn from_utc_datetime(&self, utc: &NaiveDateTime) -> DateTime<Local> {
174-
// Get the offset from the js runtime
175-
let offset =
176-
FixedOffset::west_opt((js_sys::Date::new_0().get_timezone_offset() as i32) * 60)
177-
.unwrap();
178-
DateTime::from_utc(*utc, offset)
179-
}
180-
181-
#[cfg(not(all(
182-
target_arch = "wasm32",
183-
feature = "wasmbind",
184-
not(any(target_os = "emscripten", target_os = "wasi"))
185-
)))]
186-
fn from_utc_datetime(&self, utc: &NaiveDateTime) -> DateTime<Local> {
187-
// this is OK to unwrap as getting local time from a UTC
188-
// timestamp is never ambiguous
189-
inner::naive_to_local(utc, false).unwrap()
132+
inner::offset_from_utc_datetime(utc).unwrap()
190133
}
191134
}
192135

src/offset/local/stub.rs

Lines changed: 5 additions & 211 deletions
Original file line numberDiff line numberDiff line change
@@ -8,218 +8,12 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use std::time::{SystemTime, UNIX_EPOCH};
11+
use crate::{FixedOffset, LocalResult, NaiveDateTime};
1212

13-
use super::{FixedOffset, Local};
14-
use crate::{DateTime, Datelike, LocalResult, NaiveDate, NaiveDateTime, NaiveTime, Timelike};
15-
16-
/// Converts a local `NaiveDateTime` to the `time::Timespec`.
17-
#[cfg(not(all(
18-
target_arch = "wasm32",
19-
feature = "wasmbind",
20-
not(any(target_os = "emscripten", target_os = "wasi"))
21-
)))]
22-
pub(super) fn naive_to_local(d: &NaiveDateTime, local: bool) -> LocalResult<DateTime<Local>> {
23-
let tm = Tm {
24-
tm_sec: d.second() as i32,
25-
tm_min: d.minute() as i32,
26-
tm_hour: d.hour() as i32,
27-
tm_mday: d.day() as i32,
28-
tm_mon: d.month0() as i32, // yes, C is that strange...
29-
tm_year: d.year() - 1900, // this doesn't underflow, we know that d is `NaiveDateTime`.
30-
tm_wday: 0, // to_local ignores this
31-
tm_yday: 0, // and this
32-
tm_isdst: -1,
33-
// This seems pretty fake?
34-
tm_utcoff: if local { 1 } else { 0 },
35-
// do not set this, OS APIs are heavily inconsistent in terms of leap second handling
36-
tm_nsec: 0,
37-
};
38-
39-
let spec = Timespec {
40-
sec: match local {
41-
false => utc_tm_to_time(&tm),
42-
true => local_tm_to_time(&tm),
43-
},
44-
nsec: tm.tm_nsec,
45-
};
46-
47-
// Adjust for leap seconds
48-
let mut tm = spec.local();
49-
assert_eq!(tm.tm_nsec, 0);
50-
tm.tm_nsec = d.nanosecond() as i32;
51-
52-
LocalResult::Single(tm_to_datetime(tm))
53-
}
54-
55-
/// Converts a `time::Tm` struct into the timezone-aware `DateTime`.
56-
/// This assumes that `time` is working correctly, i.e. any error is fatal.
57-
#[cfg(not(all(
58-
target_arch = "wasm32",
59-
feature = "wasmbind",
60-
not(any(target_os = "emscripten", target_os = "wasi"))
61-
)))]
62-
fn tm_to_datetime(mut tm: Tm) -> DateTime<Local> {
63-
if tm.tm_sec >= 60 {
64-
tm.tm_nsec += (tm.tm_sec - 59) * 1_000_000_000;
65-
tm.tm_sec = 59;
66-
}
67-
68-
let date = NaiveDate::from_yo(tm.tm_year + 1900, tm.tm_yday as u32 + 1);
69-
let time = NaiveTime::from_hms_nano(
70-
tm.tm_hour as u32,
71-
tm.tm_min as u32,
72-
tm.tm_sec as u32,
73-
tm.tm_nsec as u32,
74-
);
75-
76-
let offset = FixedOffset::east_opt(tm.tm_utcoff).unwrap();
77-
DateTime::from_utc(date.and_time(time) - offset, offset)
78-
}
79-
80-
/// A record specifying a time value in seconds and nanoseconds, where
81-
/// nanoseconds represent the offset from the given second.
82-
///
83-
/// For example a timespec of 1.2 seconds after the beginning of the epoch would
84-
/// be represented as {sec: 1, nsec: 200000000}.
85-
struct Timespec {
86-
sec: i64,
87-
nsec: i32,
88-
}
89-
90-
impl Timespec {
91-
/// Converts this timespec into the system's local time.
92-
fn local(self) -> Tm {
93-
let mut tm = Tm {
94-
tm_sec: 0,
95-
tm_min: 0,
96-
tm_hour: 0,
97-
tm_mday: 0,
98-
tm_mon: 0,
99-
tm_year: 0,
100-
tm_wday: 0,
101-
tm_yday: 0,
102-
tm_isdst: 0,
103-
tm_utcoff: 0,
104-
tm_nsec: 0,
105-
};
106-
time_to_local_tm(self.sec, &mut tm);
107-
tm.tm_nsec = self.nsec;
108-
tm
109-
}
110-
}
111-
112-
/// Holds a calendar date and time broken down into its components (year, month,
113-
/// day, and so on), also called a broken-down time value.
114-
// FIXME: use c_int instead of i32?
115-
#[repr(C)]
116-
pub(super) struct Tm {
117-
/// Seconds after the minute - [0, 60]
118-
tm_sec: i32,
119-
120-
/// Minutes after the hour - [0, 59]
121-
tm_min: i32,
122-
123-
/// Hours after midnight - [0, 23]
124-
tm_hour: i32,
125-
126-
/// Day of the month - [1, 31]
127-
tm_mday: i32,
128-
129-
/// Months since January - [0, 11]
130-
tm_mon: i32,
131-
132-
/// Years since 1900
133-
tm_year: i32,
134-
135-
/// Days since Sunday - [0, 6]. 0 = Sunday, 1 = Monday, ..., 6 = Saturday.
136-
tm_wday: i32,
137-
138-
/// Days since January 1 - [0, 365]
139-
tm_yday: i32,
140-
141-
/// Daylight Saving Time flag.
142-
///
143-
/// This value is positive if Daylight Saving Time is in effect, zero if
144-
/// Daylight Saving Time is not in effect, and negative if this information
145-
/// is not available.
146-
tm_isdst: i32,
147-
148-
/// Identifies the time zone that was used to compute this broken-down time
149-
/// value, including any adjustment for Daylight Saving Time. This is the
150-
/// number of seconds east of UTC. For example, for U.S. Pacific Daylight
151-
/// Time, the value is `-7*60*60 = -25200`.
152-
tm_utcoff: i32,
153-
154-
/// Nanoseconds after the second - [0, 10<sup>9</sup> - 1]
155-
tm_nsec: i32,
156-
}
157-
158-
fn time_to_tm(ts: i64, tm: &mut Tm) {
159-
let leapyear = |year| -> bool { year % 4 == 0 && (year % 100 != 0 || year % 400 == 0) };
160-
161-
static YTAB: [[i64; 12]; 2] = [
162-
[31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
163-
[31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
164-
];
165-
166-
let mut year = 1970;
167-
168-
let dayclock = ts % 86400;
169-
let mut dayno = ts / 86400;
170-
171-
tm.tm_sec = (dayclock % 60) as i32;
172-
tm.tm_min = ((dayclock % 3600) / 60) as i32;
173-
tm.tm_hour = (dayclock / 3600) as i32;
174-
tm.tm_wday = ((dayno + 4) % 7) as i32;
175-
loop {
176-
let yearsize = if leapyear(year) { 366 } else { 365 };
177-
if dayno >= yearsize {
178-
dayno -= yearsize;
179-
year += 1;
180-
} else {
181-
break;
182-
}
183-
}
184-
tm.tm_year = (year - 1900) as i32;
185-
tm.tm_yday = dayno as i32;
186-
let mut mon = 0;
187-
while dayno >= YTAB[if leapyear(year) { 1 } else { 0 }][mon] {
188-
dayno -= YTAB[if leapyear(year) { 1 } else { 0 }][mon];
189-
mon += 1;
190-
}
191-
tm.tm_mon = mon as i32;
192-
tm.tm_mday = dayno as i32 + 1;
193-
tm.tm_isdst = 0;
194-
}
195-
196-
fn tm_to_time(tm: &Tm) -> i64 {
197-
let mut y = tm.tm_year as i64 + 1900;
198-
let mut m = tm.tm_mon as i64 + 1;
199-
if m <= 2 {
200-
y -= 1;
201-
m += 12;
202-
}
203-
let d = tm.tm_mday as i64;
204-
let h = tm.tm_hour as i64;
205-
let mi = tm.tm_min as i64;
206-
let s = tm.tm_sec as i64;
207-
(365 * y + y / 4 - y / 100 + y / 400 + 3 * (m + 1) / 5 + 30 * m + d - 719561) * 86400
208-
+ 3600 * h
209-
+ 60 * mi
210-
+ s
211-
}
212-
213-
pub(super) fn time_to_local_tm(sec: i64, tm: &mut Tm) {
214-
// FIXME: Add timezone logic
215-
time_to_tm(sec, tm);
216-
}
217-
218-
pub(super) fn utc_tm_to_time(tm: &Tm) -> i64 {
219-
tm_to_time(tm)
13+
pub(super) fn offset_from_utc_datetime(_utc_time: &NaiveDateTime) -> LocalResult<FixedOffset> {
14+
LocalResult::Single(FixedOffset::east_opt(0).unwrap())
22015
}
22116

222-
pub(super) fn local_tm_to_time(tm: &Tm) -> i64 {
223-
// FIXME: Add timezone logic
224-
tm_to_time(tm)
17+
pub(super) fn offset_from_local_datetime(_local_time: &NaiveDateTime) -> LocalResult<FixedOffset> {
18+
LocalResult::Single(FixedOffset::east_opt(0).unwrap())
22519
}

src/offset/local/unix.rs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,17 @@
1111
use std::{cell::RefCell, collections::hash_map, env, fs, hash::Hasher, time::SystemTime};
1212

1313
use super::tz_info::TimeZone;
14-
use super::{DateTime, Local, NaiveDateTime};
15-
use crate::{Datelike, LocalResult};
14+
use crate::{Datelike, FixedOffset, LocalResult, NaiveDateTime};
1615

17-
pub(super) fn naive_to_local(d: &NaiveDateTime, local: bool) -> LocalResult<DateTime<Local>> {
16+
pub(super) fn offset_from_utc_datetime(utc: &NaiveDateTime) -> LocalResult<FixedOffset> {
17+
get_offset(utc, false)
18+
}
19+
20+
pub(super) fn offset_from_local_datetime(local: &NaiveDateTime) -> LocalResult<FixedOffset> {
21+
get_offset(local, true)
22+
}
23+
24+
fn get_offset(d: &NaiveDateTime, local: bool) -> LocalResult<FixedOffset> {
1825
TZ_INFO.with(|maybe_cache| {
1926
maybe_cache.borrow_mut().get_or_insert_with(Cache::default).offset(*d, local)
2027
})
@@ -97,7 +104,7 @@ fn current_zone(var: Option<&str>) -> TimeZone {
97104
}
98105

99106
impl Cache {
100-
fn offset(&mut self, d: NaiveDateTime, local: bool) -> LocalResult<DateTime<Local>> {
107+
fn offset(&mut self, d: NaiveDateTime, local: bool) -> LocalResult<FixedOffset> {
101108
let now = SystemTime::now();
102109

103110
match now.duration_since(self.last_checked) {
@@ -147,14 +154,13 @@ impl Cache {
147154
.find_local_time_type(d.timestamp())
148155
.expect("unable to select local time type")
149156
.ut_offset;
150-
return LocalResult::Single(DateTime::from_utc(d, offset));
157+
return LocalResult::Single(offset);
151158
}
152159

153160
// we pass through the year as the year of a local point in time must either be valid in that locale, or
154161
// the entire time was skipped in which case we will return LocalResult::None anyway.
155162
self.zone
156163
.find_local_offset_from_local(d.timestamp(), d.year())
157164
.expect("unable to select local time type")
158-
.map(|offset| DateTime::from_utc(d - offset, offset))
159165
}
160166
}

0 commit comments

Comments
 (0)