hyperlane_time/time/
time.rs

1use super::r#type::from_env_var;
2use std::fmt::Write;
3use std::time::{Duration, SystemTime, UNIX_EPOCH};
4
5/// Leap Year
6pub static LEAP_YEAR: [u64; 12] = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
7/// Common Year
8pub static COMMON_YEAR: [u64; 12] = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
9/// Days
10pub static DAYS: [&str; 7] = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
11/// Months
12pub static 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
23#[inline]
24fn is_leap_year(year: u64) -> bool {
25    (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)
26}
27
28/// Calculates the current year, month, day, and the number of seconds remaining in the day.
29///
30/// # Returns
31/// A tuple containing:
32/// - `year`: The current year
33/// - `month`: The current month
34/// - `day`: The current day
35/// - `remaining_seconds`: The number of seconds passed today
36#[inline]
37fn calculate_current_date() -> (u64, u64, u64, u64) {
38    // Get the current time
39    let start: SystemTime = SystemTime::now();
40    let duration: Duration = start.duration_since(UNIX_EPOCH).unwrap();
41    let total_seconds: u64 = duration.as_secs();
42    let mut total_days: u64 = total_seconds / 86400;
43    let mut year: u64 = 1970;
44    while total_days >= if is_leap_year(year) { 366 } else { 365 } {
45        total_days -= if is_leap_year(year) { 366 } else { 365 };
46        year += 1;
47    }
48    let mut month: u64 = 1;
49    let month_days: [u64; 12] = if is_leap_year(year) {
50        LEAP_YEAR
51    } else {
52        COMMON_YEAR
53    };
54    while total_days >= month_days[month as usize - 1] {
55        total_days -= month_days[month as usize - 1];
56        month += 1;
57    }
58    let day: u64 = total_days + 1;
59    let remaining_seconds: u64 = total_seconds % 86400;
60    (year, month, day, remaining_seconds)
61}
62
63/// Gets the current time, including the date and time.
64///
65/// # Returns
66/// `String`: The formatted time as "YYYY-MM-DD HH:MM:SS"
67#[inline]
68pub fn current_time() -> String {
69    let (year, month, day, remaining_seconds) = calculate_current_date();
70    let timezone_offset: u64 = from_env_var().value(); // Assuming from_env_var() is defined elsewhere
71    let hours: u64 = ((remaining_seconds + timezone_offset) / 3600) % 24;
72    let minutes: u64 = (remaining_seconds % 3600) / 60;
73    let seconds: u64 = remaining_seconds % 60;
74    let mut date_time: String = String::new();
75    write!(
76        &mut date_time,
77        "{:04}-{:02}-{:02} {:02}:{:02}:{:02}",
78        year, month, day, hours, minutes, seconds
79    )
80    .unwrap_or_default();
81    date_time
82}
83
84/// Gets the current day, without the time.
85///
86/// # Returns
87/// `String`: The formatted date as "YYYY-MM-DD"
88#[inline]
89pub fn current_date() -> String {
90    let (year, month, day, _) = calculate_current_date();
91    let mut date_time: String = String::new();
92    write!(&mut date_time, "{:04}-{:02}-{:02}", year, month, day).unwrap_or_default();
93    date_time
94}
95
96/// Computes the year, month, and day from days since Unix epoch (1970-01-01).
97///
98/// - `days_since_epoch`: Number of days since `1970-01-01`.
99/// - Returns: `(year, month, day)`
100fn compute_date(mut days_since_epoch: u64) -> (u64, u64, u64) {
101    let mut year: u64 = 1970;
102    loop {
103        let days_in_year = if is_leap_year(year) { 366 } else { 365 };
104        if days_since_epoch < days_in_year {
105            break;
106        }
107        days_since_epoch -= days_in_year as u64;
108        year += 1;
109    }
110    let mut month: u64 = 0;
111    for (i, &days) in COMMON_YEAR.iter().enumerate() {
112        let days_in_month = if i == 1 && is_leap_year(year) {
113            days + 1
114        } else {
115            days
116        };
117        if days_since_epoch < days_in_month as u64 {
118            month = i as u64 + 1;
119            return (year, month, (days_since_epoch + 1) as u64);
120        }
121        days_since_epoch -= days_in_month as u64;
122    }
123
124    (year, month, 1)
125}
126
127#[inline]
128pub fn current_date_gmt() -> String {
129    let now: SystemTime = SystemTime::now();
130    let duration_since_epoch: Duration = now.duration_since(UNIX_EPOCH).unwrap();
131    let timestamp: u64 = duration_since_epoch.as_secs();
132    let seconds_in_day: u64 = 86_400;
133    let days_since_epoch: u64 = timestamp / seconds_in_day;
134    let seconds_of_day: u64 = timestamp % seconds_in_day;
135    let hours: u64 = (seconds_of_day / 3600) as u64;
136    let minutes: u64 = ((seconds_of_day % 3600) / 60) as u64;
137    let seconds: u64 = (seconds_of_day % 60) as u64;
138    let (year, month, day) = compute_date(days_since_epoch);
139    let weekday: usize = ((days_since_epoch + 4) % 7) as usize;
140    format!(
141        "{}, {:02} {} {} {:02}:{:02}:{:02} GMT",
142        DAYS[weekday],
143        day,
144        MONTHS[month as usize - 1],
145        year,
146        hours,
147        minutes,
148        seconds
149    )
150}