Skip to content

Commit 6d82f95

Browse files
committed
Only implement the offset_from_ methods on Local
1 parent 7c7bc85 commit 6d82f95

File tree

5 files changed

+82
-344
lines changed

5 files changed

+82
-344
lines changed

src/offset/local/mod.rs

+15-72
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,11 @@ use rkyv::{Archive, Deserialize, Serialize};
88

99
use super::fixed::FixedOffset;
1010
use super::{LocalResult, TimeZone};
11-
use crate::naive::{NaiveDate, NaiveDateTime};
11+
use crate::naive::{NaiveDate, NaiveDateTime, NaiveTime};
1212
#[allow(deprecated)]
1313
use crate::Date;
1414
use crate::{DateTime, Utc};
1515

16-
// we don't want `stub.rs` when the target_os is not wasi or emscripten
17-
// as we use js-sys to get the date instead
1816
#[cfg(all(
1917
not(unix),
2018
not(windows),
@@ -35,6 +33,14 @@ mod inner;
3533
#[path = "windows.rs"]
3634
mod inner;
3735

36+
#[cfg(all(
37+
target_arch = "wasm32",
38+
feature = "wasmbind",
39+
not(any(target_os = "emscripten", target_os = "wasi"))
40+
))]
41+
#[path = "wasmbind.rs"]
42+
mod inner;
43+
3844
#[cfg(unix)]
3945
mod tz_info;
4046

@@ -103,87 +109,24 @@ impl TimeZone for Local {
103109
Local
104110
}
105111

106-
// they are easier to define in terms of the finished date and time unlike other offsets
107112
#[allow(deprecated)]
108113
fn offset_from_local_date(&self, local: &NaiveDate) -> LocalResult<FixedOffset> {
109-
self.from_local_date(local).map(|date| *date.offset())
114+
// Get the offset at local midnight.
115+
self.offset_from_local_datetime(&local.and_time(NaiveTime::MIN))
110116
}
111117

112118
fn offset_from_local_datetime(&self, local: &NaiveDateTime) -> LocalResult<FixedOffset> {
113-
self.from_local_datetime(local).map(|datetime| *datetime.offset())
119+
inner::offset_from_local_datetime(local)
114120
}
115121

116122
#[allow(deprecated)]
117123
fn offset_from_utc_date(&self, utc: &NaiveDate) -> FixedOffset {
118-
*self.from_utc_date(utc).offset()
124+
// Get the offset at midnight.
125+
self.offset_from_utc_datetime(&utc.and_time(NaiveTime::MIN))
119126
}
120127

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

src/offset/local/stub.rs

+5-211
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
}

0 commit comments

Comments
 (0)