cuprate_helper/
time.rs

1//! System related
2//!
3//! Requires `std`.
4
5//---------------------------------------------------------------------------------------------------- Use
6use std::time::{SystemTime, UNIX_EPOCH};
7
8//---------------------------------------------------------------------------------------------------- Public API
9#[inline]
10/// Returns the current system time as a UNIX timestamp.
11///
12/// ```rust
13/// # use cuprate_helper::time::*;
14/// assert!(current_unix_timestamp() > 0);
15/// ```
16///
17/// # Panics
18/// This function panics if the call to get the system time fails.
19pub fn current_unix_timestamp() -> u64 {
20    SystemTime::now()
21        .duration_since(UNIX_EPOCH)
22        .unwrap()
23        .as_secs()
24}
25
26#[inline]
27/// Get the clock time of a UNIX timestamp
28///
29/// The input must be a UNIX timestamp.
30///
31/// The returned `u64` will represent how many seconds has
32/// passed on the day corresponding to that timestamp.
33///
34/// The output is guaranteed to be in the range of `0..=86399`.
35///
36/// ```rust
37/// # use cuprate_helper::time::*;
38/// // October 20th 2023 - 10:18:30 PM
39/// const TIME: u64 = 1697840310;
40///
41/// let seconds = unix_clock(TIME);
42/// assert_eq!(seconds, 80310);
43///
44/// let (h, m, s) = secs_to_clock(seconds);
45/// // 10:18:30 PM.
46/// assert_eq!((h, m, s), (22, 18, 30))
47/// ```
48pub const fn unix_clock(seconds_after_unix_epoch: u64) -> u32 {
49    (seconds_after_unix_epoch % 86400) as _
50}
51
52#[inline]
53/// Convert seconds to `hours`, `minutes` and `seconds`.
54///
55/// - The seconds returned is guaranteed to be `0..=59`
56/// - The minutes returned is guaranteed to be `0..=59`
57/// - The hours returned can be over `23`, as this is not a clock function,
58///   see [`secs_to_clock`] for clock-like behavior that wraps around on `24`
59///
60/// ```rust
61/// # use cuprate_helper::time::*;
62/// // 59 seconds.
63/// assert_eq!(secs_to_hms(59), (0, 0, 59));
64///
65/// // 1 minute.
66/// assert_eq!(secs_to_hms(60), (0, 1, 0));
67///
68/// // 59 minutes, 59 seconds.
69/// assert_eq!(secs_to_hms(3599), (0, 59, 59));
70///
71/// // 1 hour.
72/// assert_eq!(secs_to_hms(3600), (1, 0, 0));
73///
74/// // 23 hours, 59 minutes, 59 seconds.
75/// assert_eq!(secs_to_hms(86399), (23, 59, 59));
76///
77/// // 24 hours.
78/// assert_eq!(secs_to_hms(86400), (24, 0, 0));
79/// ```
80pub const fn secs_to_hms(seconds: u64) -> (u64, u8, u8) {
81    let hours = seconds / 3600;
82    let minutes = (seconds % 3600) / 60;
83    let seconds = (seconds % 3600) % 60;
84
85    debug_assert!(minutes < 60);
86    debug_assert!(seconds < 60);
87
88    (hours, minutes as u8, seconds as u8)
89}
90
91#[inline]
92/// Convert seconds to clock time, `hours`, `minutes` and `seconds`.
93///
94/// This is the same as [`secs_to_hms`] except it will wrap around,
95/// e.g, `24:00:00` would turn into `00:00:00`.
96///
97/// - The seconds returned is guaranteed to be `0..=59`
98/// - The minutes returned is guaranteed to be `0..=59`
99/// - The hours returned is guaranteed to be `0..=23`
100///
101/// ```rust
102/// # use cuprate_helper::time::*;
103/// // 59 seconds.
104/// assert_eq!(secs_to_clock(59), (0, 0, 59));
105///
106/// // 1 minute.
107/// assert_eq!(secs_to_clock(60), (0, 1, 0));
108///
109/// // 59 minutes, 59 seconds.
110/// assert_eq!(secs_to_clock(3599), (0, 59, 59));
111///
112/// // 1 hour.
113/// assert_eq!(secs_to_clock(3600), (1, 0, 0));
114///
115/// // 23 hours, 59 minutes, 59 seconds.
116/// assert_eq!(secs_to_clock(86399), (23, 59, 59));
117///
118/// // 24 hours (wraps back)
119/// assert_eq!(secs_to_clock(86400), (0, 0, 0));
120///
121/// // 24 hours, 59 minutes, 59 seconds (wraps back)
122/// assert_eq!(secs_to_clock(89999), (0, 59, 59));
123/// ```
124pub const fn secs_to_clock(seconds: u32) -> (u8, u8, u8) {
125    let seconds = seconds % 86400;
126    let (h, m, s) = secs_to_hms(seconds as u64);
127
128    debug_assert!(h < 24);
129    debug_assert!(m < 60);
130    debug_assert!(s < 60);
131
132    #[expect(clippy::cast_possible_truncation, reason = "checked above")]
133    (h as u8, m, s)
134}
135
136#[inline]
137/// Get the current system time in the system's timezone
138///
139/// The returned value is the total amount of seconds passed in the current day.
140///
141/// This is guaranteed to return a value between `0..=86399`
142///
143/// This will return `0` if the underlying system call fails.
144pub fn time() -> u32 {
145    use chrono::Timelike;
146    let now = chrono::offset::Local::now().time();
147    (now.hour() * 3600) + (now.minute() * 60) + now.second()
148}
149
150#[inline]
151/// Get the current system time in the UTC timezone
152///
153/// The returned value is the total amount of seconds passed in the current day.
154///
155/// This is guaranteed to return a value between `0..=86399`
156pub fn time_utc() -> u32 {
157    #[expect(clippy::cast_sign_loss, reason = "checked in function calls")]
158    unix_clock(chrono::offset::Local::now().timestamp() as u64)
159}
160
161//---------------------------------------------------------------------------------------------------- Tests
162#[cfg(test)]
163mod test {}