#![doc = include_str!("README.md")]
mod timezone;
pub use timezone::Timezone;
pub use libtz_sys::TimeT;
use std::mem::MaybeUninit;
use std::ffi::{CStr};
#[derive(Clone, Debug, PartialEq)]
pub struct Tm {
pub tm_sec : i32,
pub tm_min : i32,
pub tm_hour : i32,
pub tm_mday : i32,
pub tm_mon : i32,
pub tm_year : i32,
pub tm_wday : i32,
pub tm_yday : i32,
pub tm_isdst : i32,
pub tm_gmtoff : i64,
pub tm_zone : String,
}
impl TryFrom<&libtz_sys::Tm> for Tm {
type Error = String;
fn try_from(tztm: &libtz_sys::Tm) -> Result<Self, Self::Error> {
let zone: &str = unsafe { CStr::from_ptr(tztm.tm_zone).to_str().map_err(|_| "Invalid utf8")? };
Ok(Tm{
tm_sec : tztm.tm_sec,
tm_min : tztm.tm_min,
tm_hour : tztm.tm_hour,
tm_mday : tztm.tm_mday,
tm_mon : tztm.tm_mon,
tm_year : tztm.tm_year,
tm_wday : tztm.tm_wday,
tm_yday : tztm.tm_yday,
tm_isdst : tztm.tm_isdst,
tm_gmtoff : tztm.tm_gmtoff,
tm_zone : zone.to_string(),
})
}
}
impl Into<libtz_sys::Tm> for &Tm {
fn into(self) -> libtz_sys::Tm {
libtz_sys::Tm{
tm_sec : self.tm_sec,
tm_min : self.tm_min,
tm_hour : self.tm_hour,
tm_mday : self.tm_mday,
tm_mon : self.tm_mon,
tm_year : self.tm_year,
tm_wday : self.tm_wday,
tm_yday : self.tm_yday,
tm_isdst : self.tm_isdst,
tm_gmtoff : self.tm_gmtoff,
tm_zone : std::ptr::null_mut(),
}
}
}
pub fn timegm(tm: &Tm) -> Result<TimeT, String> {
match unsafe { libtz_sys::timegm(&tm.into()) } {
-1 => Err(format!("Invalid date specified")),
time => Ok(time),
}
}
pub fn gmtime(time: TimeT) -> Result<Tm, String> {
let mut tztm = MaybeUninit::<libtz_sys::Tm>::uninit();
let ret = unsafe { libtz_sys::gmtime_r(&time, tztm.as_mut_ptr()) };
if ret == std::ptr::null_mut() {
return Err(format!("errno={}", std::io::Error::last_os_error()));
}
let tztm = unsafe { tztm.assume_init() };
Tm::try_from(&tztm)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn gmtime_test() {
let time = 283996800;
let tm = gmtime(time).expect("gmtime");
assert_eq!(tm, Tm{tm_sec :0,
tm_min :0,
tm_hour :0,
tm_mday :1,
tm_mon :0,
tm_year :79,
tm_wday :1,
tm_yday :0,
tm_isdst :0,
tm_gmtoff :0,
tm_zone :"UTC".to_string()});
assert_eq!(timegm(&tm).expect("timegm"), time);
}
#[test]
fn test_readme_deps() {
version_sync::assert_markdown_deps_updated!("README.md");
}
}