hyperlane_time/time/
fn.rs

1use super::r#enum::from_env_var;
2use std::fmt::Write;
3use std::time::{Duration, SystemTime, UNIX_EPOCH};
4
5/// Leap Year
6pub const LEAP_YEAR: [u64; 12] = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
7/// Common Year
8pub const COMMON_YEAR: [u64; 12] = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
9/// Days
10pub const DAYS: [&str; 7] = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
11/// Months
12pub const MONTHS: [&str; 12] = [
13    "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
14];
15
16/// Determines if a year is a leap year.
17///
18/// # Parameters
19/// `u64`: The year
20///
21/// # Returns
22/// `bool`: Whether it is a leap year
23pub fn is_leap_year(year: u64) -> bool {
24    (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)
25}
26
27/// Gets the current time, including the date and time.
28///
29/// # Returns
30/// `String`: The formatted time as "YYYY-MM-DD HH:MM:SS"
31pub fn time() -> String {
32    let (year, month, day, hour, minute, second, _, _) = calculate_time();
33    let mut date_time: String = String::new();
34    write!(
35        &mut date_time,
36        "{:04}-{:02}-{:02} {:02}:{:02}:{:02}",
37        year, month, day, hour, minute, second
38    )
39    .unwrap_or_default();
40    date_time
41}
42
43/// Gets the current day, without the time.
44///
45/// # Returns
46/// `String`: The formatted date as "YYYY-MM-DD"
47pub fn date() -> String {
48    let (year, month, day, _, _, _, _, _) = calculate_time();
49    let mut date_time: String = String::new();
50    write!(&mut date_time, "{:04}-{:02}-{:02}", year, month, day).unwrap_or_default();
51    date_time
52}
53
54/// Computes the year, month, and day from days since Unix epoch (1970-01-01).
55///
56/// - `days_since_epoch`: Number of days since `1970-01-01`.
57/// - Returns: `(year, month, day)`
58pub fn compute_date(mut days_since_epoch: u64) -> (u64, u64, u64) {
59    let mut year: u64 = 1970;
60    loop {
61        let days_in_year: u64 = if is_leap_year(year) { 366 } else { 365 };
62        if days_since_epoch < days_in_year {
63            break;
64        }
65        days_since_epoch -= days_in_year as u64;
66        year += 1;
67    }
68    let mut month: u64 = 0;
69    for (i, &days) in COMMON_YEAR.iter().enumerate() {
70        let days_in_month = if i == 1 && is_leap_year(year) {
71            days + 1
72        } else {
73            days
74        };
75        if days_since_epoch < days_in_month as u64 {
76            month = i as u64 + 1;
77            return (year, month, (days_since_epoch + 1) as u64);
78        }
79        days_since_epoch -= days_in_month as u64;
80    }
81
82    (year, month, 1)
83}
84
85/// Gets the current date and time in GMT format.
86///
87/// # Returns
88/// `String`: The current date and time in GMT format.
89pub fn gmt() -> String {
90    let now: SystemTime = SystemTime::now();
91    let duration_since_epoch: Duration = now.duration_since(UNIX_EPOCH).unwrap();
92    let timestamp: u64 = duration_since_epoch.as_secs();
93    let seconds_in_day: u64 = 86_400;
94    let days_since_epoch: u64 = timestamp / seconds_in_day;
95    let seconds_of_day: u64 = timestamp % seconds_in_day;
96    let hours: u64 = (seconds_of_day / 3600) as u64;
97    let minutes: u64 = ((seconds_of_day % 3600) / 60) as u64;
98    let seconds: u64 = (seconds_of_day % 60) as u64;
99    let (year, month, day) = compute_date(days_since_epoch);
100    let weekday: usize = ((days_since_epoch + 4) % 7) as usize;
101    format!(
102        "{}, {:02} {} {} {:02}:{:02}:{:02} GMT",
103        DAYS[weekday],
104        day,
105        MONTHS[month as usize - 1],
106        year,
107        hours,
108        minutes,
109        seconds
110    )
111}
112
113/// Gets the current year.
114///
115/// # Returns
116/// `u64`: The current year
117pub fn year() -> u64 {
118    calculate_time().0
119}
120
121/// Gets the current month.
122///
123/// # Returns
124/// `u64`: The current month (1-12)
125pub fn month() -> u64 {
126    calculate_time().1
127}
128
129/// Gets the current day.
130///
131/// # Returns
132/// `u64`: The current day of the month
133pub fn day() -> u64 {
134    calculate_time().2
135}
136
137/// Gets the current hour.
138///
139/// # Returns
140/// `u64`: The current hour (0-23)
141pub fn hour() -> u64 {
142    calculate_time().3
143}
144
145/// Gets the current minute.
146///
147/// # Returns
148/// `u64`: The current minute (0-59)
149pub fn minute() -> u64 {
150    calculate_time().4
151}
152
153/// Gets the current second.
154///
155/// # Returns
156/// `u64`: The current second (0-59)
157pub fn second() -> u64 {
158    calculate_time().5
159}
160
161/// Gets the current timestamp in milliseconds.
162///
163/// # Returns
164/// `u64`: The current timestamp in milliseconds since Unix epoch
165pub fn millis() -> u64 {
166    calculate_time().6
167}
168
169/// Gets the current timestamp in microseconds.
170///
171/// # Returns
172/// `u64`: The current timestamp in microseconds since Unix epoch
173pub fn micros() -> u64 {
174    calculate_time().7
175}
176
177/// Calculates the current year, month, day, hour, minute, second, millisecond and microsecond.
178///
179/// # Returns
180/// A tuple containing:
181/// - `year`: The current year
182/// - `month`: The current month
183/// - `day`: The current day
184/// - `hour`: The current hour (0-23)
185/// - `minute`: The current minute (0-59)
186/// - `second`: The current second (0-59)
187/// - `millisecond`: The number of milliseconds passed in the current second
188/// - `microsecond`: The number of microseconds passed in the current second
189pub fn calculate_time() -> (u64, u64, u64, u64, u64, u64, u64, u64) {
190    let start: SystemTime = SystemTime::now();
191    let duration: Duration = start.duration_since(UNIX_EPOCH).unwrap();
192    let total_seconds: u64 = duration.as_secs();
193    let nanoseconds: u64 = duration.subsec_nanos() as u64;
194    let milliseconds: u64 = nanoseconds / 1_000_000;
195    let microseconds: u64 = nanoseconds / 1_000;
196    let mut total_days: u64 = total_seconds / 86400;
197    let mut year: u64 = 1970;
198    while total_days >= if is_leap_year(year) { 366 } else { 365 } {
199        total_days -= if is_leap_year(year) { 366 } else { 365 };
200        year += 1;
201    }
202    let mut month: u64 = 1;
203    let month_days: [u64; 12] = if is_leap_year(year) {
204        LEAP_YEAR
205    } else {
206        COMMON_YEAR
207    };
208    while total_days >= month_days[month as usize - 1] {
209        total_days -= month_days[month as usize - 1];
210        month += 1;
211    }
212    let day: u64 = total_days + 1;
213    let remaining_seconds: u64 = total_seconds % 86400;
214    let timezone_offset: u64 = from_env_var().value();
215    let hour: u64 = ((remaining_seconds + timezone_offset) / 3600) % 24;
216    let minute: u64 = (remaining_seconds % 3600) / 60;
217    let second: u64 = remaining_seconds % 60;
218    (
219        year,
220        month,
221        day,
222        hour,
223        minute,
224        second,
225        milliseconds,
226        microseconds,
227    )
228}
229
230/// Gets the current time with milliseconds, including the date and time.
231///
232/// # Returns
233/// `String`: The formatted time as "YYYY-MM-DD HH:MM:SS.sss"
234pub fn time_millis() -> String {
235    let (year, month, day, hour, minute, second, millisecond, _) = calculate_time();
236    let mut date_time: String = String::new();
237    write!(
238        &mut date_time,
239        "{:04}-{:02}-{:02} {:02}:{:02}:{:02}.{:03}",
240        year, month, day, hour, minute, second, millisecond
241    )
242    .unwrap_or_default();
243    date_time
244}
245
246/// Gets the current time with microseconds, including the date and time.
247///
248/// # Returns
249/// `String`: The formatted time as "YYYY-MM-DD HH:MM:SS.ssssss"
250pub fn time_micros() -> String {
251    let (year, month, day, hour, minute, second, _, microseconds) = calculate_time();
252    let mut date_time: String = String::new();
253    write!(
254        &mut date_time,
255        "{:04}-{:02}-{:02} {:02}:{:02}:{:02}.{:06}",
256        year, month, day, hour, minute, second, microseconds
257    )
258    .unwrap_or_default();
259    date_time
260}
261
262/// Gets the current timestamp in seconds since Unix epoch.
263///
264/// # Returns
265/// `u64`: The current timestamp in seconds
266pub fn timestamp() -> u64 {
267    let timezone_offset: u64 = from_env_var().value();
268    SystemTime::now()
269        .duration_since(UNIX_EPOCH)
270        .unwrap()
271        .as_secs()
272        .saturating_add(timezone_offset)
273}
274
275/// Gets the current timestamp in milliseconds since Unix epoch.
276///
277/// # Returns
278/// `u64`: The current timestamp in milliseconds
279pub fn timestamp_millis() -> u64 {
280    let timezone_offset: u64 = from_env_var().value();
281    let duration: Duration = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
282    (duration.as_secs().saturating_add(timezone_offset)) * 1000 + duration.subsec_millis() as u64
283}
284
285/// Gets the current timestamp in microseconds since Unix epoch.
286///
287/// # Returns
288/// `u64`: The current timestamp in microseconds
289pub fn timestamp_micros() -> u64 {
290    let timezone_offset: u64 = from_env_var().value();
291    let duration: Duration = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
292    (duration.as_secs().saturating_add(timezone_offset)) * 1_000_000
293        + duration.subsec_micros() as u64
294}