1use crate::{
13 is_leap_year, Debug, Display, FmtResult, Formatter, Month, TimeSplit, TimeSplitYearSec,
14 TryFromIntError,
15};
16
17#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord)]
21pub struct UnixTimeI64 {
22 pub seconds: i64,
24}
25
26#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord)]
32pub struct UnixTimeU32 {
33 pub seconds: u32,
35}
36
37impl UnixTimeI64 {
38 pub fn new(seconds: i64) -> Self {
50 Self { seconds }
51 }
52
53 #[cfg(feature = "std")]
55 #[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "std")))]
57 pub fn now() -> Self {
59 Self { seconds: Self::unix_time_64() }
60 }
61
62 pub const fn split(&self) -> TimeSplitYearSec<i32, u8, u8, u8, u8, u8> {
73 let seconds_per_minute: u32 = 60;
74 let minutes_per_hour: u32 = 60;
75 let hours_per_day: u32 = 24;
76 let days_per_year: u32 = 365;
77
78 let mut seconds_left = self.seconds.abs();
79 let mut year = if self.seconds >= 0 { 1970 } else { 1969 };
80 let mut leap = is_leap_year(year);
81
82 while seconds_left
83 >= (hours_per_day * minutes_per_hour * seconds_per_minute * days_per_year) as i64
84 {
85 leap = is_leap_year(year);
86 let days_in_year = if leap { 366 } else { 365 };
87 seconds_left -=
88 (hours_per_day * minutes_per_hour * seconds_per_minute * days_in_year) as i64;
89
90 if self.seconds >= 0 {
91 year += 1;
92 } else {
93 year -= 1;
94 }
95 }
96
97 let mut month = Month::January;
98 while seconds_left
99 >= (hours_per_day * minutes_per_hour * seconds_per_minute * month.len(leap) as u32)
100 as i64
101 {
102 seconds_left -=
103 (hours_per_day * minutes_per_hour * seconds_per_minute * month.len(leap) as u32)
104 as i64;
105 month = month.next();
106 }
107
108 let day = (seconds_left / (hours_per_day * minutes_per_hour * seconds_per_minute) as i64)
109 as u8
110 + 1;
111 seconds_left %= (hours_per_day * minutes_per_hour * seconds_per_minute) as i64;
112
113 let hour = seconds_left / (minutes_per_hour * seconds_per_minute) as i64;
114 seconds_left %= (minutes_per_hour * seconds_per_minute) as i64;
115
116 let minute = seconds_left / seconds_per_minute as i64;
117 let second = seconds_left % seconds_per_minute as i64;
118
119 if self.seconds >= 0 {
120 TimeSplit::new_year_sec(
121 year,
122 month.number(),
123 day,
124 hour as u8,
125 minute as u8,
126 second as u8,
127 )
128 } else {
129 TimeSplit::new_year_sec(
130 year,
131 13 - month.number(),
132 Month::December.previous_nth(month.index()).len(leap) - day + 1,
133 23 - hour as u8,
134 59 - minute as u8,
135 60 - second as u8,
136 )
137 }
138 }
139}
140
141impl UnixTimeI64 {
143 #[cfg(feature = "std")]
145 fn unix_time_64() -> i64 {
146 use crate::SystemTime;
147 SystemTime::now()
148 .duration_since(SystemTime::UNIX_EPOCH)
149 .unwrap()
150 .as_secs()
151 .min(i64::MAX as u64) as i64
152 }
153
154 }
167
168impl UnixTimeU32 {
169 pub fn new(seconds: u32) -> Self {
178 Self { seconds }
179 }
180
181 #[cfg(feature = "std")]
183 #[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "std")))]
185 pub fn now() -> Self {
187 Self { seconds: Self::unix_time_32() }
188 }
189
190 pub const fn split(&self) -> TimeSplitYearSec<u16, u8, u8, u8, u8, u8> {
200 let seconds_per_minute: u32 = 60;
201 let minutes_per_hour: u32 = 60;
202 let hours_per_day: u32 = 24;
203 let days_per_year: u32 = 365;
204
205 let mut seconds_left = self.seconds;
206 let mut year = 1970;
207 let mut leap = is_leap_year(year);
208
209 while seconds_left
210 >= (hours_per_day * minutes_per_hour * seconds_per_minute * days_per_year)
211 {
212 year += 1;
213 leap = is_leap_year(year);
214 let days_in_year = if leap { 366 } else { 365 };
215 seconds_left -= hours_per_day * minutes_per_hour * seconds_per_minute * days_in_year;
216 }
217
218 let mut month = Month::January;
219 while seconds_left
220 >= hours_per_day * minutes_per_hour * seconds_per_minute * month.len(leap) as u32
221 {
222 seconds_left -=
223 hours_per_day * minutes_per_hour * seconds_per_minute * month.len(leap) as u32;
224 month = month.next();
225 }
226
227 let day = (seconds_left / (hours_per_day * minutes_per_hour * seconds_per_minute)) + 1;
228 seconds_left %= hours_per_day * minutes_per_hour * seconds_per_minute;
229
230 let hour = seconds_left / (minutes_per_hour * seconds_per_minute);
231 seconds_left %= minutes_per_hour * seconds_per_minute;
232
233 let minute = seconds_left / seconds_per_minute;
234 let second = seconds_left % seconds_per_minute;
235
236 TimeSplit::new_year_sec(
237 year as u16,
238 month.number(),
239 day as u8,
240 hour as u8,
241 minute as u8,
242 second as u8,
243 )
244 }
245}
246
247impl UnixTimeU32 {
249 #[cfg(feature = "std")]
253 fn unix_time_32() -> u32 {
254 use crate::SystemTime;
255 SystemTime::now()
256 .duration_since(SystemTime::UNIX_EPOCH)
257 .unwrap()
258 .as_secs()
259 .min(u32::MAX as u64) as u32
260 }
261
262 }
271
272impl Display for UnixTimeI64 {
273 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult<()> {
274 let TimeSplit { y, mo, d, h, m, s, .. } = self.split();
275 write![f, "{y:04}-{mo:02}-{d:02}_{h:02}:{m:02}:{s:02}"]
276 }
277}
278impl Debug for UnixTimeI64 {
279 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult<()> {
280 let TimeSplit { y, mo, d, h, m, s, .. } = self.split();
281 write![f, "UnixTimeI64 {{ {y:04}-{mo:02}-{d:02}_{h:02}:{m:02}:{s:02} }}"]
282 }
283}
284
285impl Display for UnixTimeU32 {
286 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult<()> {
287 let TimeSplit { y, mo, d, h, m, s, .. } = self.split();
288 write![f, "{y:04}-{mo:02}-{d:02}_{h:02}:{m:02}:{s:02}"]
289 }
290}
291
292impl Debug for UnixTimeU32 {
293 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult<()> {
294 let TimeSplit { y, mo, d, h, m, s, .. } = self.split();
295 write![f, "UnixTimeU32 {{ {y:04}-{mo:02}-{d:02}_{h:02}:{m:02}:{s:02} }}"]
296 }
297}
298
299impl From<UnixTimeU32> for UnixTimeI64 {
300 fn from(ut: UnixTimeU32) -> UnixTimeI64 {
301 UnixTimeI64 { seconds: ut.seconds.into() }
302 }
303}
304
305impl TryFrom<UnixTimeI64> for UnixTimeU32 {
306 type Error = TryFromIntError;
307
308 fn try_from(ut: UnixTimeI64) -> Result<UnixTimeU32, Self::Error> {
309 Ok(UnixTimeU32 { seconds: u32::try_from(ut.seconds)? })
310 }
311}
312
313#[cfg(feature = "std")]
314mod std_impls {
315 #[cfg(all(feature = "cast", feature = "error"))]
316 use crate::{Cast, DataOverflow, UnixTimeU32};
317 use crate::{SystemTime, SystemTimeError, UnixTimeI64};
318
319 impl TryFrom<SystemTime> for UnixTimeI64 {
320 type Error = SystemTimeError;
321
322 fn try_from(time: SystemTime) -> Result<Self, Self::Error> {
323 let duration = time.duration_since(SystemTime::UNIX_EPOCH)?;
324 Ok(UnixTimeI64 {
325 seconds: duration.as_secs() as i64, })
327 }
328 }
329
330 #[cfg(all(feature = "cast", feature = "error"))]
331 #[cfg_attr(feature = "nightly_doc", doc(cfg(all(feature = "cast", feature = "error"))))]
332 impl TryFrom<SystemTime> for UnixTimeU32 {
333 type Error = crate::TimeError;
334
335 fn try_from(time: SystemTime) -> Result<Self, Self::Error> {
336 let since = time.duration_since(SystemTime::UNIX_EPOCH)?;
337 let seconds = u32::try_from(since.as_secs())
338 .map_err(|_| DataOverflow(Cast(since.as_secs()).checked_cast_to_usize().ok()))?;
339 Ok(UnixTimeU32 { seconds })
340 }
341 }
342
343 }
361
362macro_rules! impl_from_prim {
364 ($ut:ty, $($prim:ty),+) => { $( impl_from_prim![@ $ut, $prim]; )+ };
366 (@ $ut:ty, $prim:ty) => {
367 impl From<$prim> for $ut {
368 fn from(seconds: $prim) -> $ut {
369 Self { seconds: seconds.into() }
370 }
371 }
372 };
373}
374impl_from_prim![UnixTimeI64, i64, i32, i16, i8, u32, u16, u8];
375impl_from_prim![UnixTimeU32, u32, u16, u8];
376
377macro_rules! impl_try_from_prim {
379 ($ut:ty, $($prim:ty),+) => { $( impl_try_from_prim![@ $ut, $prim]; )+ };
380 (@ $ut:ty, $prim:ty) => {
381 impl TryFrom<$prim> for $ut {
382 type Error = TryFromIntError;
383 fn try_from(seconds: $prim) -> Result<$ut, Self::Error> {
384 Ok(Self { seconds: seconds.try_into()? })
385 }
386 }
387 };
388}
389impl_try_from_prim![UnixTimeI64, u64, u128, usize, i128, isize];
390#[rustfmt::skip]
391impl_try_from_prim![UnixTimeU32, u64, u128, usize, i8, i16, i32, i64, i128, isize];