cuprate_helper/
time.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
//! System related
//!
//! Requires `std`.

//---------------------------------------------------------------------------------------------------- Use
use std::time::{SystemTime, UNIX_EPOCH};

//---------------------------------------------------------------------------------------------------- Public API
#[inline]
/// Returns the current system time as a UNIX timestamp.
///
/// ```rust
/// # use cuprate_helper::time::*;
/// assert!(current_unix_timestamp() > 0);
/// ```
///
/// # Panics
/// This function panics if the call to get the system time fails.
pub fn current_unix_timestamp() -> u64 {
    SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .unwrap()
        .as_secs()
}

#[inline]
/// Get the clock time of a UNIX timestamp
///
/// The input must be a UNIX timestamp.
///
/// The returned `u64` will represent how many seconds has
/// passed on the day corresponding to that timestamp.
///
/// The output is guaranteed to be in the range of `0..=86399`.
///
/// ```rust
/// # use cuprate_helper::time::*;
/// // October 20th 2023 - 10:18:30 PM
/// const TIME: u64 = 1697840310;
///
/// let seconds = unix_clock(TIME);
/// assert_eq!(seconds, 80310);
///
/// let (h, m, s) = secs_to_clock(seconds);
/// // 10:18:30 PM.
/// assert_eq!((h, m, s), (22, 18, 30))
/// ```
pub const fn unix_clock(seconds_after_unix_epoch: u64) -> u32 {
    (seconds_after_unix_epoch % 86400) as _
}

#[inline]
/// Convert seconds to `hours`, `minutes` and `seconds`.
///
/// - The seconds returned is guaranteed to be `0..=59`
/// - The minutes returned is guaranteed to be `0..=59`
/// - The hours returned can be over `23`, as this is not a clock function,
///   see [`secs_to_clock`] for clock-like behavior that wraps around on `24`
///
/// ```rust
/// # use cuprate_helper::time::*;
/// // 59 seconds.
/// assert_eq!(secs_to_hms(59), (0, 0, 59));
///
/// // 1 minute.
/// assert_eq!(secs_to_hms(60), (0, 1, 0));
///
/// // 59 minutes, 59 seconds.
/// assert_eq!(secs_to_hms(3599), (0, 59, 59));
///
/// // 1 hour.
/// assert_eq!(secs_to_hms(3600), (1, 0, 0));
///
/// // 23 hours, 59 minutes, 59 seconds.
/// assert_eq!(secs_to_hms(86399), (23, 59, 59));
///
/// // 24 hours.
/// assert_eq!(secs_to_hms(86400), (24, 0, 0));
/// ```
pub const fn secs_to_hms(seconds: u64) -> (u64, u8, u8) {
    let hours = seconds / 3600;
    let minutes = (seconds % 3600) / 60;
    let seconds = (seconds % 3600) % 60;

    debug_assert!(minutes < 60);
    debug_assert!(seconds < 60);

    (hours, minutes as u8, seconds as u8)
}

#[inline]
/// Convert seconds to clock time, `hours`, `minutes` and `seconds`.
///
/// This is the same as [`secs_to_hms`] except it will wrap around,
/// e.g, `24:00:00` would turn into `00:00:00`.
///
/// - The seconds returned is guaranteed to be `0..=59`
/// - The minutes returned is guaranteed to be `0..=59`
/// - The hours returned is guaranteed to be `0..=23`
///
/// ```rust
/// # use cuprate_helper::time::*;
/// // 59 seconds.
/// assert_eq!(secs_to_clock(59), (0, 0, 59));
///
/// // 1 minute.
/// assert_eq!(secs_to_clock(60), (0, 1, 0));
///
/// // 59 minutes, 59 seconds.
/// assert_eq!(secs_to_clock(3599), (0, 59, 59));
///
/// // 1 hour.
/// assert_eq!(secs_to_clock(3600), (1, 0, 0));
///
/// // 23 hours, 59 minutes, 59 seconds.
/// assert_eq!(secs_to_clock(86399), (23, 59, 59));
///
/// // 24 hours (wraps back)
/// assert_eq!(secs_to_clock(86400), (0, 0, 0));
///
/// // 24 hours, 59 minutes, 59 seconds (wraps back)
/// assert_eq!(secs_to_clock(89999), (0, 59, 59));
/// ```
pub const fn secs_to_clock(seconds: u32) -> (u8, u8, u8) {
    let seconds = seconds % 86400;
    let (h, m, s) = secs_to_hms(seconds as u64);

    debug_assert!(h < 24);
    debug_assert!(m < 60);
    debug_assert!(s < 60);

    #[expect(clippy::cast_possible_truncation, reason = "checked above")]
    (h as u8, m, s)
}

#[inline]
/// Get the current system time in the system's timezone
///
/// The returned value is the total amount of seconds passed in the current day.
///
/// This is guaranteed to return a value between `0..=86399`
///
/// This will return `0` if the underlying system call fails.
pub fn time() -> u32 {
    use chrono::Timelike;
    let now = chrono::offset::Local::now().time();
    (now.hour() * 3600) + (now.minute() * 60) + now.second()
}

#[inline]
/// Get the current system time in the UTC timezone
///
/// The returned value is the total amount of seconds passed in the current day.
///
/// This is guaranteed to return a value between `0..=86399`
pub fn time_utc() -> u32 {
    #[expect(clippy::cast_sign_loss, reason = "checked in function calls")]
    unix_clock(chrono::offset::Local::now().timestamp() as u64)
}

//---------------------------------------------------------------------------------------------------- Tests
#[cfg(test)]
mod test {}