time_c/
sys.rs

1//!Raw system types and functions
2#![allow(non_camel_case_types)]
3#![allow(non_snake_case)]
4
5use crate::Time;
6
7use core::{mem, ptr, time};
8use core::ffi::{c_void, c_int, c_long};
9
10///Alias to time_t.
11///
12///This crate supports 64bit time only
13///
14///## Note
15///
16///Your system uses 32bit for time()? Don't use this crate then
17pub type time_t = i64;
18
19#[repr(C)]
20#[derive(Copy, Clone, Debug)]
21///C definition of decoded time.
22pub struct tm {
23    ///Seconds after the minute. Range 0-60
24    pub tm_sec: c_int,
25    ///Minutes after the hour. Range 0-59
26    pub tm_min: c_int,
27    ///Hours since midnight. Range 0-23
28    pub tm_hour: c_int,
29    ///Day of the month. Range 1-31
30    pub tm_mday: c_int,
31    ///Months since January. Range 0-11
32    pub tm_mon: c_int,
33    ///Years since 1900
34    pub tm_year: c_int,
35    ///days since Sunday. Range 0-6
36    pub tm_wday: c_int,
37    ///days since January 1. Range 0-365
38    pub tm_yday: c_int,
39    /// Daylight Saving Time flag. Non-zero value indicates DST is present.
40    pub tm_isdst: c_int,
41    //Other fields are non-standard and depend on platform
42    //So don't care about these fields
43    _reserved: mem::MaybeUninit<[u8; mem::size_of::<c_long>() + mem::size_of::<*const c_void>() + mem::size_of::<c_int>()]>,
44}
45
46impl tm {
47    ///Normalizes time to a more convenient struct for interpreting time components.
48    pub const fn normalize(&self) -> Time {
49        let tm {
50            tm_sec,
51            tm_min,
52            tm_hour,
53            tm_mday,
54            tm_mon,
55            tm_year,
56            tm_wday,
57            tm_yday,
58            tm_isdst,
59            ..
60        } = self;
61
62        Time {
63            sec: *tm_sec as _,
64            min: *tm_min as _,
65            hour: *tm_hour as _,
66            month_day: *tm_mday as _,
67            month: (*tm_mon as u8).saturating_add(1),
68            year: (*tm_year as u16).saturating_add(1900),
69            week_day: *tm_wday as _,
70            day: *tm_yday as _,
71            is_dst: *tm_isdst > 0,
72        }
73    }
74}
75
76extern "C" {
77    #[cfg_attr(windows, link_name = "_time64")]
78    ///Raw C API function to access time
79    pub fn time(time: *mut time_t) -> time_t;
80}
81
82///Gets current UTC time in seconds, if available.
83pub fn get_time() -> Option<time_t> {
84    let result = unsafe {
85        time(ptr::null_mut())
86    };
87
88    match result {
89        -1 => None,
90        time => Some(time)
91    }
92}
93
94
95#[cfg(windows)]
96///Parses UTC time into tm struct, if possible
97pub fn parse_unix(timer: &time_t) -> Option<tm> {
98    extern "C" {
99        #[link_name = "_gmtime64_s"]
100        pub fn gmtime_s(buf: *mut tm, timer: *const time_t) -> c_int;
101    }
102
103    let mut tm = mem::MaybeUninit::uninit();
104    let res = unsafe {
105        gmtime_s(tm.as_mut_ptr(), timer)
106    };
107    match res {
108        0 => unsafe {
109            Some(tm.assume_init())
110        },
111        _ => None,
112    }
113}
114
115#[cfg(not(windows))]
116///Parses UTC time into tm struct, if possible
117pub fn parse_unix(timer: &time_t) -> Option<tm> {
118    extern "C" {
119        pub fn gmtime_r(timer: *const time_t, buf: *mut tm) -> *mut tm;
120    }
121
122    let mut tm = mem::MaybeUninit::uninit();
123    let res = unsafe {
124        gmtime_r(timer, tm.as_mut_ptr())
125    };
126    if res.is_null() {
127        None
128    } else {
129        unsafe {
130            Some(tm.assume_init())
131        }
132    }
133}
134
135#[cfg(windows)]
136///Gets UTC time, if available
137pub fn utc_now() -> Option<time::Duration> {
138    #[repr(C)]
139    #[derive(Copy, Clone)]
140    pub struct FILETIME {
141        pub dwLowDateTime: u32,
142        pub dwHighDateTime: u32,
143    }
144
145    #[repr(C)]
146    pub union ULARGE_INTEGER {
147        file_time: FILETIME,
148        integer: u64,
149    }
150
151    extern "system" {
152        fn GetSystemTimeAsFileTime(time: *mut FILETIME);
153    }
154
155    let time = unsafe {
156        let mut time = mem::MaybeUninit::<ULARGE_INTEGER>::uninit();
157        GetSystemTimeAsFileTime(ptr::addr_of_mut!((*time.as_mut_ptr()).file_time));
158        time.assume_init().integer.saturating_sub(116_444_736_000_000_000)
159    };
160
161    Some(time::Duration::new(
162        time / 10_000_000,
163        ((time % 10_000_000) * 100) as _
164    ))
165}
166
167#[cfg(unix)]
168///Gets UTC time, if available
169pub fn utc_now() -> Option<time::Duration> {
170    #[repr(C)]
171    struct timespec {
172        tv_sec: time_t,
173        #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))]
174        tv_nanos: i64,
175        #[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))]
176        tv_nanos: c_long,
177    }
178
179    extern "C" {
180        fn timespec_get(time: *mut timespec, base: c_int) -> c_int;
181    }
182
183    let time = unsafe {
184        let mut time = mem::MaybeUninit::uninit();
185        if timespec_get(time.as_mut_ptr(), 1) == 0 {
186            return None;
187        }
188        time.assume_init()
189    };
190
191    Some(time::Duration::new(time.tv_sec as _, time.tv_nanos as _))
192}
193