Skip to main content

system_time/
fn.rs

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