time/sys/local_offset_at/
unix.rs1use core::mem::MaybeUninit;
4
5use crate::{OffsetDateTime, UtcOffset};
6
7#[inline]
9fn timestamp_to_tm(timestamp: i64) -> Option<libc::tm> {
10 #[allow(
11 clippy::useless_conversion,
12 reason = "the exact type of `timestamp` beforehand can vary, so this conversion is \
13 necessary"
14 )]
15 let timestamp = timestamp.try_into().ok()?;
16
17 let mut tm = MaybeUninit::uninit();
18
19 let tm_ptr = unsafe { libc::localtime_r(×tamp, tm.as_mut_ptr()) };
22
23 if tm_ptr.is_null() {
24 None
25 } else {
26 Some(unsafe { tm.assume_init() })
28 }
29}
30
31#[cfg(any(
34 target_os = "redox",
35 target_os = "linux",
36 target_os = "l4re",
37 target_os = "android",
38 target_os = "emscripten",
39 target_os = "macos",
40 target_os = "ios",
41 target_os = "watchos",
42 target_os = "freebsd",
43 target_os = "dragonfly",
44 target_os = "openbsd",
45 target_os = "netbsd",
46 target_os = "haiku",
47))]
48#[inline]
49fn tm_to_offset(_unix_timestamp: i64, tm: libc::tm) -> Option<UtcOffset> {
50 let seconds = tm.tm_gmtoff.try_into().ok()?;
51 UtcOffset::from_whole_seconds(seconds).ok()
52}
53
54#[cfg(not(any(
61 target_os = "redox",
62 target_os = "linux",
63 target_os = "l4re",
64 target_os = "android",
65 target_os = "emscripten",
66 target_os = "macos",
67 target_os = "ios",
68 target_os = "watchos",
69 target_os = "freebsd",
70 target_os = "dragonfly",
71 target_os = "openbsd",
72 target_os = "netbsd",
73 target_os = "haiku",
74)))]
75#[inline]
76fn tm_to_offset(unix_timestamp: i64, tm: libc::tm) -> Option<UtcOffset> {
77 use crate::Date;
78
79 let mut tm = tm;
80 if tm.tm_sec == 60 {
81 tm.tm_sec = 59;
83 }
84
85 let local_timestamp =
86 Date::from_ordinal_date(1900 + tm.tm_year, u16::try_from(tm.tm_yday).ok()? + 1)
87 .ok()?
88 .with_hms(
89 tm.tm_hour.try_into().ok()?,
90 tm.tm_min.try_into().ok()?,
91 tm.tm_sec.try_into().ok()?,
92 )
93 .ok()?
94 .assume_utc()
95 .unix_timestamp();
96
97 let diff_secs = (local_timestamp - unix_timestamp).try_into().ok()?;
98
99 UtcOffset::from_whole_seconds(diff_secs).ok()
100}
101
102#[inline]
104pub(super) fn local_offset_at(datetime: OffsetDateTime) -> Option<UtcOffset> {
105 let unix_timestamp = datetime.unix_timestamp();
106 let tm = timestamp_to_tm(unix_timestamp)?;
107 tm_to_offset(unix_timestamp, tm)
108}