hyperlane_time/time/
fn.rs

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