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