chrono/offset/local/
mod.rs1#[cfg(feature = "rkyv")]
7use rkyv::{Archive, Deserialize, Serialize};
8
9use super::fixed::FixedOffset;
10use super::{LocalResult, TimeZone};
11use crate::naive::{NaiveDate, NaiveDateTime, NaiveTime};
12#[allow(deprecated)]
13use crate::Date;
14use crate::{DateTime, Utc};
15
16#[cfg(unix)]
17#[path = "unix.rs"]
18mod inner;
19
20#[cfg(windows)]
21#[path = "windows.rs"]
22mod inner;
23
24#[cfg(all(windows, feature = "clock"))]
25#[allow(unreachable_pub)]
26mod win_bindings;
27
28#[cfg(all(
29 not(unix),
30 not(windows),
31 not(all(
32 target_arch = "wasm32",
33 feature = "wasmbind",
34 not(any(target_os = "emscripten", target_os = "wasi"))
35 ))
36))]
37mod inner {
38 use crate::{FixedOffset, LocalResult, NaiveDateTime};
39
40 pub(super) fn offset_from_utc_datetime(_utc_time: &NaiveDateTime) -> LocalResult<FixedOffset> {
41 LocalResult::Single(FixedOffset::east_opt(0).unwrap())
42 }
43
44 pub(super) fn offset_from_local_datetime(
45 _local_time: &NaiveDateTime,
46 ) -> LocalResult<FixedOffset> {
47 LocalResult::Single(FixedOffset::east_opt(0).unwrap())
48 }
49}
50
51#[cfg(all(
52 target_arch = "wasm32",
53 feature = "wasmbind",
54 not(any(target_os = "emscripten", target_os = "wasi"))
55))]
56mod inner {
57 use crate::{Datelike, FixedOffset, LocalResult, NaiveDateTime, Timelike};
58
59 pub(super) fn offset_from_utc_datetime(utc: &NaiveDateTime) -> LocalResult<FixedOffset> {
60 let offset = js_sys::Date::from(utc.and_utc()).get_timezone_offset();
61 LocalResult::Single(FixedOffset::west_opt((offset as i32) * 60).unwrap())
62 }
63
64 pub(super) fn offset_from_local_datetime(local: &NaiveDateTime) -> LocalResult<FixedOffset> {
65 let mut year = local.year();
66 if year < 100 {
67 let shift_cycles = (year - 100).div_euclid(400);
71 year -= shift_cycles * 400;
72 }
73 let js_date = js_sys::Date::new_with_year_month_day_hr_min_sec(
74 year as u32,
75 local.month0() as i32,
76 local.day() as i32,
77 local.hour() as i32,
78 local.minute() as i32,
79 local.second() as i32,
80 );
82 let offset = js_date.get_timezone_offset();
83 LocalResult::Single(FixedOffset::west_opt((offset as i32) * 60).unwrap())
85 }
86}
87
88#[cfg(unix)]
89mod tz_info;
90
91#[derive(Copy, Clone, Debug)]
107#[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))]
108#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
109pub struct Local;
110
111impl Local {
112 #[deprecated(since = "0.4.23", note = "use `Local::now()` instead")]
114 #[allow(deprecated)]
115 #[must_use]
116 pub fn today() -> Date<Local> {
117 Local::now().date()
118 }
119
120 pub fn now() -> DateTime<Local> {
148 Utc::now().with_timezone(&Local)
149 }
150}
151
152impl TimeZone for Local {
153 type Offset = FixedOffset;
154
155 fn from_offset(_offset: &FixedOffset) -> Local {
156 Local
157 }
158
159 #[allow(deprecated)]
160 fn offset_from_local_date(&self, local: &NaiveDate) -> LocalResult<FixedOffset> {
161 self.offset_from_local_datetime(&local.and_time(NaiveTime::MIN))
163 }
164
165 fn offset_from_local_datetime(&self, local: &NaiveDateTime) -> LocalResult<FixedOffset> {
166 inner::offset_from_local_datetime(local)
167 }
168
169 #[allow(deprecated)]
170 fn offset_from_utc_date(&self, utc: &NaiveDate) -> FixedOffset {
171 self.offset_from_utc_datetime(&utc.and_time(NaiveTime::MIN))
173 }
174
175 fn offset_from_utc_datetime(&self, utc: &NaiveDateTime) -> FixedOffset {
176 inner::offset_from_utc_datetime(utc).unwrap()
177 }
178}
179
180#[cfg(test)]
181mod tests {
182 use super::Local;
183 use crate::offset::TimeZone;
184 use crate::{Datelike, Duration, Utc};
185
186 #[test]
187 fn verify_correct_offsets() {
188 let now = Local::now();
189 let from_local = Local.from_local_datetime(&now.naive_local()).unwrap();
190 let from_utc = Local.from_utc_datetime(&now.naive_utc());
191
192 assert_eq!(now.offset().local_minus_utc(), from_local.offset().local_minus_utc());
193 assert_eq!(now.offset().local_minus_utc(), from_utc.offset().local_minus_utc());
194
195 assert_eq!(now, from_local);
196 assert_eq!(now, from_utc);
197 }
198
199 #[test]
200 fn verify_correct_offsets_distant_past() {
201 let distant_past = Local::now() - Duration::days(250 * 31);
203 let from_local = Local.from_local_datetime(&distant_past.naive_local()).unwrap();
204 let from_utc = Local.from_utc_datetime(&distant_past.naive_utc());
205
206 assert_eq!(distant_past.offset().local_minus_utc(), from_local.offset().local_minus_utc());
207 assert_eq!(distant_past.offset().local_minus_utc(), from_utc.offset().local_minus_utc());
208
209 assert_eq!(distant_past, from_local);
210 assert_eq!(distant_past, from_utc);
211 }
212
213 #[test]
214 fn verify_correct_offsets_distant_future() {
215 let distant_future = Local::now() + Duration::days(250 * 31);
216 let from_local = Local.from_local_datetime(&distant_future.naive_local()).unwrap();
217 let from_utc = Local.from_utc_datetime(&distant_future.naive_utc());
218
219 assert_eq!(
220 distant_future.offset().local_minus_utc(),
221 from_local.offset().local_minus_utc()
222 );
223 assert_eq!(distant_future.offset().local_minus_utc(), from_utc.offset().local_minus_utc());
224
225 assert_eq!(distant_future, from_local);
226 assert_eq!(distant_future, from_utc);
227 }
228
229 #[test]
230 fn test_local_date_sanity_check() {
231 assert_eq!(Local.with_ymd_and_hms(2999, 12, 28, 0, 0, 0).unwrap().day(), 28);
233 }
234
235 #[test]
236 fn test_leap_second() {
237 let today = Utc::now().date_naive();
239
240 if let Some(dt) = today.and_hms_milli_opt(15, 2, 59, 1000) {
241 let timestr = dt.time().to_string();
242 assert!(
245 timestr == "15:02:60" || timestr == "15:03:00",
246 "unexpected timestr {:?}",
247 timestr
248 );
249 }
250
251 if let Some(dt) = today.and_hms_milli_opt(15, 2, 3, 1234) {
252 let timestr = dt.time().to_string();
253 assert!(
254 timestr == "15:02:03.234" || timestr == "15:02:04.234",
255 "unexpected timestr {:?}",
256 timestr
257 );
258 }
259 }
260}