sys_time/
lib.rs

1#[derive(Debug, Default)]
2pub struct DateTime {
3    seconds: u8,
4    minutes: u8,
5    hours: u8,
6    day: u8,
7    weekday: u8,
8    month: u8,
9    year: u64,
10    timestamp: u64,
11}
12
13use std::time::SystemTime;
14
15impl DateTime {
16    /// Create a new `DateTime` with the current date and time in UTC.
17    ///
18    /// ```rust
19    /// # use sys_time::DateTime;
20    /// assert!(DateTime::now_utc().year() >= 2022);
21    /// ```
22    #[inline(always)]
23    pub fn now_utc() -> Self {
24        SystemTime::now().into()
25    }
26
27    #[inline(always)]
28    pub fn hour(&self) -> u8 {
29        self.hours
30    }
31
32    #[inline(always)]
33    pub fn minute(&self) -> u8 {
34        self.minutes
35    }
36
37    #[inline(always)]
38    pub fn second(&self) -> u8 {
39        self.seconds
40    }
41    #[inline(always)]
42    pub fn day(&self) -> u8 {
43        self.day
44    }
45
46    pub fn year(&self) -> u64 {
47        self.year
48    }
49
50    pub fn unix_timestamp(&self) -> u64 {
51        self.timestamp
52    }
53    pub fn unix_timestamp_millis(&self) -> u128 {
54        self.timestamp as u128 * 1000
55    }
56
57    pub fn unix_timestamp_nanos(&self) -> u128 {
58        self.timestamp as u128 * 1000000000
59    }
60
61    pub fn month(&self) -> Month {
62        match self.month {
63            1 => Month::January,
64            2 => Month::February,
65            3 => Month::March,
66            4 => Month::April,
67            5 => Month::May,
68            6 => Month::June,
69            7 => Month::July,
70            8 => Month::August,
71            9 => Month::September,
72            10 => Month::October,
73            11 => Month::November,
74            12 => Month::December,
75            _ => panic!("Month is not valid"),
76        }
77    }
78
79    #[inline(always)]
80    pub fn weekday(&self) -> Weekday {
81        match self.weekday {
82            0 => panic!("Week is not valid"),
83            1 => Weekday::Monday,
84            2 => Weekday::Tuesday,
85            3 => Weekday::Wednesday,
86            4 => Weekday::Thursday,
87            5 => Weekday::Friday,
88            6 => Weekday::Saturday,
89            7 => Weekday::Sunday,
90            _ => panic!("Week is not valid"),
91        }
92    }
93}
94
95#[derive(Debug, PartialEq)]
96pub enum Weekday {
97    Sunday = 1,
98    Monday,
99    Tuesday,
100    Wednesday,
101    Thursday,
102    Friday,
103    Saturday,
104}
105
106impl std::fmt::Display for Weekday {
107    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
108        match *self {
109            Weekday::Sunday => write!(f, "Sunday"),
110            Weekday::Monday => write!(f, "Monday"),
111            Weekday::Tuesday => write!(f, "Tuesday"),
112            Weekday::Wednesday => write!(f, "Wednesday"),
113            Weekday::Thursday => write!(f, "Thrusday"),
114            Weekday::Friday => write!(f, "Friday"),
115            Weekday::Saturday => write!(f, "Saturday"),
116        }
117    }
118}
119
120#[derive(Debug, PartialEq)]
121pub enum Month {
122    January = 1,
123    February,
124    March,
125    April,
126    May,
127    June,
128    July,
129    August,
130    September,
131    October,
132    November,
133    December,
134}
135
136impl std::fmt::Display for Month {
137    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
138        match *self {
139            Month::January => write!(f, "January"),
140            Month::February => write!(f, "February"),
141            Month::March => write!(f, "March"),
142            Month::April => write!(f, "April"),
143            Month::May => write!(f, "May"),
144            Month::June => write!(f, "June"),
145            Month::July => write!(f, "July"),
146            Month::August => write!(f, "August"),
147            Month::September => write!(f, "September"),
148            Month::October => write!(f, "October"),
149            Month::November => write!(f, "November"),
150            Month::December => write!(f, "December"),
151        }
152    }
153}
154
155impl From<SystemTime> for DateTime {
156    // There is definitely some way to have this conversion be infallible, but
157    // it won't be an issue for over 500 years.
158    #[inline(always)]
159    fn from(system_time: SystemTime) -> Self {
160        let mut datetime = DateTime::default();
161
162        let duration = match system_time.duration_since(SystemTime::UNIX_EPOCH) {
163            Ok(duration) => duration,
164            Err(err) => err.duration(),
165        };
166
167        datetime.timestamp = duration.as_secs();
168
169        //Retrieve hours, minutes and seconds
170        datetime.seconds = (datetime.timestamp % 60) as u8;
171        datetime.timestamp /= 60;
172        datetime.minutes = (datetime.timestamp % 60) as u8;
173        datetime.timestamp /= 60;
174        datetime.hours = (datetime.timestamp % 24) as u8;
175        datetime.timestamp /= 24;
176
177        //Convert Unix time to date
178        let a = (4 * datetime.timestamp + 102032) / 146097 + 15;
179        let b = datetime.timestamp + 2442113 + a - (a / 4);
180        let mut c = (20 * b - 2442) / 7305;
181        let d = (b - 365 * c - (c / 4)) as u16;
182        let mut e = (d as u32 * 1000 / 30601) as u8;
183        let f = (d - e as u16 * 30 - e as u16 * 601 / 1000) as u8;
184
185        //January and February are counted as months 13 and 14 of the previous year
186        if e <= 13 {
187            c -= 4716;
188            e -= 1;
189        } else {
190            c -= 4715;
191            e -= 13;
192        }
193
194        //Retrieve year, month and day
195        datetime.year = c;
196        datetime.month = e;
197        datetime.day = f;
198
199        datetime.weekday = compute_day_of_week(c, e, f);
200
201        datetime
202    }
203}
204
205fn compute_day_of_week(mut y: u64, mut m: u8, d: u8) -> u8 {
206    //January and February are counted as months 13 and 14 of the previous year
207    if m <= 2 {
208        m += 12;
209        y -= 1;
210    }
211
212    let j = y / 100;
213    //K the year of the century
214    let k = y % 100;
215
216    //Compute H using Zeller's congruence
217    let h: u64 = d as u64 + (26 * (m as u64 + 1) / 10) + k + (k / 4) + (5 * j) + (j / 4);
218
219    //Return the day of the week
220    (((h + 5) % 7) as u8) + 1
221}