1use core::{sync::atomic::Ordering, time::Duration};
2
3use crate::RtVdsoVtable;
4
5#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
6#[repr(C)]
7pub struct Instant {
8 ticks: u64, }
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
12#[repr(C)]
13pub struct SystemTime {
14 nanos: u128, }
16
17#[allow(unused)]
18pub const UNIX_EPOCH: SystemTime = SystemTime { nanos: 0u128 };
19const NANOS_IN_SEC: u64 = 1_000_000_000;
20
21impl Instant {
22 pub const fn nan() -> Self {
23 Instant { ticks: 0 }
24 }
25 pub fn is_nan(&self) -> bool {
26 self.ticks == 0
27 }
28
29 pub fn from_u64(val: u64) -> Self {
30 Instant { ticks: val }
31 }
32
33 pub fn as_u64(&self) -> u64 {
34 self.ticks
35 }
36
37 pub fn now() -> Self {
38 let vdso_time_instant_now: extern "C" fn() -> u64 = unsafe {
39 core::mem::transmute(
40 RtVdsoVtable::get().time_instant_now.load(Ordering::Relaxed) as usize as *const ()
41 )
42 };
43
44 Self {
45 ticks: vdso_time_instant_now(),
46 }
47 }
48
49 pub fn duration_since(&self, earlier: Instant) -> Duration {
50 if earlier.ticks > self.ticks {
51 return Duration::ZERO;
52 }
53
54 let ticks_diff = self.ticks - earlier.ticks;
55 if ticks_diff == 0 {
56 return Duration::ZERO;
57 }
58
59 let nanos = ticks_to_nanos(ticks_diff);
60
61 Duration::new(
62 (nanos / (NANOS_IN_SEC as u128)) as u64,
63 (nanos % (NANOS_IN_SEC as u128)) as u32,
64 )
65 }
66
67 pub fn elapsed(&self) -> Duration {
68 Instant::now().duration_since(*self)
69 }
70
71 pub const fn infinite_future() -> Self {
72 Instant { ticks: u64::MAX }
73 }
74
75 pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
76 if *self < *other {
77 return None;
78 }
79
80 let result_ticks = self.ticks - other.ticks;
81 let result_nanos = ticks_to_nanos(result_ticks);
82 if result_nanos > (u64::MAX as u128) {
83 None
84 } else {
85 Some(Duration::from_nanos(result_nanos as u64))
86 }
87 }
88
89 pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
90 let tsc_secs = other.as_secs().checked_mul(ticks_in_sec())?;
91 let tsc_diff = nanos_to_ticks(other.subsec_nanos() as u64).checked_add(tsc_secs)?;
92
93 Some(Instant {
94 ticks: self.ticks.checked_add(tsc_diff)?,
95 })
96 }
97
98 pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
99 let tsc_secs = other.as_secs().checked_mul(ticks_in_sec())?;
100 let tsc_diff = nanos_to_ticks(other.subsec_nanos() as u64).checked_add(tsc_secs)?;
101
102 if tsc_diff > self.ticks {
103 None
104 } else {
105 Some(Instant {
106 ticks: self.ticks - tsc_diff,
107 })
108 }
109 }
110}
111
112impl core::ops::Add<Duration> for Instant {
113 type Output = Instant;
114
115 fn add(self, other: Duration) -> Instant {
116 let tsc_secs = other.as_secs() * ticks_in_sec();
117 let tsc_diff = nanos_to_ticks(other.subsec_nanos() as u64) + tsc_secs;
118
119 Instant {
120 ticks: self.ticks + tsc_diff,
121 }
122 }
123}
124
125impl core::ops::Sub<Duration> for Instant {
126 type Output = Instant;
127
128 fn sub(self, other: Duration) -> Self::Output {
129 let tsc_secs = other.as_secs() * ticks_in_sec();
130 let tsc_diff = nanos_to_ticks(other.subsec_nanos() as u64) + tsc_secs;
131
132 Instant {
133 ticks: self.ticks - tsc_diff,
134 }
135 }
136}
137
138pub fn since_system_start() -> Duration {
139 Instant::now()
140 .checked_sub_instant(&Instant { ticks: 0 })
141 .unwrap()
142}
143
144impl SystemTime {
145 pub const MIN: Self = Self { nanos: u128::MIN };
146 pub const MAX: Self = Self { nanos: u128::MAX };
147
148 pub fn now() -> Self {
149 SystemTime {
150 nanos: abs_ticks_to_nanos(Instant::now().ticks),
151 }
152 }
153
154 pub const fn as_u128(&self) -> u128 {
155 self.nanos
156 }
157
158 pub const fn from_u128(val: u128) -> Self {
159 Self { nanos: val }
160 }
161
162 pub const fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
163 if self.nanos >= other.nanos {
164 let total_nanos = self.nanos - other.nanos;
165 let secs = total_nanos / (NANOS_IN_SEC as u128);
166 let nanos = total_nanos % (NANOS_IN_SEC as u128);
167 Ok(Duration::new(secs as u64, nanos as u32))
168 } else {
169 let total_nanos = other.nanos - self.nanos;
170 let secs = total_nanos / (NANOS_IN_SEC as u128);
171 let nanos = total_nanos % (NANOS_IN_SEC as u128);
172 Err(Duration::new(secs as u64, nanos as u32))
173 }
174 }
175
176 pub const fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
177 match self.nanos.checked_add(other.as_nanos()) {
178 Some(nanos) => Some(Self { nanos }),
179 None => None,
180 }
181 }
182
183 pub const fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
184 match self.nanos.checked_sub(other.as_nanos()) {
185 Some(nanos) => Some(Self { nanos }),
186 None => None,
187 }
188 }
189}
190
191fn ticks_to_nanos(ticks: u64) -> u128 {
193 let vdso_ticks_to_nanos: extern "C" fn(u64, *mut u64, *mut u64) = unsafe {
194 core::mem::transmute(
195 RtVdsoVtable::get()
196 .time_ticks_to_nanos
197 .load(Ordering::Relaxed) as usize as *const (),
198 )
199 };
200
201 let mut hi = 0_u64;
202 let mut lo = 0_u64;
203
204 vdso_ticks_to_nanos(ticks, &mut hi, &mut lo);
205
206 ((hi as u128) << 64) + (lo as u128)
207}
208
209fn abs_ticks_to_nanos(ticks: u64) -> u128 {
211 let vdso_abs_ticks_to_nanos: extern "C" fn(u64, *mut u64, *mut u64) = unsafe {
212 core::mem::transmute(
213 RtVdsoVtable::get()
214 .time_abs_ticks_to_nanos
215 .load(Ordering::Relaxed) as usize as *const (),
216 )
217 };
218
219 let mut hi = 0_u64;
220 let mut lo = 0_u64;
221
222 vdso_abs_ticks_to_nanos(ticks, &mut hi, &mut lo);
223
224 ((hi as u128) << 64) + (lo as u128)
225}
226
227fn nanos_to_ticks(nanos: u64) -> u64 {
228 let vdso_nanos_to_ticks: extern "C" fn(u64) -> u64 = unsafe {
229 core::mem::transmute(
230 RtVdsoVtable::get()
231 .time_nanos_to_ticks
232 .load(Ordering::Relaxed) as usize as *const (),
233 )
234 };
235
236 vdso_nanos_to_ticks(nanos)
237}
238
239fn ticks_in_sec() -> u64 {
240 RtVdsoVtable::get()
241 .time_ticks_in_sec
242 .load(Ordering::Relaxed)
243}
244
245#[derive(Debug)]
246pub struct UtcDateTime {
247 pub year: u32,
248 pub month: u8, pub day: u8, pub hour: u8,
251 pub minute: u8,
252 pub second: u8,
253 pub nanosecond: u32,
254}
255
256impl core::fmt::Display for UtcDateTime {
257 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
258 write!(
259 f,
260 "{}-{:02}-{:02} {:02}:{:02}:{:02}.{:03}Z",
261 self.year,
262 self.month,
263 self.day,
264 self.hour,
265 self.minute,
266 self.second,
267 self.nanosecond / (1000 * 1000)
268 )
269 }
270}
271
272impl UtcDateTime {
273 pub fn now() -> Self {
274 unsafe { Self::from_instant(Instant::now()) }
276 }
277
278 pub unsafe fn from_instant(ts: Instant) -> Self {
286 Self::from_unix_nanos(abs_ticks_to_nanos(ts.as_u64()))
287 }
288
289 pub fn from_unix_nanos(nanos: u128) -> Self {
290 let st = nanos as u64;
291 let nanosecond = (st % (1000 * 1000 * 1000)) as u32;
292
293 let seconds = (st - (nanosecond as u64)) / (1000 * 1000 * 1000);
294 let time = seconds % (24 * 60 * 60);
295
296 let second = (time % 60) as u8;
297 let minutes = (time - (second as u64)) / 60;
298 let minute = (minutes % 60) as u8;
299 let hour = ((minutes - (minute as u64)) / 60) as u8;
300
301 let mut days = (seconds - time) / (24 * 60 * 60);
302 let mut year: u32 = 1970;
303
304 fn leap_year(year: u32) -> bool {
305 year.is_multiple_of(400) || (year.is_multiple_of(4) && !year.is_multiple_of(100))
306 }
307
308 loop {
310 if leap_year(year) {
311 if days < 366 {
312 break;
313 }
314 days -= 366; } else if days < 365 {
316 break;
317 } else {
318 days -= 365; }
320 year += 1;
321 }
322
323 const MONTHS: [u8; 12] = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
325 let mut month: u8 = 0;
326 loop {
327 if month == 1 {
328 if leap_year(year) {
329 if days < 29 {
330 break;
331 }
332 days -= 29;
333 month += 1;
334 continue;
335 } else if days < 28 {
336 break;
337 }
338 days -= 28;
339 month += 1;
340 continue;
341 }
342 if days < MONTHS[month as usize] as u64 {
343 break;
344 }
345 days -= MONTHS[month as usize] as u64;
346 month += 1;
347 }
348
349 Self {
350 year,
351 month: month + 1,
352 day: (days + 1) as u8,
353 hour,
354 minute,
355 second,
356 nanosecond,
357 }
358 }
359}