/rust/registry/src/index.crates.io-1949cf8c6b5b557f/time-0.3.55/src/timestamp.rs
Line | Count | Source |
1 | | //! The [`Timestamp`] struct and associated `impl`s. |
2 | | |
3 | | #[cfg(feature = "formatting")] |
4 | | use alloc::string::String; |
5 | | use core::cmp::Ordering; |
6 | | use core::fmt; |
7 | | use core::hash::{Hash, Hasher}; |
8 | | use core::mem::MaybeUninit; |
9 | | use core::ops::{Add, AddAssign, Sub, SubAssign}; |
10 | | use core::time::Duration as StdDuration; |
11 | | #[cfg(feature = "formatting")] |
12 | | use std::io; |
13 | | #[cfg(feature = "std")] |
14 | | use std::time::SystemTime; |
15 | | |
16 | | use deranged::{ri64, ri128, ru8, ru32}; |
17 | | |
18 | | #[cfg(any(feature = "formatting", feature = "parsing"))] |
19 | | use crate::PrivateMethod; |
20 | | #[cfg(feature = "formatting")] |
21 | | use crate::formatting::Formattable; |
22 | | use crate::internal_macros::{bug, const_try, div_floor, ensure_ranged}; |
23 | | use crate::num_fmt::{str_from_raw_parts, truncated_subsecond_from_nanos, u64_pad_none}; |
24 | | #[cfg(feature = "parsing")] |
25 | | use crate::parsing::{Parsable, Parsed}; |
26 | | use crate::unit::*; |
27 | | use crate::util::Overflow; |
28 | | use crate::{ |
29 | | Date, Month, OffsetDateTime, SignedDuration, Time, UtcDateTime, UtcOffset, Weekday, error, util, |
30 | | }; |
31 | | |
32 | | /// The range of valid seconds for a [`Timestamp`]. |
33 | | pub(crate) type Seconds = |
34 | | ri64<{ UtcDateTime::MIN.unix_timestamp() }, { UtcDateTime::MAX.unix_timestamp() }>; |
35 | | type Nanoseconds = ru32<0, 999_999_999>; |
36 | | |
37 | | // Validate that the minimum time is midnight and the maximum is one nanosecond before midnight. |
38 | | // This is necessary because the soundness of some functions relies on this fact. |
39 | | const _: () = { |
40 | | assert!(Timestamp::MIN.time().as_u64() == Time::MIDNIGHT.as_u64()); |
41 | | assert!(Timestamp::MAX.time().as_u64() == Time::MAX.as_u64()); |
42 | | }; |
43 | | |
44 | | /// By explicitly inserting this enum where padding is expected, the compiler is able to better |
45 | | /// perform niche value optimization. |
46 | | #[repr(u32)] |
47 | | #[derive(Clone, Copy, PartialEq, Eq)] |
48 | | enum Padding { |
49 | | #[allow(clippy::missing_docs_in_private_items)] |
50 | | Optimize, |
51 | | } |
52 | | |
53 | | /// A Unix timestamp with nanosecond precision. |
54 | | /// |
55 | | /// This type represents a point in time as a number of seconds and nanoseconds elapsed since the |
56 | | /// Unix epoch (1970-01-01 00:00:00 UTC). Negative values represent times before the Unix epoch. |
57 | | #[derive(Clone, Copy, Eq)] |
58 | | #[cfg_attr(not(docsrs), repr(C))] |
59 | | pub struct Timestamp { |
60 | | #[cfg(target_endian = "big")] |
61 | | seconds: Seconds, |
62 | | #[cfg(target_endian = "big")] |
63 | | nanoseconds: Nanoseconds, |
64 | | #[cfg(target_endian = "big")] |
65 | | padding: Padding, |
66 | | |
67 | | #[cfg(target_endian = "little")] |
68 | | padding: Padding, |
69 | | #[cfg(target_endian = "little")] |
70 | | nanoseconds: Nanoseconds, |
71 | | #[cfg(target_endian = "little")] |
72 | | seconds: Seconds, |
73 | | } |
74 | | |
75 | | impl Hash for Timestamp { |
76 | | #[inline] |
77 | 0 | fn hash<H: Hasher>(&self, state: &mut H) { |
78 | 0 | state.write_i128(self.as_i128()); |
79 | 0 | } |
80 | | } |
81 | | |
82 | | impl PartialEq for Timestamp { |
83 | | #[inline] |
84 | 0 | fn eq(&self, other: &Self) -> bool { |
85 | 0 | self.as_i128() == other.as_i128() |
86 | 0 | } |
87 | | } |
88 | | |
89 | | impl PartialOrd for Timestamp { |
90 | | #[inline] |
91 | 0 | fn partial_cmp(&self, other: &Self) -> Option<Ordering> { |
92 | 0 | Some(self.cmp(other)) |
93 | 0 | } |
94 | | } |
95 | | |
96 | | impl Ord for Timestamp { |
97 | | #[inline] |
98 | 0 | fn cmp(&self, other: &Self) -> Ordering { |
99 | 0 | self.as_i128().cmp(&other.as_i128()) |
100 | 0 | } |
101 | | } |
102 | | |
103 | | impl Timestamp { |
104 | | #[inline] |
105 | 0 | const fn as_i128(self) -> i128 { |
106 | | // Safety: `self` is presumed valid because it exists, and any value of `i128` is valid. |
107 | | // Size and alignment are enforced by the compiler. There is no implicit padding in |
108 | | // either `Timestamp` or `i128`. |
109 | 0 | unsafe { core::mem::transmute(self) } |
110 | 0 | } |
111 | | |
112 | | /// A `Timestamp` representing the Unix epoch (1970-01-01 00:00:00 UTC). |
113 | | pub const UNIX_EPOCH: Self = |
114 | | Self::new_ranged(Seconds::new_static::<0>(), Nanoseconds::new_static::<0>()); |
115 | | |
116 | | /// The minimum valid `Timestamp`. |
117 | | /// |
118 | | /// The moment in time represented by this value may vary depending on the feature flags |
119 | | /// enabled. |
120 | | pub const MIN: Self = Self::new_ranged(Seconds::MIN, Nanoseconds::MIN); |
121 | | |
122 | | /// The maximum valid `Timestamp`. |
123 | | /// |
124 | | /// The moment in time represented by this value may vary depending on the feature flags |
125 | | /// enabled. |
126 | | pub const MAX: Self = Self::new_ranged(Seconds::MAX, Nanoseconds::MAX); |
127 | | |
128 | | /// Create a new `Timestamp` representing the current moment in time. |
129 | | /// |
130 | | /// ```rust |
131 | | /// # use time::Timestamp; |
132 | | /// assert!(Timestamp::now().year() >= 2019); |
133 | | /// ``` |
134 | | #[cfg(feature = "std")] |
135 | | #[inline] |
136 | 0 | pub fn now() -> Self { |
137 | 0 | SystemTime::now().into() |
138 | 0 | } |
139 | | |
140 | | /// Create a `Timestamp` from the provided seconds and nanoseconds values without checking if |
141 | | /// they are valid. |
142 | | /// |
143 | | /// # Safety |
144 | | /// |
145 | | /// Both `seconds` and `nanoseconds` must be in range. |
146 | | #[doc(hidden)] |
147 | | #[inline] |
148 | | #[track_caller] |
149 | 0 | pub const unsafe fn __new_unchecked(seconds: i64, nanoseconds: u32) -> Self { |
150 | | // Safety: The caller must ensure both values are valid. |
151 | | unsafe { |
152 | 0 | Self::new_ranged( |
153 | 0 | Seconds::new_unchecked(seconds), |
154 | 0 | Nanoseconds::new_unchecked(nanoseconds), |
155 | | ) |
156 | | } |
157 | 0 | } |
158 | | |
159 | | /// Create a `Timestamp` from the provided seconds and nanoseconds values that are known to be |
160 | | /// in range. |
161 | | #[inline] |
162 | 0 | pub(crate) const fn new_ranged(seconds: Seconds, nanoseconds: Nanoseconds) -> Self { |
163 | 0 | Self { |
164 | 0 | seconds, |
165 | 0 | nanoseconds, |
166 | 0 | padding: Padding::Optimize, |
167 | 0 | } |
168 | 0 | } |
169 | | |
170 | | /// Create a `Timestamp` from the provided Unix timestamp in seconds and nanoseconds, returning |
171 | | /// an error if the resulting value is out of range. |
172 | | /// |
173 | | /// ```rust |
174 | | /// # use time::Timestamp; |
175 | | /// assert!(Timestamp::new(0, 0).is_ok()); |
176 | | /// assert!(Timestamp::new(i64::MAX, 0).is_err()); |
177 | | /// ``` |
178 | | #[inline] |
179 | 0 | pub const fn new(seconds: i64, nanoseconds: u32) -> Result<Self, error::ComponentRange> { |
180 | 0 | Ok(Self::new_ranged( |
181 | 0 | ensure_ranged!(Seconds: seconds), |
182 | 0 | ensure_ranged!(Nanoseconds: nanoseconds), |
183 | | )) |
184 | 0 | } |
185 | | |
186 | | /// Create a `Timestamp` from the provided Unix timestamp in seconds, returning an error if the |
187 | | /// resulting value is out of range. |
188 | | /// |
189 | | /// ```rust |
190 | | /// # use time::Timestamp; |
191 | | /// assert!(Timestamp::from_seconds(0).is_ok()); |
192 | | /// assert!(Timestamp::from_seconds(i64::MAX).is_err()); |
193 | | /// ``` |
194 | | #[inline] |
195 | 0 | pub const fn from_seconds(seconds: i64) -> Result<Self, error::ComponentRange> { |
196 | 0 | Ok(Self::new_ranged( |
197 | 0 | ensure_ranged!(Seconds: seconds), |
198 | 0 | Nanoseconds::new_static::<0>(), |
199 | | )) |
200 | 0 | } |
201 | | |
202 | | /// Create a `Timestamp` from the provided Unix timestamp in milliseconds, returning an error if |
203 | | /// the resulting value is out of range. |
204 | | /// |
205 | | /// ```rust |
206 | | /// # use time::Timestamp; |
207 | | /// assert!(Timestamp::from_milliseconds(0).is_ok()); |
208 | | /// assert!(Timestamp::from_milliseconds(i64::MAX).is_err()); |
209 | | /// ``` |
210 | | #[inline] |
211 | 0 | pub const fn from_milliseconds(milliseconds: i64) -> Result<Self, error::ComponentRange> { |
212 | | const MAX: i64 = Seconds::MAX.get() * Millisecond::per_t::<i64>(Second) |
213 | | + (Nanoseconds::MAX.get() as i64) / Nanosecond::per_t::<i64>(Millisecond); |
214 | | const MIN: i64 = Seconds::MIN.get() * Millisecond::per_t::<i64>(Second) |
215 | | + (Nanoseconds::MIN.get() as i64) / Nanosecond::per_t::<i64>(Millisecond); |
216 | | |
217 | 0 | ensure_ranged!(ri64<MIN, MAX>: milliseconds); |
218 | | |
219 | 0 | let mut seconds = milliseconds / Millisecond::per_t::<i64>(Second); |
220 | 0 | let nanoseconds = (milliseconds.rem_euclid(Millisecond::per_t(Second)) |
221 | 0 | * Nanosecond::per_t::<i64>(Millisecond)) as u32; |
222 | | |
223 | 0 | if milliseconds < 0 && nanoseconds != 0 { |
224 | 0 | seconds -= 1; |
225 | 0 | } |
226 | | |
227 | | // Safety: The value provided was checked to be in range. |
228 | 0 | Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds) }) |
229 | 0 | } |
230 | | |
231 | | /// Create a `Timestamp` from the provided Unix timestamp in microseconds, returning an error if |
232 | | /// the resulting value is out of range. |
233 | | /// |
234 | | /// ```rust |
235 | | /// # use time::Timestamp; |
236 | | /// assert!(Timestamp::from_microseconds(0).is_ok()); |
237 | | /// assert!(Timestamp::from_microseconds(i128::MAX).is_err()); |
238 | | /// ``` |
239 | | #[inline] |
240 | 0 | pub const fn from_microseconds(microseconds: i128) -> Result<Self, error::ComponentRange> { |
241 | | const MAX: i128 = Seconds::MAX.get() as i128 * Microsecond::per_t::<i128>(Second) |
242 | | + (Nanoseconds::MAX.get() as i128) / Nanosecond::per_t::<i128>(Microsecond); |
243 | | const MIN: i128 = Seconds::MIN.get() as i128 * Microsecond::per_t::<i128>(Second) |
244 | | + (Nanoseconds::MIN.get() as i128) / Nanosecond::per_t::<i128>(Microsecond); |
245 | | |
246 | 0 | ensure_ranged!(ri128<MIN, MAX>: microseconds); |
247 | | |
248 | 0 | let mut seconds = (microseconds / Microsecond::per_t::<i128>(Second)) as i64; |
249 | 0 | let nanoseconds = (microseconds.rem_euclid(Microsecond::per_t(Second)) |
250 | 0 | * Nanosecond::per_t::<i128>(Microsecond)) as u32; |
251 | | |
252 | 0 | if microseconds < 0 && nanoseconds != 0 { |
253 | 0 | seconds -= 1; |
254 | 0 | } |
255 | | |
256 | | // Safety: The value provided was checked to be in range. |
257 | 0 | Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds) }) |
258 | 0 | } |
259 | | |
260 | | /// Create a `Timestamp` from the provided Unix timestamp in nanoseconds, returning an error if |
261 | | /// the resulting value is out of range. |
262 | | /// |
263 | | /// ```rust |
264 | | /// # use time::Timestamp; |
265 | | /// assert!(Timestamp::from_nanoseconds(0).is_ok()); |
266 | | /// assert!(Timestamp::from_nanoseconds(i128::MAX).is_err()); |
267 | | /// ``` |
268 | | #[inline] |
269 | 0 | pub const fn from_nanoseconds(nanoseconds: i128) -> Result<Self, error::ComponentRange> { |
270 | | const MAX: i128 = Seconds::MAX.get() as i128 * Nanosecond::per_t::<i128>(Second) |
271 | | + Nanoseconds::MAX.get() as i128; |
272 | | const MIN: i128 = Seconds::MIN.get() as i128 * Nanosecond::per_t::<i128>(Second) |
273 | | + Nanoseconds::MIN.get() as i128; |
274 | | |
275 | 0 | ensure_ranged!(ri128<MIN, MAX>: nanoseconds); |
276 | | |
277 | 0 | let input_is_negative = nanoseconds < 0; |
278 | 0 | let mut seconds = (nanoseconds / Nanosecond::per_t::<i128>(Second)) as i64; |
279 | 0 | let nanoseconds = nanoseconds.rem_euclid(Nanosecond::per_t(Second)) as u32; |
280 | | |
281 | 0 | if input_is_negative && nanoseconds != 0 { |
282 | 0 | seconds -= 1; |
283 | 0 | } |
284 | | |
285 | | // Safety: The value provided was checked to be in range. |
286 | 0 | Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds) }) |
287 | 0 | } |
288 | | |
289 | | /// Convert the `Timestamp` to an [`OffsetDateTime`] at the provided offset. |
290 | | /// |
291 | | /// ```rust |
292 | | /// # use time_macros::{offset, timestamp}; |
293 | | /// assert_eq!(timestamp!(1_546_398_245).to_offset(offset!(+1)).hour(), 4); |
294 | | /// ``` |
295 | | /// |
296 | | /// # Panics |
297 | | /// |
298 | | /// This panics if the resulting date-time with the provided offset is outside the supported |
299 | | /// range. Consider using [`checked_to_offset`](Self::checked_to_offset) for a non-panicking |
300 | | /// alternative. |
301 | | #[inline] |
302 | 0 | pub const fn to_offset(self, offset: UtcOffset) -> OffsetDateTime { |
303 | 0 | self.to_utc().to_offset(offset) |
304 | 0 | } |
305 | | |
306 | | /// Convert the `Timestamp` to an [`OffsetDateTime`] with the provided offset, returning `None` |
307 | | /// if the resulting value is out of range. |
308 | | /// |
309 | | /// ```rust |
310 | | /// # use time_macros::{offset, timestamp}; |
311 | | /// assert!( |
312 | | /// timestamp!(1_546_398_245) |
313 | | /// .checked_to_offset(offset!(+1)) |
314 | | /// .is_some() |
315 | | /// ); |
316 | | /// ``` |
317 | | #[inline] |
318 | 0 | pub const fn checked_to_offset(self, offset: UtcOffset) -> Option<OffsetDateTime> { |
319 | 0 | self.to_utc().checked_to_offset(offset) |
320 | 0 | } |
321 | | |
322 | | /// Convert the `Timestamp` to a [`UtcDateTime`]. |
323 | | /// |
324 | | /// ```rust |
325 | | /// # use time_macros::{timestamp, utc_datetime}; |
326 | | /// assert_eq!(timestamp!(1_546_398_245).to_utc(), utc_datetime!(2019-01-02 3:04:05)); |
327 | | /// ``` |
328 | | #[inline] |
329 | 0 | pub const fn to_utc(self) -> UtcDateTime { |
330 | 0 | let Ok(utc_dt) = UtcDateTime::from_unix_timestamp(self.seconds.get()) else { |
331 | 0 | bug!("timestamp was invalid beforehand"); |
332 | | }; |
333 | 0 | let Ok(utc_dt) = utc_dt.replace_nanosecond(self.nanoseconds.get()) else { |
334 | 0 | bug!("nanosecond was invalid beforehand"); |
335 | | }; |
336 | | |
337 | 0 | utc_dt |
338 | 0 | } |
339 | | |
340 | | /// Get the seconds and nanoseconds of the timestamp as ranged values. |
341 | | #[inline] |
342 | 0 | pub(crate) const fn as_parts_ranged(self) -> (Seconds, Nanoseconds) { |
343 | 0 | (self.seconds, self.nanoseconds) |
344 | 0 | } |
345 | | |
346 | | /// Get the number of seconds since the Unix epoch. |
347 | | /// |
348 | | /// Negative values represent moments before the Unix epoch. |
349 | | /// |
350 | | /// ```rust |
351 | | /// # use time_macros::timestamp; |
352 | | /// assert_eq!(timestamp!(1_546_398_245).as_seconds(), 1_546_398_245); |
353 | | /// ``` |
354 | | #[inline] |
355 | 0 | pub const fn as_seconds(self) -> i64 { |
356 | 0 | self.seconds.get() |
357 | 0 | } |
358 | | |
359 | | /// Get the number of milliseconds since the Unix epoch. |
360 | | /// |
361 | | /// Negative values represent moments before the Unix epoch. |
362 | | /// |
363 | | /// ```rust |
364 | | /// # use time_macros::timestamp; |
365 | | /// assert_eq!( |
366 | | /// timestamp!(1_546_398_245.006).as_milliseconds(), |
367 | | /// 1_546_398_245_006 |
368 | | /// ); |
369 | | /// ``` |
370 | | #[inline] |
371 | 0 | pub const fn as_milliseconds(self) -> i64 { |
372 | 0 | self.seconds.get() * Millisecond::per_t::<i64>(Second) |
373 | 0 | + (self.nanoseconds.get() / Nanosecond::per_t::<u32>(Millisecond)) as i64 |
374 | 0 | } |
375 | | |
376 | | /// Get the number of microseconds since the Unix epoch. |
377 | | /// |
378 | | /// Negative values represent moments before the Unix epoch. |
379 | | /// |
380 | | /// ```rust |
381 | | /// # use time_macros::timestamp; |
382 | | /// assert_eq!( |
383 | | /// timestamp!(1_546_398_245.006_007).as_microseconds(), |
384 | | /// 1_546_398_245_006_007 |
385 | | /// ); |
386 | | /// ``` |
387 | | #[inline] |
388 | 0 | pub const fn as_microseconds(self) -> i128 { |
389 | 0 | self.seconds.get() as i128 * Microsecond::per_t::<i128>(Second) |
390 | 0 | + (self.nanoseconds.get() / Nanosecond::per_t::<u32>(Microsecond)) as i128 |
391 | 0 | } |
392 | | |
393 | | /// Get the number of nanoseconds since the Unix epoch. |
394 | | /// |
395 | | /// Negative values represent moments before the Unix epoch. |
396 | | /// |
397 | | /// ```rust |
398 | | /// # use time_macros::timestamp; |
399 | | /// assert_eq!( |
400 | | /// timestamp!(1_546_398_245.006_007_008).as_nanoseconds(), |
401 | | /// 1_546_398_245_006_007_008 |
402 | | /// ); |
403 | | /// ``` |
404 | | #[inline] |
405 | 0 | pub const fn as_nanoseconds(self) -> i128 { |
406 | 0 | self.seconds.get() as i128 * Nanosecond::per_t::<i128>(Second) |
407 | 0 | + self.nanoseconds.get() as i128 |
408 | 0 | } |
409 | | |
410 | | /// Get the [`Date`] of the timestamp in UTC. |
411 | | /// |
412 | | /// ```rust |
413 | | /// # use time_macros::{date, timestamp}; |
414 | | /// assert_eq!(timestamp!(1_546_398_245).date(), date!(2019-01-02)); |
415 | | /// ``` |
416 | | #[inline] |
417 | 0 | pub const fn date(self) -> Date { |
418 | 0 | self.to_utc().date() |
419 | 0 | } |
420 | | |
421 | | /// Get the [`Time`] of the timestamp in UTC. |
422 | | /// |
423 | | /// ```rust |
424 | | /// # use time_macros::{time, timestamp}; |
425 | | /// assert_eq!(timestamp!(1_546_398_245).time(), time!(3:04:05)); |
426 | | /// ``` |
427 | | #[inline] |
428 | 0 | pub const fn time(self) -> Time { |
429 | 0 | let within_day = self.as_seconds().rem_euclid(Second::per_t::<i64>(Day)) as u32; |
430 | | |
431 | 0 | let hour = within_day / Second::per_t::<u32>(Hour); |
432 | 0 | let minute = |
433 | 0 | (within_day - hour * Second::per_t::<u32>(Hour)) / Second::per_t::<u32>(Minute); |
434 | 0 | let second = |
435 | 0 | within_day - hour * Second::per_t::<u32>(Hour) - minute * Second::per_t::<u32>(Minute); |
436 | | |
437 | | // Safety: All values are guaranteed to be in range. |
438 | | unsafe { |
439 | 0 | Time::__from_hms_nanos_unchecked( |
440 | 0 | hour as u8, |
441 | 0 | minute as u8, |
442 | 0 | second as u8, |
443 | 0 | self.nanosecond(), |
444 | | ) |
445 | | } |
446 | 0 | } |
447 | | |
448 | | /// Compute the year, leap year status, and ordinal day of the timestamp in UTC. |
449 | | /// |
450 | | /// This algorithm is essentially identical to `Date::from_julian_day_unchecked`. Instead of |
451 | | /// returning `Date`, it returns the components as a tuple. By not bitpacking the values, it |
452 | | /// allows the compiler to see through the function boundary and better optimize methods. |
453 | | #[inline] |
454 | 0 | const fn year_leap_ordinal(self) -> (i32, bool, u16) { |
455 | | const ERAS: u32 = 5_949; |
456 | | const D_SHIFT: u32 = 146097 * ERAS + 719_528; |
457 | | const Y_SHIFT: u32 = 400 * ERAS; |
458 | | |
459 | | const CEN_MUL: u32 = ((4u64 << 47) / 146_097) as u32; |
460 | | const JUL_MUL: u32 = ((4u64 << 40) / 1_461 + 1) as u32; |
461 | | const CEN_CUT: u32 = ((365u64 << 32) / 36_525) as u32; |
462 | | |
463 | 0 | let raw_day = div_floor!(self.as_seconds(), Second::per_t::<i64>(Day)) as i32; |
464 | | |
465 | 0 | let day = raw_day.cast_unsigned().wrapping_add(D_SHIFT); |
466 | 0 | let c_n = (day as u64 * CEN_MUL as u64) >> 15; |
467 | 0 | let cen = (c_n >> 32) as u32; |
468 | 0 | let cpt = c_n as u32; |
469 | 0 | let ijy = cpt > CEN_CUT || cen.is_multiple_of(4); |
470 | 0 | let jul = day - cen / 4 + cen; |
471 | 0 | let y_n = (jul as u64 * JUL_MUL as u64) >> 8; |
472 | 0 | let yrs = (y_n >> 32) as u32; |
473 | 0 | let ypt = y_n as u32; |
474 | | |
475 | 0 | let year = yrs.wrapping_sub(Y_SHIFT).cast_signed(); |
476 | 0 | let ordinal = ((ypt as u64 * 1_461) >> 34) as u32 + ijy as u32; |
477 | 0 | let leap = yrs.is_multiple_of(4) & ijy; |
478 | | |
479 | 0 | (year, leap, ordinal as u16) |
480 | 0 | } |
481 | | |
482 | | /// Get the year of the timestamp in UTC. |
483 | | /// |
484 | | /// ```rust |
485 | | /// # use time_macros::timestamp; |
486 | | /// assert_eq!(timestamp!(1_546_398_245).year(), 2019); |
487 | | /// ``` |
488 | | #[inline] |
489 | 0 | pub const fn year(self) -> i32 { |
490 | 0 | self.year_leap_ordinal().0 |
491 | 0 | } |
492 | | |
493 | | /// Get the month of the timestamp in UTC. |
494 | | /// |
495 | | /// ```rust |
496 | | /// # use time::Month; |
497 | | /// # use time_macros::timestamp; |
498 | | /// assert_eq!(timestamp!(1_546_398_245).month(), Month::January); |
499 | | /// ``` |
500 | | #[inline] |
501 | 0 | pub const fn month(self) -> Month { |
502 | 0 | let (_, leap, ordinal) = self.year_leap_ordinal(); |
503 | 0 | util::leap_ordinal_to_month_day(leap, ordinal).0 |
504 | 0 | } |
505 | | |
506 | | /// Get the day of the month of the timestamp in UTC. |
507 | | /// |
508 | | /// The returned value will always be in the range `1..=31`. |
509 | | /// |
510 | | /// ```rust |
511 | | /// # use time_macros::timestamp; |
512 | | /// assert_eq!(timestamp!(1_546_398_245).day(), 2); |
513 | | /// ``` |
514 | | #[inline] |
515 | 0 | pub const fn day(self) -> u8 { |
516 | 0 | let (_, leap, ordinal) = self.year_leap_ordinal(); |
517 | 0 | util::leap_ordinal_to_month_day(leap, ordinal).1 |
518 | 0 | } |
519 | | |
520 | | /// Get the day of the year of the timestamp in UTC. |
521 | | /// |
522 | | /// The returned value will always be in the range `1..=366`. |
523 | | /// |
524 | | /// ```rust |
525 | | /// # use time_macros::timestamp; |
526 | | /// assert_eq!(timestamp!(1_546_398_245).ordinal(), 2); |
527 | | /// ``` |
528 | | #[inline] |
529 | 0 | pub const fn ordinal(self) -> u16 { |
530 | 0 | self.year_leap_ordinal().2 |
531 | 0 | } |
532 | | |
533 | | /// Get the ISO week number of the timestamp in UTC. |
534 | | /// |
535 | | /// The returned value will always be in the range `1..=53`. |
536 | | /// |
537 | | /// ```rust |
538 | | /// # use time_macros::timestamp; |
539 | | /// assert_eq!(timestamp!(1_546_398_245).iso_week(), 1); |
540 | | /// ``` |
541 | | #[inline] |
542 | 0 | pub const fn iso_week(self) -> u8 { |
543 | 0 | self.date().iso_week() |
544 | 0 | } |
545 | | |
546 | | /// Get the Sunday-based week number of the timestamp in UTC. |
547 | | /// |
548 | | /// The returned value will always be in the range `0..=53`. |
549 | | /// |
550 | | /// ```rust |
551 | | /// # use time_macros::timestamp; |
552 | | /// assert_eq!(timestamp!(1_546_398_245).sunday_based_week(), 0); |
553 | | /// ``` |
554 | | #[inline] |
555 | 0 | pub const fn sunday_based_week(self) -> u8 { |
556 | 0 | self.date().sunday_based_week() |
557 | 0 | } |
558 | | |
559 | | /// Get the Monday-based week number of the timestamp in UTC. |
560 | | /// |
561 | | /// The returned value will always be in the range `0..=53`. |
562 | | /// |
563 | | /// ```rust |
564 | | /// # use time_macros::timestamp; |
565 | | /// assert_eq!(timestamp!(1_546_398_245).monday_based_week(), 0); |
566 | | /// ``` |
567 | | #[inline] |
568 | 0 | pub const fn monday_based_week(self) -> u8 { |
569 | 0 | self.date().monday_based_week() |
570 | 0 | } |
571 | | |
572 | | /// Get the calendar date (year, month, day) of the timestamp in UTC. |
573 | | /// |
574 | | /// ```rust |
575 | | /// # use time::Month; |
576 | | /// # use time_macros::timestamp; |
577 | | /// assert_eq!( |
578 | | /// timestamp!(1_546_398_245).to_calendar_date(), |
579 | | /// (2019, Month::January, 2) |
580 | | /// ); |
581 | | /// ``` |
582 | | #[inline] |
583 | 0 | pub const fn to_calendar_date(self) -> (i32, Month, u8) { |
584 | 0 | let (year, leap, ordinal) = self.year_leap_ordinal(); |
585 | 0 | let (month, day) = util::leap_ordinal_to_month_day(leap, ordinal); |
586 | 0 | (year, month, day) |
587 | 0 | } |
588 | | |
589 | | /// Get the ordinal date (year, ordinal day) of the timestamp in UTC. |
590 | | /// |
591 | | /// ```rust |
592 | | /// # use time_macros::timestamp; |
593 | | /// assert_eq!(timestamp!(1_546_398_245).to_ordinal_date(), (2019, 2)); |
594 | | /// ``` |
595 | | #[inline] |
596 | 0 | pub const fn to_ordinal_date(self) -> (i32, u16) { |
597 | 0 | let (year, _, ordinal) = self.year_leap_ordinal(); |
598 | 0 | (year, ordinal) |
599 | 0 | } |
600 | | |
601 | | /// Get the ISO week date (year, week number, weekday) of the timestamp in UTC. |
602 | | /// |
603 | | /// ```rust |
604 | | /// # use time::Weekday; |
605 | | /// # use time_macros::timestamp; |
606 | | /// assert_eq!( |
607 | | /// timestamp!(1_546_398_245).to_iso_week_date(), |
608 | | /// (2019, 1, Weekday::Wednesday) |
609 | | /// ); |
610 | | /// ``` |
611 | | #[inline] |
612 | 0 | pub const fn to_iso_week_date(self) -> (i32, u8, Weekday) { |
613 | 0 | self.date().to_iso_week_date() |
614 | 0 | } |
615 | | |
616 | | /// Get the weekday of the timestamp in UTC. |
617 | | /// |
618 | | /// ```rust |
619 | | /// # use time::Weekday; |
620 | | /// # use time_macros::timestamp; |
621 | | /// assert_eq!(timestamp!(1_546_398_245).weekday(), Weekday::Wednesday); |
622 | | /// ``` |
623 | | #[inline] |
624 | 0 | pub const fn weekday(self) -> Weekday { |
625 | | // 365,961,669 is obtained by starting with the smallest timestamp (with large-dates |
626 | | // enabled), dividing by 86,400 to get the number of days, then rounding down to get a |
627 | | // multiple of 7. This value is negated as we want to end with a positive number. Finally, 3 |
628 | | // is added to shift the zero value to Monday, matching the internal representation of |
629 | | // `Weekday`. |
630 | 0 | match (div_floor!(self.seconds.get(), 86_400) + 365_961_669) % 7 { |
631 | 0 | 0 => Weekday::Monday, |
632 | 0 | 1 => Weekday::Tuesday, |
633 | 0 | 2 => Weekday::Wednesday, |
634 | 0 | 3 => Weekday::Thursday, |
635 | 0 | 4 => Weekday::Friday, |
636 | 0 | 5 => Weekday::Saturday, |
637 | 0 | 6 => Weekday::Sunday, |
638 | 0 | _ => unreachable!(), |
639 | | } |
640 | 0 | } |
641 | | |
642 | | /// Get the Julian day of the timestamp. |
643 | | /// |
644 | | /// ```rust |
645 | | /// # use time_macros::timestamp; |
646 | | /// assert_eq!(timestamp!(1_546_398_245).to_julian_day(), 2_458_486); |
647 | | /// ``` |
648 | | #[inline] |
649 | 0 | pub const fn to_julian_day(self) -> i32 { |
650 | | const UNIX_EPOCH_JULIAN_DAY: i32 = Date::UNIX_EPOCH.to_julian_day(); |
651 | 0 | div_floor!(self.seconds.get(), 86_400) as i32 + UNIX_EPOCH_JULIAN_DAY |
652 | 0 | } |
653 | | |
654 | | /// Get the hours, minutes, and seconds of the timestamp in UTC. |
655 | | /// |
656 | | /// ```rust |
657 | | /// # use time_macros::timestamp; |
658 | | /// assert_eq!(timestamp!(1_546_398_245).as_hms(), (3, 4, 5)); |
659 | | /// ``` |
660 | | #[inline] |
661 | 0 | pub const fn as_hms(self) -> (u8, u8, u8) { |
662 | 0 | self.time().as_hms() |
663 | 0 | } |
664 | | |
665 | | /// Get the hours, minutes, seconds, and milliseconds of the timestamp in UTC. |
666 | | /// |
667 | | /// ```rust |
668 | | /// # use time_macros::timestamp; |
669 | | /// assert_eq!(timestamp!(1_546_398_245.006).as_hms_milli(), (3, 4, 5, 6)); |
670 | | /// ``` |
671 | | #[inline] |
672 | 0 | pub const fn as_hms_milli(self) -> (u8, u8, u8, u16) { |
673 | 0 | self.time().as_hms_milli() |
674 | 0 | } |
675 | | |
676 | | /// Get the hours, minutes, seconds, and microseconds of the timestamp in UTC. |
677 | | /// |
678 | | /// ```rust |
679 | | /// # use time_macros::timestamp; |
680 | | /// assert_eq!( |
681 | | /// timestamp!(1_546_398_245.006_007).as_hms_micro(), |
682 | | /// (3, 4, 5, 6_007) |
683 | | /// ); |
684 | | /// ``` |
685 | | #[inline] |
686 | 0 | pub const fn as_hms_micro(self) -> (u8, u8, u8, u32) { |
687 | 0 | self.time().as_hms_micro() |
688 | 0 | } |
689 | | |
690 | | /// Get the hours, minutes, seconds, and nanoseconds of the timestamp in UTC. |
691 | | /// |
692 | | /// ```rust |
693 | | /// # use time_macros::timestamp; |
694 | | /// assert_eq!( |
695 | | /// timestamp!(1_546_398_245.006_007_008).as_hms_nano(), |
696 | | /// (3, 4, 5, 6_007_008) |
697 | | /// ); |
698 | | /// ``` |
699 | | #[inline] |
700 | 0 | pub const fn as_hms_nano(self) -> (u8, u8, u8, u32) { |
701 | 0 | self.time().as_hms_nano() |
702 | 0 | } |
703 | | |
704 | | /// Get the hour of the timestamp in UTC. |
705 | | /// |
706 | | /// ```rust |
707 | | /// # use time_macros::timestamp; |
708 | | /// assert_eq!(timestamp!(1_546_398_245).hour(), 3); |
709 | | /// ``` |
710 | | #[inline] |
711 | 0 | pub const fn hour(self) -> u8 { |
712 | 0 | self.time().hour() |
713 | 0 | } |
714 | | |
715 | | /// Get the minute of the timestamp in UTC. |
716 | | /// |
717 | | /// ```rust |
718 | | /// # use time_macros::timestamp; |
719 | | /// assert_eq!(timestamp!(1_546_398_245).minute(), 4); |
720 | | /// ``` |
721 | | #[inline] |
722 | 0 | pub const fn minute(self) -> u8 { |
723 | 0 | (div_floor!(self.seconds.get(), Second::per_t::<i64>(Minute))) |
724 | 0 | .rem_euclid(Minute::per_t(Hour)) as u8 |
725 | 0 | } |
726 | | |
727 | | /// Get the second of the timestamp in UTC. |
728 | | /// |
729 | | /// ```rust |
730 | | /// # use time_macros::timestamp; |
731 | | /// assert_eq!(timestamp!(1_546_398_245).second(), 5); |
732 | | /// ``` |
733 | | #[inline] |
734 | 0 | pub const fn second(self) -> u8 { |
735 | 0 | self.seconds.get().rem_euclid(Second::per_t(Minute)) as u8 |
736 | 0 | } |
737 | | |
738 | | /// Get the millisecond of the timestamp in UTC. |
739 | | /// |
740 | | /// ```rust |
741 | | /// # use time_macros::timestamp; |
742 | | /// assert_eq!(timestamp!(1_546_398_245.006).millisecond(), 6); |
743 | | /// ``` |
744 | | #[inline] |
745 | 0 | pub const fn millisecond(self) -> u16 { |
746 | 0 | (self.nanoseconds.get() / Nanosecond::per_t::<u32>(Millisecond)) as u16 |
747 | 0 | } |
748 | | |
749 | | /// Get the microsecond of the timestamp in UTC. |
750 | | /// |
751 | | /// ```rust |
752 | | /// # use time_macros::timestamp; |
753 | | /// assert_eq!(timestamp!(1_546_398_245.006_007).microsecond(), 6_007); |
754 | | /// ``` |
755 | | #[inline] |
756 | 0 | pub const fn microsecond(self) -> u32 { |
757 | 0 | self.nanoseconds.get() / Nanosecond::per_t::<u32>(Microsecond) |
758 | 0 | } |
759 | | |
760 | | /// Get the nanosecond of the timestamp in UTC. |
761 | | /// |
762 | | /// ```rust |
763 | | /// # use time_macros::timestamp; |
764 | | /// assert_eq!( |
765 | | /// timestamp!(1_546_398_245.006_007_008).nanosecond(), |
766 | | /// 6_007_008 |
767 | | /// ); |
768 | | /// ``` |
769 | | #[inline] |
770 | 0 | pub const fn nanosecond(self) -> u32 { |
771 | 0 | self.nanoseconds.get() |
772 | 0 | } |
773 | | |
774 | | /// Add a [`SignedDuration`] to the timestamp. Returns `Overflow::Positive` or |
775 | | /// `Overflow::Negative` if the result is out of range. |
776 | | #[inline] |
777 | 0 | const fn add(self, duration: SignedDuration) -> Result<Self, Overflow> { |
778 | 0 | let (second_adj, nanoseconds) = if duration.is_negative() { |
779 | 0 | let nanos = self.nanoseconds.get() as i32 + duration.subsec_nanoseconds(); |
780 | 0 | if nanos < 0 { |
781 | 0 | (-1, (nanos + Nanosecond::per_t::<i32>(Second)) as u32) |
782 | | } else { |
783 | 0 | (0, nanos as u32) |
784 | | } |
785 | | } else { |
786 | 0 | let nanos = self.nanoseconds.get() + duration.subsec_nanoseconds() as u32; |
787 | 0 | if nanos >= Nanosecond::per_t(Second) { |
788 | 0 | (1, nanos - Nanosecond::per_t::<u32>(Second)) |
789 | | } else { |
790 | 0 | (0, nanos) |
791 | | } |
792 | | }; |
793 | | |
794 | 0 | let seconds = match self.seconds.get().checked_add(duration.whole_seconds()) { |
795 | 0 | Some(seconds) => seconds, |
796 | 0 | None if duration.is_negative() => return Err(Overflow::Negative), |
797 | 0 | None => return Err(Overflow::Positive), |
798 | | }; |
799 | 0 | let seconds = match seconds.checked_add(second_adj) { |
800 | 0 | Some(seconds) => seconds, |
801 | 0 | None if second_adj < 0 => return Err(Overflow::Negative), |
802 | 0 | None => return Err(Overflow::Positive), |
803 | | }; |
804 | | |
805 | | // Check if the resulting seconds are within the valid range |
806 | 0 | if seconds < Seconds::MIN.get() { |
807 | 0 | return Err(Overflow::Negative); |
808 | 0 | } else if seconds > Seconds::MAX.get() { |
809 | 0 | return Err(Overflow::Positive); |
810 | 0 | } |
811 | | |
812 | | // Safety: Both values are guaranteed to be in range. |
813 | 0 | Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds) }) |
814 | 0 | } |
815 | | |
816 | | /// Subtract a [`SignedDuration`] from the timestamp. Returns `Overflow::Positive` or |
817 | | /// `Overflow::Negative` if the result is out of range. |
818 | | #[inline] |
819 | 0 | const fn sub(self, duration: SignedDuration) -> Result<Self, Overflow> { |
820 | 0 | let nanos = self.nanoseconds.get() as i32 - duration.subsec_nanoseconds(); |
821 | 0 | let (second_adj, nanoseconds) = if duration.is_negative() { |
822 | 0 | if nanos >= Nanosecond::per_t::<i32>(Second) { |
823 | 0 | (1, (nanos - Nanosecond::per_t::<i32>(Second)) as u32) |
824 | 0 | } else if nanos < 0 { |
825 | 0 | (-1, (nanos + Nanosecond::per_t::<i32>(Second)) as u32) |
826 | | } else { |
827 | 0 | (0, nanos as u32) |
828 | | } |
829 | | } else { |
830 | 0 | if nanos < 0 { |
831 | 0 | (-1, (nanos + Nanosecond::per_t::<i32>(Second)) as u32) |
832 | | } else { |
833 | 0 | (0, nanos as u32) |
834 | | } |
835 | | }; |
836 | | |
837 | 0 | let seconds = match self.seconds.get().checked_sub(duration.whole_seconds()) { |
838 | 0 | Some(seconds) => seconds, |
839 | 0 | None if duration.is_negative() => return Err(Overflow::Positive), |
840 | 0 | None => return Err(Overflow::Negative), |
841 | | }; |
842 | 0 | let seconds = match seconds.checked_add(second_adj) { |
843 | 0 | Some(seconds) => seconds, |
844 | 0 | None if second_adj < 0 => return Err(Overflow::Negative), |
845 | 0 | None => return Err(Overflow::Positive), |
846 | | }; |
847 | | |
848 | | // Check if the resulting seconds are within the valid range |
849 | 0 | if seconds < Seconds::MIN.get() { |
850 | 0 | return Err(Overflow::Negative); |
851 | 0 | } else if seconds > Seconds::MAX.get() { |
852 | 0 | return Err(Overflow::Positive); |
853 | 0 | } |
854 | | |
855 | | // Safety: Both values are guaranteed to be in range. |
856 | 0 | Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds) }) |
857 | 0 | } |
858 | | |
859 | | /// Add a [`std::time::Duration`] to the timestamp. Returns `Overflow::Positive` or |
860 | | /// `Overflow::Negative` if the result is out of range. |
861 | | #[inline] |
862 | 0 | const fn add_std(self, duration: StdDuration) -> Result<Self, Overflow> { |
863 | 0 | let Some(mut seconds) = self.seconds.get().checked_add_unsigned(duration.as_secs()) else { |
864 | 0 | return Err(Overflow::Positive); |
865 | | }; |
866 | 0 | let mut nanoseconds = self.nanoseconds.get() + duration.subsec_nanos(); |
867 | | |
868 | 0 | if nanoseconds >= Nanosecond::per_t(Second) { |
869 | 0 | nanoseconds -= Nanosecond::per_t::<u32>(Second); |
870 | 0 | let Some(new_seconds) = seconds.checked_add(1) else { |
871 | 0 | return Err(Overflow::Positive); |
872 | | }; |
873 | 0 | seconds = new_seconds; |
874 | 0 | } |
875 | | |
876 | | // Check if the resulting seconds are within the valid range |
877 | 0 | if seconds < Seconds::MIN.get() { |
878 | 0 | return Err(Overflow::Negative); |
879 | 0 | } else if seconds > Seconds::MAX.get() { |
880 | 0 | return Err(Overflow::Positive); |
881 | 0 | } |
882 | | |
883 | | // Safety: Both values are guaranteed to be in range. |
884 | 0 | Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds) }) |
885 | 0 | } |
886 | | |
887 | | /// Subtract a [`std::time::Duration`] from the timestamp. Returns `Overflow::Positive` or |
888 | | /// `Overflow::Negative` if the result is out of range. |
889 | | #[inline] |
890 | 0 | const fn sub_std(self, duration: StdDuration) -> Result<Self, Overflow> { |
891 | 0 | let Some(mut seconds) = self.seconds.get().checked_sub_unsigned(duration.as_secs()) else { |
892 | 0 | return Err(Overflow::Negative); |
893 | | }; |
894 | 0 | let mut nanoseconds = self.nanoseconds.get() as i32 - duration.subsec_nanos() as i32; |
895 | | |
896 | 0 | if nanoseconds < 0 { |
897 | 0 | nanoseconds += Nanosecond::per_t::<i32>(Second); |
898 | 0 | let Some(new_seconds) = seconds.checked_sub(1) else { |
899 | 0 | return Err(Overflow::Negative); |
900 | | }; |
901 | 0 | seconds = new_seconds; |
902 | 0 | } |
903 | | |
904 | | // Check if the resulting seconds are within the valid range |
905 | 0 | if seconds < Seconds::MIN.get() { |
906 | 0 | return Err(Overflow::Negative); |
907 | 0 | } else if seconds > Seconds::MAX.get() { |
908 | 0 | return Err(Overflow::Positive); |
909 | 0 | } |
910 | | |
911 | | // Safety: Both values are guaranteed to be in range. |
912 | 0 | Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds as u32) }) |
913 | 0 | } |
914 | | |
915 | | /// Checked addition of a [`SignedDuration`], returning `None` if the result is out of range. |
916 | | /// |
917 | | /// ```rust |
918 | | /// # use time_macros::timestamp; |
919 | | /// # use time::ext::NumericalDuration as _; |
920 | | /// assert_eq!( |
921 | | /// timestamp!(1_546_398_245).checked_add(1.days()), |
922 | | /// Some(timestamp!(1_546_484_645)) |
923 | | /// ); |
924 | | /// assert_eq!( |
925 | | /// timestamp!(1_546_398_245).checked_add((-1).days()), |
926 | | /// Some(timestamp!(1_546_311_845)) |
927 | | /// ); |
928 | | /// ``` |
929 | | #[inline] |
930 | 0 | pub const fn checked_add(self, duration: SignedDuration) -> Option<Self> { |
931 | 0 | match self.add(duration) { |
932 | 0 | Ok(timestamp) => Some(timestamp), |
933 | 0 | Err(Overflow::Positive | Overflow::Negative) => None, |
934 | | } |
935 | 0 | } |
936 | | |
937 | | /// Checked subtraction of a [`SignedDuration`], returning `None` if the result is out of range. |
938 | | /// |
939 | | /// ```rust |
940 | | /// # use time_macros::timestamp; |
941 | | /// # use time::ext::NumericalDuration as _; |
942 | | /// assert_eq!( |
943 | | /// timestamp!(1_546_398_245).checked_sub(1.days()), |
944 | | /// Some(timestamp!(1_546_311_845)) |
945 | | /// ); |
946 | | /// assert_eq!( |
947 | | /// timestamp!(1_546_398_245).checked_sub((-1).days()), |
948 | | /// Some(timestamp!(1_546_484_645)) |
949 | | /// ); |
950 | | /// ``` |
951 | | #[inline] |
952 | 0 | pub const fn checked_sub(self, duration: SignedDuration) -> Option<Self> { |
953 | 0 | match self.sub(duration) { |
954 | 0 | Ok(timestamp) => Some(timestamp), |
955 | 0 | Err(Overflow::Positive | Overflow::Negative) => None, |
956 | | } |
957 | 0 | } |
958 | | |
959 | | /// Saturating addition of a [`SignedDuration`]. |
960 | | /// |
961 | | /// Returns [`Timestamp::MAX`] or [`Timestamp::MIN`] if the result is out of range. |
962 | | /// |
963 | | /// ```rust |
964 | | /// # use time::Timestamp; |
965 | | /// # use time_macros::timestamp; |
966 | | /// # use time::ext::NumericalDuration as _; |
967 | | /// assert_eq!( |
968 | | /// timestamp!(1_546_398_245).saturating_add(1.days()), |
969 | | /// timestamp!(1_546_484_645) |
970 | | /// ); |
971 | | /// assert_eq!(Timestamp::MAX.saturating_add(1.days()), Timestamp::MAX); |
972 | | /// assert_eq!(Timestamp::MIN.saturating_add((-1).days()), Timestamp::MIN); |
973 | | /// ``` |
974 | | #[inline] |
975 | 0 | pub const fn saturating_add(self, duration: SignedDuration) -> Self { |
976 | 0 | match self.add(duration) { |
977 | 0 | Ok(timestamp) => timestamp, |
978 | 0 | Err(Overflow::Positive) => Self::MAX, |
979 | 0 | Err(Overflow::Negative) => Self::MIN, |
980 | | } |
981 | 0 | } |
982 | | |
983 | | /// Saturating subtraction of a [`SignedDuration`]. |
984 | | /// |
985 | | /// Returns [`Timestamp::MAX`] or [`Timestamp::MIN`] if the result is out of range. |
986 | | /// |
987 | | /// ```rust |
988 | | /// # use time::Timestamp; |
989 | | /// # use time_macros::timestamp; |
990 | | /// # use time::ext::NumericalDuration as _; |
991 | | /// assert_eq!( |
992 | | /// timestamp!(1_546_398_245).saturating_sub(1.days()), |
993 | | /// timestamp!(1_546_311_845) |
994 | | /// ); |
995 | | /// assert_eq!(Timestamp::MIN.saturating_sub(1.days()), Timestamp::MIN); |
996 | | /// assert_eq!(Timestamp::MAX.saturating_sub((-1).days()), Timestamp::MAX); |
997 | | /// ``` |
998 | | #[inline] |
999 | 0 | pub const fn saturating_sub(self, duration: SignedDuration) -> Self { |
1000 | 0 | match self.sub(duration) { |
1001 | 0 | Ok(timestamp) => timestamp, |
1002 | 0 | Err(Overflow::Positive) => Self::MAX, |
1003 | 0 | Err(Overflow::Negative) => Self::MIN, |
1004 | | } |
1005 | 0 | } |
1006 | | } |
1007 | | |
1008 | | /// Methods that replace part of the `Timestamp`. |
1009 | | impl Timestamp { |
1010 | | /// Replace the time, preserving the date. |
1011 | | /// |
1012 | | /// ```rust |
1013 | | /// # use time_macros::{time, timestamp}; |
1014 | | /// assert_eq!( |
1015 | | /// timestamp!(1_546_398_245).replace_time(time!(12:34:56)), |
1016 | | /// timestamp!(1_546_432_496) |
1017 | | /// ); |
1018 | | /// ``` |
1019 | | #[inline] |
1020 | | #[must_use = "This method does not mutate the original `Timestamp`."] |
1021 | 0 | pub const fn replace_time(self, time: Time) -> Self { |
1022 | 0 | let seconds_since_midnight = time.hour() as i64 * Second::per_t::<i64>(Hour) |
1023 | 0 | + time.minute() as i64 * Second::per_t::<i64>(Minute) |
1024 | 0 | + time.second() as i64; |
1025 | 0 | let seconds = div_floor!(self.seconds.get(), Second::per_t::<i64>(Day)) |
1026 | 0 | * Second::per_t::<i64>(Day) |
1027 | 0 | + seconds_since_midnight; |
1028 | | // Safety: Seconds is constructed from an existing valid value, and nanoseconds are always |
1029 | | // in range given the origin. Any time of day is valid for any date in range, as enforced by |
1030 | | // const assertions. |
1031 | 0 | unsafe { Self::__new_unchecked(seconds, time.nanosecond()) } |
1032 | 0 | } |
1033 | | |
1034 | | /// Replace the date, preserving the time. |
1035 | | /// |
1036 | | /// ```rust |
1037 | | /// # use time_macros::{date, timestamp}; |
1038 | | /// assert_eq!( |
1039 | | /// timestamp!(1_546_398_245).replace_date(date!(2020-01-02)), |
1040 | | /// timestamp!(1_577_934_245) |
1041 | | /// ); |
1042 | | /// ``` |
1043 | | #[inline] |
1044 | | #[must_use = "This method does not mutate the original `Timestamp`."] |
1045 | 0 | pub const fn replace_date(mut self, date: Date) -> Self { |
1046 | 0 | let seconds_after_midnight = self.seconds.get().rem_euclid(Second::per_t(Day)); |
1047 | 0 | let seconds = (date.to_julian_day() as i64 |
1048 | 0 | - UtcDateTime::UNIX_EPOCH.to_julian_day() as i64) |
1049 | 0 | * Second::per_t::<i64>(Day) |
1050 | 0 | + seconds_after_midnight; |
1051 | | // Safety: The range of valid dates is identical to the range of valid timestamps, so any |
1052 | | // date is necessarily valid. |
1053 | 0 | self.seconds = unsafe { Seconds::new_unchecked(seconds) }; |
1054 | 0 | self |
1055 | 0 | } |
1056 | | |
1057 | | /// Replace the year, preserving the month and day. If the date is February 29 and the resulting |
1058 | | /// year is not a leap year, an error is returned. |
1059 | | /// |
1060 | | /// ```rust |
1061 | | /// # use time_macros::timestamp; |
1062 | | /// assert_eq!( |
1063 | | /// timestamp!(1_546_398_245).replace_year(2020), |
1064 | | /// Ok(timestamp!(1_577_934_245)) |
1065 | | /// ); |
1066 | | /// assert!(timestamp!(1_546_398_245).replace_year(-1_000_000).is_err()); // -1_000_000 isn't a valid year |
1067 | | /// assert!(timestamp!(1_546_398_245).replace_year(1_000_000).is_err()); // 1_000_000 isn't a valid year |
1068 | | /// ``` |
1069 | | #[inline] |
1070 | | #[must_use = "This method does not mutate the original `Timestamp`."] |
1071 | 0 | pub const fn replace_year(self, year: i32) -> Result<Self, error::ComponentRange> { |
1072 | 0 | let date = const_try!(self.date().replace_year(year)); |
1073 | 0 | Ok(self.replace_date(date)) |
1074 | 0 | } |
1075 | | |
1076 | | /// Replace the month of the year, preserving the year and day. If the day is invalid for the |
1077 | | /// resulting month, an error is returned. |
1078 | | /// |
1079 | | /// ```rust |
1080 | | /// # use time_macros::timestamp; |
1081 | | /// # use time::Month; |
1082 | | /// assert_eq!( |
1083 | | /// timestamp!(1_546_398_245).replace_month(Month::February), |
1084 | | /// Ok(timestamp!(1_549_076_645)) |
1085 | | /// ); |
1086 | | /// assert!( |
1087 | | /// timestamp!(1_548_817_445) |
1088 | | /// .replace_month(Month::February) |
1089 | | /// .is_err() |
1090 | | /// ); // the day of the month is 30, which is invalid for February |
1091 | | /// ``` |
1092 | | #[inline] |
1093 | | #[must_use = "This method does not mutate the original `Timestamp`."] |
1094 | 0 | pub const fn replace_month(self, month: Month) -> Result<Self, error::ComponentRange> { |
1095 | 0 | let date = const_try!(self.date().replace_month(month)); |
1096 | 0 | Ok(self.replace_date(date)) |
1097 | 0 | } |
1098 | | |
1099 | | /// Replace the day of the month. |
1100 | | /// |
1101 | | /// ```rust |
1102 | | /// # use time_macros::timestamp; |
1103 | | /// assert_eq!( |
1104 | | /// timestamp!(1_546_398_245).replace_day(1), |
1105 | | /// Ok(timestamp!(1_546_311_845)) |
1106 | | /// ); |
1107 | | /// assert!(timestamp!(1_546_398_245).replace_day(0).is_err()); // 00 isn't a valid day |
1108 | | /// assert!(timestamp!(1_546_398_245).replace_day(32).is_err()); // 32 isn't a valid day |
1109 | | /// ``` |
1110 | | #[inline] |
1111 | | #[must_use = "This method does not mutate the original `Timestamp`."] |
1112 | 0 | pub const fn replace_day(self, day: u8) -> Result<Self, error::ComponentRange> { |
1113 | 0 | let date = const_try!(self.date().replace_day(day)); |
1114 | 0 | Ok(self.replace_date(date)) |
1115 | 0 | } |
1116 | | |
1117 | | /// Replace the day of the year. |
1118 | | /// |
1119 | | /// ```rust |
1120 | | /// # use time_macros::timestamp; |
1121 | | /// assert_eq!( |
1122 | | /// timestamp!(1_546_398_245).replace_ordinal(1), |
1123 | | /// Ok(timestamp!(1_546_311_845)) |
1124 | | /// ); |
1125 | | /// assert!(timestamp!(1_546_398_245).replace_ordinal(0).is_err()); // 0 isn't a valid day of the year |
1126 | | /// assert!(timestamp!(1_546_398_245).replace_ordinal(366).is_err()); // the timestamp is in 2019, which isn't a leap year |
1127 | | /// ``` |
1128 | | #[inline] |
1129 | | #[must_use = "This method does not mutate the original `Timestamp`."] |
1130 | 0 | pub const fn replace_ordinal(self, ordinal: u16) -> Result<Self, error::ComponentRange> { |
1131 | 0 | let date = const_try!(self.date().replace_ordinal(ordinal)); |
1132 | 0 | Ok(self.replace_date(date)) |
1133 | 0 | } |
1134 | | |
1135 | | /// Replace the clock hour. |
1136 | | /// |
1137 | | /// ```rust |
1138 | | /// # use time_macros::timestamp; |
1139 | | /// assert_eq!( |
1140 | | /// timestamp!(1_546_398_245).replace_hour(0), |
1141 | | /// Ok(timestamp!(1_546_387_445)) |
1142 | | /// ); |
1143 | | /// assert!(timestamp!(1_546_398_245).replace_hour(24).is_err()); // 24 isn't a valid hour |
1144 | | /// ``` |
1145 | | #[inline] |
1146 | | #[must_use = "This method does not mutate the original `Timestamp`."] |
1147 | 0 | pub const fn replace_hour(mut self, hour: u8) -> Result<Self, error::ComponentRange> { |
1148 | 0 | ensure_ranged!(ru8<0, 23>: hour); |
1149 | 0 | let seconds = div_floor!(self.seconds.get(), Second::per_t::<i64>(Day)) |
1150 | 0 | * Second::per_t::<i64>(Day) |
1151 | 0 | + hour as i64 * Second::per_t::<i64>(Hour) |
1152 | 0 | + self.minute() as i64 * Second::per_t::<i64>(Minute) |
1153 | 0 | + self.second() as i64; |
1154 | | // Safety: Any value is valid so long as `hour` is in range. |
1155 | 0 | self.seconds = unsafe { Seconds::new_unchecked(seconds) }; |
1156 | 0 | Ok(self) |
1157 | 0 | } |
1158 | | |
1159 | | /// Replace the minutes within the hour. |
1160 | | /// |
1161 | | /// ```rust |
1162 | | /// # use time_macros::timestamp; |
1163 | | /// assert_eq!( |
1164 | | /// timestamp!(1_546_398_245).replace_minute(0), |
1165 | | /// Ok(timestamp!(1_546_398_005)) |
1166 | | /// ); |
1167 | | /// assert!(timestamp!(1_546_398_245).replace_minute(60).is_err()); // 60 isn't a valid minute |
1168 | | /// ``` |
1169 | | #[inline] |
1170 | | #[must_use = "This method does not mutate the original `Timestamp`."] |
1171 | 0 | pub const fn replace_minute(mut self, minute: u8) -> Result<Self, error::ComponentRange> { |
1172 | 0 | ensure_ranged!(ru8<0, 59>: minute); |
1173 | 0 | let seconds = div_floor!(self.seconds.get(), Second::per_t::<i64>(Hour)) |
1174 | 0 | * Second::per_t::<i64>(Hour) |
1175 | 0 | + minute as i64 * Second::per_t::<i64>(Minute) |
1176 | 0 | + self.second() as i64; |
1177 | | // Safety: Any value is valid so long as `minute` is in range. |
1178 | 0 | self.seconds = unsafe { Seconds::new_unchecked(seconds) }; |
1179 | 0 | Ok(self) |
1180 | 0 | } |
1181 | | |
1182 | | /// Replace the seconds within the minute. |
1183 | | /// |
1184 | | /// ```rust |
1185 | | /// # use time_macros::timestamp; |
1186 | | /// assert_eq!( |
1187 | | /// timestamp!(1_546_398_245).replace_second(0), |
1188 | | /// Ok(timestamp!(1_546_398_240)) |
1189 | | /// ); |
1190 | | /// assert!(timestamp!(1_546_398_245).replace_second(60).is_err()); // 60 isn't a valid second |
1191 | | /// ``` |
1192 | | #[inline] |
1193 | | #[must_use = "This method does not mutate the original `Timestamp`."] |
1194 | 0 | pub const fn replace_second(mut self, second: u8) -> Result<Self, error::ComponentRange> { |
1195 | 0 | ensure_ranged!(ru8<0, 59>: second); |
1196 | 0 | let seconds = div_floor!(self.seconds.get(), Second::per_t::<i64>(Minute)) |
1197 | 0 | * Second::per_t::<i64>(Minute) |
1198 | 0 | + second as i64; |
1199 | | // Safety: Any value is valid so long as `second` is in range. |
1200 | 0 | self.seconds = unsafe { Seconds::new_unchecked(seconds) }; |
1201 | 0 | Ok(self) |
1202 | 0 | } |
1203 | | |
1204 | | /// Replace the milliseconds within the second. |
1205 | | /// |
1206 | | /// ```rust |
1207 | | /// # use time_macros::timestamp; |
1208 | | /// assert_eq!( |
1209 | | /// timestamp!(1_546_398_245.006).replace_millisecond(7), |
1210 | | /// Ok(timestamp!(1_546_398_245.007)) |
1211 | | /// ); |
1212 | | /// assert!( |
1213 | | /// timestamp!(1_546_398_245.006) |
1214 | | /// .replace_millisecond(1_000) |
1215 | | /// .is_err() |
1216 | | /// ); // 1_000 isn't a valid millisecond |
1217 | | /// ``` |
1218 | | #[inline] |
1219 | | #[must_use = "This method does not mutate the original `Timestamp`."] |
1220 | 0 | pub const fn replace_millisecond( |
1221 | 0 | self, |
1222 | 0 | millisecond: u16, |
1223 | 0 | ) -> Result<Self, error::ComponentRange> { |
1224 | 0 | let nanos = |
1225 | 0 | ensure_ranged!(Nanoseconds: millisecond as u32 * Nanosecond::per_t::<u32>(Millisecond)); |
1226 | 0 | Ok(self.replace_nanosecond_ranged(nanos)) |
1227 | 0 | } |
1228 | | |
1229 | | /// Replace the microseconds within the second. |
1230 | | /// |
1231 | | /// ```rust |
1232 | | /// # use time_macros::timestamp; |
1233 | | /// assert_eq!( |
1234 | | /// timestamp!(1_546_398_245.006_007).replace_microsecond(123_456), |
1235 | | /// Ok(timestamp!(1_546_398_245.123_456)) |
1236 | | /// ); |
1237 | | /// assert!( |
1238 | | /// timestamp!(1_546_398_245.006_007) |
1239 | | /// .replace_microsecond(1_000_000) |
1240 | | /// .is_err() |
1241 | | /// ); // 1_000_000 isn't a valid microsecond |
1242 | | /// ``` |
1243 | | #[inline] |
1244 | | #[must_use = "This method does not mutate the original `Timestamp`."] |
1245 | 0 | pub const fn replace_microsecond( |
1246 | 0 | self, |
1247 | 0 | microsecond: u32, |
1248 | 0 | ) -> Result<Self, error::ComponentRange> { |
1249 | 0 | let nanos = |
1250 | 0 | ensure_ranged!(Nanoseconds: microsecond * Nanosecond::per_t::<u32>(Microsecond)); |
1251 | 0 | Ok(self.replace_nanosecond_ranged(nanos)) |
1252 | 0 | } |
1253 | | |
1254 | | /// Replace the nanoseconds within the second. |
1255 | | /// |
1256 | | /// ```rust |
1257 | | /// # use time_macros::timestamp; |
1258 | | /// assert_eq!( |
1259 | | /// timestamp!(1_546_398_245.006_007_008).replace_nanosecond(123_456_789), |
1260 | | /// Ok(timestamp!(1_546_398_245.123_456_789)) |
1261 | | /// ); |
1262 | | /// assert!( |
1263 | | /// timestamp!(1_546_398_245.006_007_008) |
1264 | | /// .replace_nanosecond(1_000_000_000) |
1265 | | /// .is_err() |
1266 | | /// ); // 1_000_000_000 isn't a valid nanosecond |
1267 | | /// ``` |
1268 | | #[inline] |
1269 | | #[must_use = "This method does not mutate the original `Timestamp`."] |
1270 | 0 | pub const fn replace_nanosecond(self, nanosecond: u32) -> Result<Self, error::ComponentRange> { |
1271 | 0 | let nanos = ensure_ranged!(Nanoseconds: nanosecond); |
1272 | 0 | Ok(self.replace_nanosecond_ranged(nanos)) |
1273 | 0 | } |
1274 | | |
1275 | | /// Replace the nanoseconds within the second using a range-bounded integer to avoid range |
1276 | | /// checks. |
1277 | | #[inline] |
1278 | 0 | const fn replace_nanosecond_ranged(self, new_nanos: Nanoseconds) -> Self { |
1279 | 0 | let (seconds, nanoseconds) = self.as_parts_ranged(); |
1280 | | |
1281 | 0 | if seconds.get() >= 0 || nanoseconds.get() == 0 { |
1282 | 0 | Self::new_ranged(seconds, new_nanos) |
1283 | 0 | } else if new_nanos.get() == 0 { |
1284 | | // Safety: The previous conditional guarantees that `seconds` is negative (if it were |
1285 | | // non-negative, we wouldn't be in this branch). Given that the maximum value is |
1286 | | // positive, we can always add one without exceeding the maximum. |
1287 | 0 | Self::new_ranged(unsafe { seconds.unchecked_add(1) }, new_nanos) |
1288 | | } else { |
1289 | | // Safety: Given the range of `new_nanos`, subtracting it from the maximum always |
1290 | | // results in a value in range. Zero is excluded by a previous conditional. |
1291 | 0 | Self::new_ranged(seconds, unsafe { |
1292 | 0 | Nanoseconds::new_unchecked(Nanosecond::per_t::<u32>(Second) - new_nanos.get()) |
1293 | | }) |
1294 | | } |
1295 | 0 | } |
1296 | | } |
1297 | | |
1298 | | #[cfg(feature = "formatting")] |
1299 | | impl Timestamp { |
1300 | | /// Format the `Timestamp` using the provided [format description](crate::format_description). |
1301 | | #[inline] |
1302 | | pub fn format_into( |
1303 | | self, |
1304 | | output: &mut (impl io::Write + ?Sized), |
1305 | | format: &(impl Formattable + ?Sized), |
1306 | | ) -> Result<usize, error::Format> { |
1307 | | format.format_into(output, &self, &mut Default::default(), PrivateMethod) |
1308 | | } |
1309 | | |
1310 | | /// Format the `Timestamp` using the provided [format description](crate::format_description). |
1311 | | /// |
1312 | | /// ```rust |
1313 | | /// # use time_macros::{format_description, timestamp}; |
1314 | | /// let format = format_description!("[unix_timestamp]"); |
1315 | | /// assert_eq!(timestamp!(1_546_398_245).format(&format)?, "1546398245"); |
1316 | | /// # Ok::<_, time::Error>(()) |
1317 | | /// ``` |
1318 | | #[inline] |
1319 | | pub fn format(self, format: &(impl Formattable + ?Sized)) -> Result<String, error::Format> { |
1320 | | format.format(&self, &mut Default::default(), PrivateMethod) |
1321 | | } |
1322 | | } |
1323 | | |
1324 | | #[cfg(feature = "parsing")] |
1325 | | impl Timestamp { |
1326 | | /// Parse a `Timestamp` from the input using the provided [format |
1327 | | /// description](crate::format_description). |
1328 | | /// |
1329 | | /// ```rust |
1330 | | /// # use time::Timestamp; |
1331 | | /// # use time_macros::{format_description, timestamp}; |
1332 | | /// let format = format_description!("[unix_timestamp]"); |
1333 | | /// assert_eq!( |
1334 | | /// Timestamp::parse("1546398245", &format)?, |
1335 | | /// timestamp!(1_546_398_245), |
1336 | | /// ); |
1337 | | /// # Ok::<_, time::Error>(()) |
1338 | | /// ``` |
1339 | | #[inline] |
1340 | | pub fn parse( |
1341 | | input: &str, |
1342 | | description: &(impl Parsable + ?Sized), |
1343 | | ) -> Result<Self, error::Parse> { |
1344 | | description.parse_timestamp(input.as_bytes(), None, PrivateMethod) |
1345 | | } |
1346 | | |
1347 | | /// Parse a `Timestamp` from the input using the provided [format |
1348 | | /// description](crate::format_description) and default values. |
1349 | | /// |
1350 | | /// ```rust |
1351 | | /// # use time::Timestamp; |
1352 | | /// # use time::parsing::Parsed; |
1353 | | /// # use time_macros::{format_description, timestamp}; |
1354 | | /// let format = format_description!("[year]-[month]-[day]"); |
1355 | | /// let defaults = Parsed::new().with_hour_24(0).expect("0 is a valid hour"); |
1356 | | /// assert_eq!( |
1357 | | /// Timestamp::parse_with_defaults(b"2020-01-02", &format, defaults)?, |
1358 | | /// timestamp!(1_577_923_200) |
1359 | | /// ); |
1360 | | /// # Ok::<_, time::Error>(()) |
1361 | | /// ``` |
1362 | | #[inline] |
1363 | | pub fn parse_with_defaults( |
1364 | | input: &[u8], |
1365 | | description: &(impl Parsable + ?Sized), |
1366 | | defaults: Parsed, |
1367 | | ) -> Result<Self, error::Parse> { |
1368 | | description.parse_timestamp(input, Some(defaults), PrivateMethod) |
1369 | | } |
1370 | | } |
1371 | | |
1372 | | impl Timestamp { |
1373 | | /// The maximum number of bytes that the `fmt_into_buffer` method will write, which is also used |
1374 | | /// by the `Display` implementation. |
1375 | | const DISPLAY_BUFFER_SIZE: usize = 25; |
1376 | | |
1377 | | /// Format the `Timestamp` into the provided buffer, returning the number of bytes written. |
1378 | 0 | pub(crate) fn fmt_into_buffer( |
1379 | 0 | self, |
1380 | 0 | buf: &mut [MaybeUninit<u8>; Self::DISPLAY_BUFFER_SIZE], |
1381 | 0 | ) -> usize { |
1382 | 0 | let mut idx = 0; |
1383 | | |
1384 | 0 | let mut second = self.seconds.get(); |
1385 | 0 | let mut nanosecond = self.nanoseconds; |
1386 | | |
1387 | 0 | if second < 0 { |
1388 | 0 | buf[idx] = MaybeUninit::new(b'-'); |
1389 | 0 | idx += 1; |
1390 | | |
1391 | 0 | second = -second; |
1392 | | |
1393 | 0 | if nanosecond != Nanoseconds::new_static::<0>() { |
1394 | 0 | second -= 1; |
1395 | 0 | // Safety: `nanosecond` is in the range 1..=999_999_999, so subtracting it from |
1396 | 0 | // 1_000_000_000 will always yield a value in the range 1..=999_999_999, which is a |
1397 | 0 | // subset of the valid range for `Nanoseconds`. |
1398 | 0 | nanosecond = unsafe { |
1399 | 0 | Nanoseconds::new_unchecked(Nanosecond::per_t::<u32>(Second) - nanosecond.get()) |
1400 | 0 | }; |
1401 | 0 | } |
1402 | 0 | } |
1403 | | |
1404 | 0 | let seconds_str = u64_pad_none(second.cast_unsigned()); |
1405 | 0 | let seconds_len = seconds_str.len(); |
1406 | | // Safety: `buf` has sufficient capacity for the seconds digits. |
1407 | 0 | unsafe { |
1408 | 0 | seconds_str |
1409 | 0 | .as_ptr() |
1410 | 0 | .copy_to_nonoverlapping(buf.as_mut_ptr().add(idx).cast(), seconds_len); |
1411 | 0 | } |
1412 | 0 | idx += seconds_len; |
1413 | | |
1414 | 0 | if nanosecond != Nanoseconds::new_static::<0>() { |
1415 | 0 | buf[idx] = MaybeUninit::new(b'.'); |
1416 | 0 | idx += 1; |
1417 | 0 |
|
1418 | 0 | let subsecond = truncated_subsecond_from_nanos(nanosecond); |
1419 | 0 | // Safety: `buf` has sufficient capacity for the subsecond digits. |
1420 | 0 | unsafe { |
1421 | 0 | subsecond |
1422 | 0 | .as_ptr() |
1423 | 0 | .copy_to_nonoverlapping(buf.as_mut_ptr().add(idx).cast(), subsecond.len()); |
1424 | 0 | } |
1425 | 0 | idx += subsecond.len(); |
1426 | 0 | } |
1427 | | |
1428 | 0 | idx |
1429 | 0 | } |
1430 | | } |
1431 | | |
1432 | | impl fmt::Display for Timestamp { |
1433 | | #[inline] |
1434 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
1435 | 0 | let mut buf = [MaybeUninit::uninit(); Self::DISPLAY_BUFFER_SIZE]; |
1436 | 0 | let len = self.fmt_into_buffer(&mut buf); |
1437 | | // Safety: All bytes up to `len` have been initialized with ASCII characters. |
1438 | 0 | let s = unsafe { str_from_raw_parts(buf.as_ptr().cast(), len) }; |
1439 | 0 | f.pad(s) |
1440 | 0 | } |
1441 | | } |
1442 | | |
1443 | | impl fmt::Debug for Timestamp { |
1444 | | #[inline] |
1445 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
1446 | 0 | fmt::Display::fmt(self, f) |
1447 | 0 | } |
1448 | | } |
1449 | | |
1450 | | impl Add<SignedDuration> for Timestamp { |
1451 | | type Output = Self; |
1452 | | |
1453 | | /// # Panics |
1454 | | /// |
1455 | | /// This may panic if an overflow occurs. |
1456 | | #[inline] |
1457 | | #[track_caller] |
1458 | 0 | fn add(self, rhs: SignedDuration) -> Self::Output { |
1459 | 0 | self.checked_add(rhs) |
1460 | 0 | .expect("resulting value is out of range") |
1461 | 0 | } |
1462 | | } |
1463 | | |
1464 | | impl Add<StdDuration> for Timestamp { |
1465 | | type Output = Self; |
1466 | | |
1467 | | /// # Panics |
1468 | | /// |
1469 | | /// This may panic if an overflow occurs. |
1470 | | #[inline] |
1471 | | #[track_caller] |
1472 | 0 | fn add(self, rhs: StdDuration) -> Self::Output { |
1473 | 0 | self.add_std(rhs).expect("resulting value is out of range") |
1474 | 0 | } |
1475 | | } |
1476 | | |
1477 | | impl AddAssign<SignedDuration> for Timestamp { |
1478 | | /// # Panics |
1479 | | /// |
1480 | | /// This may panic if an overflow occurs. |
1481 | | #[inline] |
1482 | | #[track_caller] |
1483 | 0 | fn add_assign(&mut self, rhs: SignedDuration) { |
1484 | 0 | *self = *self + rhs; |
1485 | 0 | } |
1486 | | } |
1487 | | |
1488 | | impl AddAssign<StdDuration> for Timestamp { |
1489 | | /// # Panics |
1490 | | /// |
1491 | | /// This may panic if an overflow occurs. |
1492 | | #[inline] |
1493 | | #[track_caller] |
1494 | 0 | fn add_assign(&mut self, rhs: StdDuration) { |
1495 | 0 | *self = *self + rhs; |
1496 | 0 | } |
1497 | | } |
1498 | | |
1499 | | impl Sub<SignedDuration> for Timestamp { |
1500 | | type Output = Self; |
1501 | | |
1502 | | /// # Panics |
1503 | | /// |
1504 | | /// This may panic if an overflow occurs. |
1505 | | #[inline] |
1506 | | #[track_caller] |
1507 | 0 | fn sub(self, rhs: SignedDuration) -> Self::Output { |
1508 | 0 | self.checked_sub(rhs) |
1509 | 0 | .expect("resulting value is out of range") |
1510 | 0 | } |
1511 | | } |
1512 | | |
1513 | | impl Sub<StdDuration> for Timestamp { |
1514 | | type Output = Self; |
1515 | | |
1516 | | /// # Panics |
1517 | | /// |
1518 | | /// This may panic if an overflow occurs. |
1519 | | #[inline] |
1520 | | #[track_caller] |
1521 | 0 | fn sub(self, rhs: StdDuration) -> Self::Output { |
1522 | 0 | self.sub_std(rhs).expect("resulting value is out of range") |
1523 | 0 | } |
1524 | | } |
1525 | | |
1526 | | impl SubAssign<SignedDuration> for Timestamp { |
1527 | | /// # Panics |
1528 | | /// |
1529 | | /// This may panic if an overflow occurs. |
1530 | | #[inline] |
1531 | | #[track_caller] |
1532 | 0 | fn sub_assign(&mut self, rhs: SignedDuration) { |
1533 | 0 | *self = *self - rhs; |
1534 | 0 | } |
1535 | | } |
1536 | | |
1537 | | impl SubAssign<StdDuration> for Timestamp { |
1538 | | /// # Panics |
1539 | | /// |
1540 | | /// This may panic if an overflow occurs. |
1541 | | #[inline] |
1542 | | #[track_caller] |
1543 | 0 | fn sub_assign(&mut self, rhs: StdDuration) { |
1544 | 0 | *self = *self - rhs; |
1545 | 0 | } |
1546 | | } |
1547 | | |
1548 | | impl Sub for Timestamp { |
1549 | | type Output = SignedDuration; |
1550 | | |
1551 | | #[inline] |
1552 | 0 | fn sub(self, rhs: Self) -> Self::Output { |
1553 | 0 | let seconds = self.seconds.get() - rhs.seconds.get(); |
1554 | 0 | let nanoseconds = self.nanoseconds.get() as i32 - rhs.nanoseconds.get() as i32; |
1555 | | |
1556 | 0 | if nanoseconds < 0 { |
1557 | 0 | SignedDuration::new(seconds - 1, nanoseconds + Nanosecond::per_t::<i32>(Second)) |
1558 | | } else { |
1559 | 0 | SignedDuration::new(seconds, nanoseconds) |
1560 | | } |
1561 | 0 | } |
1562 | | } |