1#![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
10pub type time_t = i64;
18
19#[repr(C)]
20#[derive(Copy, Clone, Debug)]
21pub struct tm {
23 pub tm_sec: c_int,
25 pub tm_min: c_int,
27 pub tm_hour: c_int,
29 pub tm_mday: c_int,
31 pub tm_mon: c_int,
33 pub tm_year: c_int,
35 pub tm_wday: c_int,
37 pub tm_yday: c_int,
39 pub tm_isdst: c_int,
41 _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 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 pub fn time(time: *mut time_t) -> time_t;
80}
81
82pub 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)]
96pub 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))]
116pub 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)]
136pub 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)]
168pub 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