iceyee_datetime/
lib.rs

1// **************************************************
2// *  Author: Iceyee                                *
3// *  Mail: iceyee.studio@qq.com                    *
4// *  Git: https://github.com/iceyee                *
5// **************************************************
6//
7// Use.
8
9use tokio::time::Sleep;
10
11/// 当前系统正在使用的时区所对应的时间偏移.
12/// 比如用+0800表示东八区的时间偏移, 即+08:00.
13pub static mut TIME_OFFSET: Option<i16> = None;
14
15const ONE_MILLISECOND: i64 = 1;
16const ONE_SECOND: i64 = 1000 * ONE_MILLISECOND;
17const ONE_MINUTE: i64 = 60 * ONE_SECOND;
18const ONE_HOUR: i64 = 60 * ONE_MINUTE;
19const ONE_DAY: i64 = 24 * ONE_HOUR;
20const ONE_WEEK: i64 = 7 * ONE_DAY;
21// const ONE_MONTH: i64 = 31 * ONE_DAY;
22const ONE_YEAR: i64 = 365 * ONE_DAY;
23const FOUR_YEAR: i64 = 4 * ONE_YEAR + ONE_DAY;
24const ONE_HUNDRED_YEAR: i64 = 25 * FOUR_YEAR - ONE_DAY;
25const FOUR_HUNDRED_YEAR: i64 = 4 * ONE_HUNDRED_YEAR + ONE_DAY;
26const TIME_0: i64 =
27    4 * FOUR_HUNDRED_YEAR + 3 * ONE_HUNDRED_YEAR + ONE_DAY + 17 * FOUR_YEAR + 2 * ONE_YEAR;
28
29// Enum.
30
31// Trait.
32
33// Struct.
34
35#[derive(Debug, Clone, PartialEq)]
36pub struct DateTime {
37    /// \[0, +oo)
38    pub year: usize,
39    /// \[1, 12\]
40    pub month: usize,
41    /// \[1, 31\]
42    pub day: usize,
43    /// \[0, 23\]
44    pub hour: usize,
45    /// \[0, 59\]
46    pub minute: usize,
47    /// \[0, 59\]
48    pub second: usize,
49    /// \[0, 999\]
50    pub millisecond: usize,
51    /// \[1, 365\]
52    pub day_of_year: usize,
53    /// \[1, 7\]
54    pub weekday: usize,
55    /// 时间戳, 单位:毫秒.
56    pub timestamp: i64,
57    /// 时间偏移, 比如用+0800表示东八区的时间偏移, 即+08:00.
58    pub offset: i16,
59}
60
61impl DateTime {
62    /// 返回当前时间, 等同于:
63    ///
64    /// ```
65    /// DateTime::from((DateTime::now(), None));
66    /// ```
67    pub fn new() -> Self {
68        return Self::from((Self::now(), None));
69    }
70
71    /// 返回当前系统的时间戳, 单位:毫秒.
72    pub fn now() -> i64 {
73        #[cfg(target_os = "linux")]
74        unsafe {
75            // struct timeval {
76            //     time_t      tv_sec;     /* seconds */
77            //     suseconds_t tv_usec;    /* microseconds */
78            // };
79            // struct timezone {
80            //     int tz_minuteswest;     /* minutes west of Greenwich */
81            //     int tz_dsttime;         /* type of DST correction */
82            // };
83            // int gettimeofday(struct timeval *tv, struct timezone *tz);
84            use std::ffi::c_int;
85            use std::ffi::c_long;
86            #[derive(Debug, Clone, Default, PartialEq)]
87            #[repr(C)]
88            pub struct TimeValue {
89                pub tv_sec: c_long,
90                pub tv_usec: c_long,
91            }
92            #[derive(Debug, Clone, Default, PartialEq)]
93            #[repr(C)]
94            pub struct TimeZone {
95                pub tz_minuteswest: c_int,
96                pub tz_dsttime: c_int,
97            }
98            extern "C" {
99                fn gettimeofday(tv: *mut TimeValue, tz: *mut TimeZone) -> c_int;
100            }
101            let mut tv: TimeValue = Default::default();
102            let mut tz: TimeZone = Default::default();
103            if gettimeofday(&mut tv, &mut tz) != 0 {
104                return 0;
105            }
106            return tv.tv_sec as i64 * 1000 + tv.tv_usec as i64 / 1000;
107        }
108        #[cfg(target_os = "windows")]
109        unsafe {
110            // typedef struct _SYSTEMTIME {
111            //     WORD wYear;
112            //     WORD wMonth;
113            //     WORD wDayOfWeek;
114            //     WORD wDay;
115            //     WORD wHour;
116            //     WORD wMinute;
117            //     WORD wSecond;
118            //     WORD wMilliseconds;
119            // } SYSTEMTIME, *PSYSTEMTIME, *LPSYSTEMTIME;
120            // void GetLocalTime(
121            //         [out] LPSYSTEMTIME lpSystemTime
122            //         );
123            // time_t time(time_t *);
124            use std::ffi::c_long;
125            use std::ffi::c_short;
126            #[allow(non_snake_case)]
127            #[derive(Debug, Clone, Default)]
128            #[repr(C)]
129            struct SYSTEMTIME {
130                wYear: c_short,
131                wMonth: c_short,
132                wDayOfWeek: c_short,
133                wDay: c_short,
134                wHour: c_short,
135                wMinute: c_short,
136                wSecond: c_short,
137                wMilliseconds: c_short,
138            }
139            extern "C" {
140                fn GetLocalTime(lpSystemTime: *mut SYSTEMTIME);
141                fn time(t: *mut c_long) -> c_long;
142            }
143            let mut st: SYSTEMTIME = Default::default();
144            GetLocalTime(&mut st);
145            let mut t: c_long = 0;
146            time(&mut t);
147            return t as i64 * 1000 + st.wMilliseconds as i64;
148        }
149    }
150
151    /// 转成国际标准时间.
152    pub fn to_utc(&self) -> Self {
153        return Self::from((self.timestamp, Some(0)));
154    }
155}
156
157impl From<(i64, Option<i16>)> for DateTime {
158    /// 从时间戳转成[DateTime].
159    ///
160    /// - @param value (timestamp, offset)
161    /// - @param value$0 时间戳, 单位:毫秒.
162    /// - @param value$1 时间偏移, 默认是系统设置的时区所对应的偏移.
163    fn from(value: (i64, Option<i16>)) -> Self {
164        let (timestamp_, offset) = value;
165        let offset: i16 = match offset {
166            Some(offset) => offset,
167            None => unsafe { *TIME_OFFSET.as_ref().unwrap() },
168        };
169        let offset_hour: i16 = offset / 100 % 100;
170        let offset_minute: i16 = offset % 100;
171        let mut timestamp: i64 = TIME_0
172            + offset_hour as i64 * 60 * 60 * 1000
173            + offset_minute as i64 * 60 * 1000
174            + timestamp_;
175        // 年.
176        let mut year: i64 = 0;
177        year += timestamp / FOUR_HUNDRED_YEAR * 400;
178        timestamp %= FOUR_HUNDRED_YEAR;
179        if ONE_HUNDRED_YEAR + ONE_DAY <= timestamp {
180            timestamp -= ONE_HUNDRED_YEAR;
181            timestamp -= ONE_DAY;
182            year += 100;
183            if ONE_HUNDRED_YEAR <= timestamp {
184                timestamp -= ONE_HUNDRED_YEAR;
185                year += 100;
186            }
187            if ONE_HUNDRED_YEAR <= timestamp {
188                timestamp -= ONE_HUNDRED_YEAR;
189                year += 100;
190            }
191        }
192        if year % 400 != 0 && 4 * ONE_YEAR <= timestamp {
193            timestamp -= 4 * ONE_YEAR;
194            year += 4;
195        }
196        year += timestamp / FOUR_YEAR * 4;
197        timestamp %= FOUR_YEAR;
198        if ONE_YEAR + ONE_DAY <= timestamp {
199            timestamp -= ONE_YEAR;
200            timestamp -= ONE_DAY;
201            year += 1;
202            if ONE_YEAR <= timestamp {
203                timestamp -= ONE_YEAR;
204                year += 1;
205            }
206            if ONE_YEAR <= timestamp {
207                timestamp -= ONE_YEAR;
208                year += 1;
209            }
210        }
211        // println!("@year={:?}", year);
212        let day_of_year: i64 = timestamp / ONE_DAY + 1;
213        // println!("@day_of_year={:?}", day_of_year);
214        // 月.
215        let mut month: i64 = 0;
216        for x in 1..=12 {
217            let max_days: i64 = match x {
218                1 | 3 | 5 | 7 | 8 | 10 | 12 => 31,
219                2 => {
220                    if year % 400 == 0 || year % 100 != 0 && year % 4 == 0 {
221                        29
222                    } else {
223                        28
224                    }
225                }
226                _ => 30,
227            };
228            if max_days * ONE_DAY <= timestamp {
229                timestamp -= max_days * ONE_DAY;
230                continue;
231            } else {
232                month = x;
233                break;
234            }
235        }
236        // println!("@month={:?}", month);
237        // 日.
238        let day: i64 = 1 + timestamp / ONE_DAY;
239        timestamp %= ONE_DAY;
240        // println!("@day={:?}", day);
241        // 时分秒.
242        let hour: i64 = timestamp / ONE_HOUR;
243        timestamp %= ONE_HOUR;
244        let minute: i64 = timestamp / ONE_MINUTE;
245        timestamp %= ONE_MINUTE;
246        let second: i64 = timestamp / ONE_SECOND;
247        timestamp %= ONE_SECOND;
248        let millisecond: i64 = timestamp / ONE_MILLISECOND;
249        // println!(
250        //     "@hour,minute,second={:02}:{:02}:{:02}",
251        //     hour, minute, second
252        // );
253        // 周几.
254        let mut weekday: i64 = (TIME_0
255            + offset_hour as i64 * 60 * 60 * 1000
256            + offset_minute as i64 * 60 * 1000
257            + timestamp_)
258            % ONE_WEEK
259            / ONE_DAY
260            + 1
261            + 5;
262        if 7 < weekday {
263            weekday -= 7;
264        }
265        // println!("@week={:?}", weekday);
266        return Self {
267            year: year as usize,
268            month: month as usize,
269            day: day as usize,
270            hour: hour as usize,
271            minute: minute as usize,
272            second: second as usize,
273            millisecond: millisecond as usize,
274            day_of_year: day_of_year as usize,
275            weekday: weekday as usize,
276            timestamp: timestamp_,
277            offset: offset,
278        };
279    }
280}
281
282impl From<(usize, usize, usize, usize, usize, usize, usize, Option<i16>)> for DateTime {
283    /// 从设置好的时间, 转成[DateTime].
284    ///
285    /// - @param value (year, month, day, hour, minute, second, millisecond, offset)
286    /// - @param value$0 年.
287    /// - @param value$1 月.
288    /// - @param value$2 日.
289    /// - @param value$3 时.
290    /// - @param value$4 分.
291    /// - @param value$5 秒.
292    /// - @param value$6 毫秒.
293    /// - @param value$7 时间偏移, 默认是系统设置的时区所对应的偏移.
294    ///
295    /// # Panics
296    ///
297    /// 如果参数不符合特定的数值范围就会panic.
298    ///
299    /// 例如, '时'的范围是0~23, 如果对应的入参是24, 就会panic.
300    ///
301    /// 例如, 某一年的二月份, 只有28天, 但是参数'日'的入参是29, 就会panic.
302    fn from(value: (usize, usize, usize, usize, usize, usize, usize, Option<i16>)) -> Self {
303        let (year, month, day, hour, minute, second, millisecond, offset) = value;
304        if month == 0 || 12 < month {
305            panic!("@month={:?}", month);
306        }
307        let max_days: usize = match month {
308            1 | 3 | 5 | 7 | 8 | 10 | 12 => 31,
309            2 => {
310                if year % 400 == 0 || year % 100 != 0 && year % 4 == 0 {
311                    29
312                } else {
313                    28
314                }
315            }
316            _ => 30,
317        };
318        if day == 0 || max_days < day {
319            panic!("@day={:?}", day);
320        }
321        if 23 < hour {
322            panic!("@hour={:?}", hour);
323        }
324        if 59 < minute {
325            panic!("@minute={:?}", minute);
326        }
327        if 59 < second {
328            panic!("@second={:?}", second);
329        }
330        if 999 < millisecond {
331            panic!("@millisecond={:?}", millisecond);
332        }
333        let mut timestamp: i64 = 0;
334        let mut t: i64 = year as i64;
335        // 年.
336        timestamp += t * ONE_YEAR;
337        timestamp += t / 400 * 97 * ONE_DAY;
338        t %= 400;
339        if t != 0 {
340            timestamp += (t / 100 * 24 + 1) * ONE_DAY;
341            t %= 100;
342        }
343        if t != 0 {
344            timestamp -= ONE_DAY;
345            if t % 4 != 0 {
346                timestamp += ONE_DAY;
347            }
348            timestamp += (t / 4) * ONE_DAY;
349            t %= 4;
350        }
351        let _ = t;
352        // 月.
353        t = 0;
354        for x in 1..=12 {
355            if month <= x {
356                break;
357            }
358            let max_days: i64 = match x {
359                1 | 3 | 5 | 7 | 8 | 10 | 12 => 31,
360                2 => {
361                    if year % 400 == 0 || year % 100 != 0 && year % 4 == 0 {
362                        29
363                    } else {
364                        28
365                    }
366                }
367                _ => 30,
368            };
369            timestamp += max_days * ONE_DAY;
370            t += max_days;
371        }
372        // let day_of_year: i64 = t + day as i64;
373        // 日.
374        timestamp += (day as i64 - 1) * ONE_DAY;
375        // 时分秒.
376        timestamp += hour as i64 * ONE_HOUR;
377        timestamp += minute as i64 * ONE_MINUTE;
378        timestamp += second as i64 * ONE_SECOND;
379        timestamp += millisecond as i64 * ONE_MILLISECOND;
380        // println!("@timestamp={:?}", timestamp);
381        // 时间差.
382        let offset: i16 = match offset {
383            Some(offset) => offset,
384            None => unsafe { *TIME_OFFSET.as_ref().unwrap() },
385        };
386        let offset_hour: i16 = offset / 100 % 100;
387        let offset_minute: i16 = offset % 100;
388        timestamp -= TIME_0;
389        timestamp -= offset_hour as i64 * 60 * 60 * 1000;
390        timestamp -= offset_minute as i64 * 60 * 1000;
391        return Self::from((timestamp, Some(offset)));
392        // // println!("@timestamp={:?}", timestamp);
393        // // 周几.
394        // let mut weekday: i64 = timestamp % ONE_WEEK / ONE_DAY + 1 + 3;
395        // if 7 < weekday {
396        //     weekday -= 7;
397        // }
398        // return Self {
399        //     year: year as usize,
400        //     month: month as usize,
401        //     day: day as usize,
402        //     hour: hour as usize,
403        //     minute: minute as usize,
404        //     second: second as usize,
405        //     day_of_year: day_of_year as usize,
406        //     weekday: weekday as usize,
407        //     timestamp: timestamp,
408        //     offset: offset,
409        // };
410    }
411}
412
413impl ToString for DateTime {
414    /// 转成字符串, 使用RFC3339标准, 格式'xx-xx-xxTxx:xx:xx.xxx\[+/-\]xx:xx'.
415    fn to_string(&self) -> String {
416        let v1: String = format!(
417            "{}-{:02}-{:02}T{:02}:{:02}:{:02}.{}",
418            self.year,
419            self.month,
420            self.day,
421            self.hour,
422            self.minute,
423            self.second,
424            self.timestamp % 1000
425        );
426        let v2: &str = if self.offset == 0 {
427            ""
428        } else if self.offset < 0 {
429            "-"
430        } else {
431            "+"
432        };
433        let offset: i16 = if self.offset < 0 {
434            -self.offset
435        } else {
436            self.offset
437        };
438        let v3: String = if offset == 0 {
439            "Z".to_string()
440        } else {
441            format!("{:02}:{:02}", offset / 100 % 100, offset % 100)
442        };
443        let result: String = v1 + v2 + &v3;
444        let result: String = format!("{result:29}");
445        return result;
446    }
447}
448
449// Function.
450
451#[ctor::ctor]
452fn init() {
453    #[cfg(target_os = "linux")]
454    unsafe {
455        // extern long timezone;
456        // void tzset ();
457        use std::ffi::c_long;
458        extern "C" {
459            static mut timezone: c_long;
460            fn tzset();
461        }
462        tzset();
463        let offset_hour: i16 = timezone as i16 / 60 / 60;
464        let offset_minute: i16 = timezone as i16 / 60 % 60;
465        TIME_OFFSET = Some(-(offset_hour * 100 + offset_minute));
466    }
467    #[cfg(target_os = "windows")]
468    unsafe {
469        // typedef struct _SYSTEMTIME {
470        //     WORD wYear;
471        //     WORD wMonth;
472        //     WORD wDayOfWeek;
473        //     WORD wDay;
474        //     WORD wHour;
475        //     WORD wMinute;
476        //     WORD wSecond;
477        //     WORD wMilliseconds;
478        // } SYSTEMTIME, *PSYSTEMTIME, *LPSYSTEMTIME;
479        // typedef struct _TIME_ZONE_INFORMATION {
480        //     LONG       Bias;
481        //     WCHAR      StandardName[32];
482        //     SYSTEMTIME StandardDate;
483        //     LONG       StandardBias;
484        //     WCHAR      DaylightName[32];
485        //     SYSTEMTIME DaylightDate;
486        //     LONG       DaylightBias;
487        // } TIME_ZONE_INFORMATION, *PTIME_ZONE_INFORMATION, *LPTIME_ZONE_INFORMATION;
488        // DWORD GetTimeZoneInformation(
489        //         [out] LPTIME_ZONE_INFORMATION lpTimeZoneInformation
490        //         );
491        use std::ffi::c_int;
492        use std::ffi::c_long;
493        use std::ffi::c_ushort;
494        #[allow(non_snake_case)]
495        #[derive(Debug, Clone, Default)]
496        #[repr(C)]
497        struct SYSTEMTIME {
498            wYear: c_ushort,
499            wMonth: c_ushort,
500            wDayOfWeek: c_ushort,
501            wDay: c_ushort,
502            wHour: c_ushort,
503            wMinute: c_ushort,
504            wSecond: c_ushort,
505            wMilliseconds: c_ushort,
506        }
507        #[allow(non_camel_case_types)]
508        #[allow(non_snake_case)]
509        #[derive(Debug, Clone, Default)]
510        #[repr(C)]
511        struct TIME_ZONE_INFORMATION {
512            Bias: c_long,
513            StandardName: [c_ushort; 32],
514            StandardDate: SYSTEMTIME,
515            StandardBias: c_long,
516            DaylightName: [c_ushort; 32],
517            DaylightDate: SYSTEMTIME,
518            DaylightBias: c_long,
519        }
520        extern "C" {
521            fn GetTimeZoneInformation(lpTimeZoneInformation: *mut TIME_ZONE_INFORMATION) -> c_int;
522        }
523        let mut tzi: TIME_ZONE_INFORMATION = Default::default();
524        GetTimeZoneInformation(&mut tzi);
525        let offset_hour: i16 = tzi.Bias as i16 / 60;
526        let offset_minute: i16 = tzi.Bias as i16 % 60;
527        TIME_OFFSET = Some(-(offset_hour * 100 + offset_minute));
528    }
529    return;
530}
531
532/// 延时, 单位:毫秒.
533pub fn sleep(t: u64) -> Sleep {
534    use std::time::Duration;
535
536    return tokio::time::sleep(Duration::from_millis(t));
537}