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