time/sys/local_offset_at/
unix.rsuse core::mem::MaybeUninit;
use crate::{OffsetDateTime, UtcOffset};
fn timestamp_to_tm(timestamp: i64) -> Option<libc::tm> {
#[allow(clippy::useless_conversion)]
let timestamp = timestamp.try_into().ok()?;
let mut tm = MaybeUninit::uninit();
let tm_ptr = unsafe { libc::localtime_r(×tamp, tm.as_mut_ptr()) };
if tm_ptr.is_null() {
None
} else {
Some(unsafe { tm.assume_init() })
}
}
#[cfg(any(
target_os = "redox",
target_os = "linux",
target_os = "l4re",
target_os = "android",
target_os = "emscripten",
target_os = "macos",
target_os = "ios",
target_os = "watchos",
target_os = "freebsd",
target_os = "dragonfly",
target_os = "openbsd",
target_os = "netbsd",
target_os = "haiku",
))]
fn tm_to_offset(_unix_timestamp: i64, tm: libc::tm) -> Option<UtcOffset> {
let seconds = tm.tm_gmtoff.try_into().ok()?;
UtcOffset::from_whole_seconds(seconds).ok()
}
#[cfg(not(any(
target_os = "redox",
target_os = "linux",
target_os = "l4re",
target_os = "android",
target_os = "emscripten",
target_os = "macos",
target_os = "ios",
target_os = "watchos",
target_os = "freebsd",
target_os = "dragonfly",
target_os = "openbsd",
target_os = "netbsd",
target_os = "haiku",
)))]
fn tm_to_offset(unix_timestamp: i64, tm: libc::tm) -> Option<UtcOffset> {
use crate::Date;
let mut tm = tm;
if tm.tm_sec == 60 {
tm.tm_sec = 59;
}
let local_timestamp =
Date::from_ordinal_date(1900 + tm.tm_year, u16::try_from(tm.tm_yday).ok()? + 1)
.ok()?
.with_hms(
tm.tm_hour.try_into().ok()?,
tm.tm_min.try_into().ok()?,
tm.tm_sec.try_into().ok()?,
)
.ok()?
.assume_utc()
.unix_timestamp();
let diff_secs = (local_timestamp - unix_timestamp).try_into().ok()?;
UtcOffset::from_whole_seconds(diff_secs).ok()
}
pub(super) fn local_offset_at(datetime: OffsetDateTime) -> Option<UtcOffset> {
let unix_timestamp = datetime.unix_timestamp();
let tm = timestamp_to_tm(unix_timestamp)?;
tm_to_offset(unix_timestamp, tm)
}