time/sys/local_offset_at/
unix.rs1use core::mem::MaybeUninit;
4
5use crate::{OffsetDateTime, UtcOffset};
6
7fn timestamp_to_tm(timestamp: i64) -> Option<libc::tm> {
9 #[allow(clippy::useless_conversion)]
11 let timestamp = timestamp.try_into().ok()?;
12
13 let mut tm = MaybeUninit::uninit();
14
15 let tm_ptr = unsafe { libc::localtime_r(×tamp, tm.as_mut_ptr()) };
18
19 if tm_ptr.is_null() {
20 None
21 } else {
22 Some(unsafe { tm.assume_init() })
24 }
25}
26
27#[cfg(any(
30 target_os = "redox",
31 target_os = "linux",
32 target_os = "l4re",
33 target_os = "android",
34 target_os = "emscripten",
35 target_os = "macos",
36 target_os = "ios",
37 target_os = "watchos",
38 target_os = "freebsd",
39 target_os = "dragonfly",
40 target_os = "openbsd",
41 target_os = "netbsd",
42 target_os = "haiku",
43))]
44fn tm_to_offset(_unix_timestamp: i64, tm: libc::tm) -> Option<UtcOffset> {
45 let seconds = tm.tm_gmtoff.try_into().ok()?;
46 UtcOffset::from_whole_seconds(seconds).ok()
47}
48
49#[cfg(not(any(
56 target_os = "redox",
57 target_os = "linux",
58 target_os = "l4re",
59 target_os = "android",
60 target_os = "emscripten",
61 target_os = "macos",
62 target_os = "ios",
63 target_os = "watchos",
64 target_os = "freebsd",
65 target_os = "dragonfly",
66 target_os = "openbsd",
67 target_os = "netbsd",
68 target_os = "haiku",
69)))]
70fn tm_to_offset(unix_timestamp: i64, tm: libc::tm) -> Option<UtcOffset> {
71 use crate::Date;
72
73 let mut tm = tm;
74 if tm.tm_sec == 60 {
75 tm.tm_sec = 59;
77 }
78
79 let local_timestamp =
80 Date::from_ordinal_date(1900 + tm.tm_year, u16::try_from(tm.tm_yday).ok()? + 1)
81 .ok()?
82 .with_hms(
83 tm.tm_hour.try_into().ok()?,
84 tm.tm_min.try_into().ok()?,
85 tm.tm_sec.try_into().ok()?,
86 )
87 .ok()?
88 .assume_utc()
89 .unix_timestamp();
90
91 let diff_secs = (local_timestamp - unix_timestamp).try_into().ok()?;
92
93 UtcOffset::from_whole_seconds(diff_secs).ok()
94}
95
96pub(super) fn local_offset_at(datetime: OffsetDateTime) -> Option<UtcOffset> {
98 let unix_timestamp = datetime.unix_timestamp();
99 let tm = timestamp_to_tm(unix_timestamp)?;
100 tm_to_offset(unix_timestamp, tm)
101}