Coverage Report

Created: 2026-08-14 07:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/jiff-0.2.35/src/timestamp.rs
Line
Count
Source
1
use core::time::Duration as UnsignedDuration;
2
3
use jcore::Timestamp as JTimestamp;
4
5
use crate::{
6
    duration::{Duration, SDuration},
7
    error::{
8
        timestamp::Error as E, unit::UnitConfigError, Error, ErrorContext,
9
    },
10
    fmt::{
11
        self,
12
        temporal::{self, DEFAULT_DATETIME_PARSER},
13
    },
14
    tz::{Offset, TimeZone},
15
    util::{constant, round::Increment},
16
    zoned::Zoned,
17
    RoundMode, SignedDuration, Span, SpanRound, Unit,
18
};
19
20
/// An instant in time represented as the number of nanoseconds since the Unix
21
/// epoch.
22
///
23
/// A timestamp is always in the Unix timescale with a UTC offset of zero.
24
///
25
/// To obtain civil or "local" datetime units like year, month, day or hour, a
26
/// timestamp needs to be combined with a [`TimeZone`] to create a [`Zoned`].
27
/// That can be done with [`Timestamp::in_tz`] or [`Timestamp::to_zoned`].
28
///
29
/// The integer count of nanoseconds since the Unix epoch is signed, where
30
/// the Unix epoch is `1970-01-01 00:00:00Z`. A positive timestamp indicates
31
/// a point in time after the Unix epoch. A negative timestamp indicates a
32
/// point in time before the Unix epoch.
33
///
34
/// # Parsing and printing
35
///
36
/// The `Timestamp` type provides convenient trait implementations of
37
/// [`std::str::FromStr`] and [`std::fmt::Display`]:
38
///
39
/// ```
40
/// use jiff::Timestamp;
41
///
42
/// let ts: Timestamp = "2024-06-19 15:22:45-04".parse()?;
43
/// assert_eq!(ts.to_string(), "2024-06-19T19:22:45Z");
44
///
45
/// # Ok::<(), Box<dyn std::error::Error>>(())
46
/// ```
47
///
48
/// A `Timestamp` can also be parsed from something that _contains_ a
49
/// timestamp, but with perhaps other data (such as a time zone):
50
///
51
/// ```
52
/// use jiff::Timestamp;
53
///
54
/// let ts: Timestamp = "2024-06-19T15:22:45-04[America/New_York]".parse()?;
55
/// assert_eq!(ts.to_string(), "2024-06-19T19:22:45Z");
56
///
57
/// # Ok::<(), Box<dyn std::error::Error>>(())
58
/// ```
59
///
60
/// For more information on the specific format supported, see the
61
/// [`fmt::temporal`](crate::fmt::temporal) module documentation.
62
///
63
/// # Default value
64
///
65
/// For convenience, this type implements the `Default` trait. Its default
66
/// value corresponds to `1970-01-01T00:00:00.000000000`. That is, it is the
67
/// Unix epoch. One can also access this value via the `Timestamp::UNIX_EPOCH`
68
/// constant.
69
///
70
/// # Leap seconds
71
///
72
/// Jiff does not support leap seconds. Jiff behaves as if they don't exist.
73
/// The only exception is that if one parses a timestamp with a second
74
/// component of `60`, then it is automatically constrained to `59`:
75
///
76
/// ```
77
/// use jiff::Timestamp;
78
///
79
/// let ts: Timestamp = "2016-12-31 23:59:60Z".parse()?;
80
/// assert_eq!(ts.to_string(), "2016-12-31T23:59:59Z");
81
///
82
/// # Ok::<(), Box<dyn std::error::Error>>(())
83
/// ```
84
///
85
/// # Comparisons
86
///
87
/// The `Timestamp` type provides both `Eq` and `Ord` trait implementations
88
/// to facilitate easy comparisons. When a timestamp `ts1` occurs before a
89
/// timestamp `ts2`, then `dt1 < dt2`. For example:
90
///
91
/// ```
92
/// use jiff::Timestamp;
93
///
94
/// let ts1 = Timestamp::from_second(123_456_789)?;
95
/// let ts2 = Timestamp::from_second(123_456_790)?;
96
/// assert!(ts1 < ts2);
97
///
98
/// # Ok::<(), Box<dyn std::error::Error>>(())
99
/// ```
100
///
101
/// # Arithmetic
102
///
103
/// This type provides routines for adding and subtracting spans of time, as
104
/// well as computing the span of time between two `Timestamp` values.
105
///
106
/// For adding or subtracting spans of time, one can use any of the following
107
/// routines:
108
///
109
/// * [`Timestamp::checked_add`] or [`Timestamp::checked_sub`] for checked
110
/// arithmetic.
111
/// * [`Timestamp::saturating_add`] or [`Timestamp::saturating_sub`] for
112
/// saturating arithmetic.
113
///
114
/// Additionally, checked arithmetic is available via the `Add` and `Sub`
115
/// trait implementations. When the result overflows, a panic occurs.
116
///
117
/// ```
118
/// use jiff::{Timestamp, ToSpan};
119
///
120
/// let ts1: Timestamp = "2024-02-25T15:45Z".parse()?;
121
/// let ts2 = ts1 - 24.hours();
122
/// assert_eq!(ts2.to_string(), "2024-02-24T15:45:00Z");
123
///
124
/// # Ok::<(), Box<dyn std::error::Error>>(())
125
/// ```
126
///
127
/// One can compute the span of time between two timestamps using either
128
/// [`Timestamp::until`] or [`Timestamp::since`]. It's also possible to
129
/// subtract two `Timestamp` values directly via a `Sub` trait implementation:
130
///
131
/// ```
132
/// use jiff::{Timestamp, ToSpan};
133
///
134
/// let ts1: Timestamp = "2024-05-03 23:30:00.123Z".parse()?;
135
/// let ts2: Timestamp = "2024-02-25 07Z".parse()?;
136
/// // The default is to return spans with units no bigger than seconds.
137
/// assert_eq!(ts1 - ts2, 5934600.seconds().milliseconds(123).fieldwise());
138
///
139
/// # Ok::<(), Box<dyn std::error::Error>>(())
140
/// ```
141
///
142
/// The `until` and `since` APIs are polymorphic and allow re-balancing and
143
/// rounding the span returned. For example, the default largest unit is
144
/// seconds (as exemplified above), but we can ask for bigger units (up to
145
/// hours):
146
///
147
/// ```
148
/// use jiff::{Timestamp, ToSpan, Unit};
149
///
150
/// let ts1: Timestamp = "2024-05-03 23:30:00.123Z".parse()?;
151
/// let ts2: Timestamp = "2024-02-25 07Z".parse()?;
152
/// assert_eq!(
153
///     // If you want to deal in units bigger than hours, then you'll have to
154
///     // convert your timestamp to a [`Zoned`] first.
155
///     ts1.since((Unit::Hour, ts2))?,
156
///     1648.hours().minutes(30).milliseconds(123).fieldwise(),
157
/// );
158
///
159
/// # Ok::<(), Box<dyn std::error::Error>>(())
160
/// ```
161
///
162
/// You can also round the span returned:
163
///
164
/// ```
165
/// use jiff::{RoundMode, Timestamp, TimestampDifference, ToSpan, Unit};
166
///
167
/// let ts1: Timestamp = "2024-05-03 23:30:59.123Z".parse()?;
168
/// let ts2: Timestamp = "2024-05-02 07Z".parse()?;
169
/// assert_eq!(
170
///     ts1.since(
171
///         TimestampDifference::new(ts2)
172
///             .smallest(Unit::Minute)
173
///             .largest(Unit::Hour),
174
///     )?,
175
///     40.hours().minutes(30).fieldwise(),
176
/// );
177
/// // `TimestampDifference` uses truncation as a rounding mode by default,
178
/// // but you can set the rounding mode to break ties away from zero:
179
/// assert_eq!(
180
///     ts1.since(
181
///         TimestampDifference::new(ts2)
182
///             .smallest(Unit::Minute)
183
///             .largest(Unit::Hour)
184
///             .mode(RoundMode::HalfExpand),
185
///     )?,
186
///     // Rounds up to 31 minutes.
187
///     40.hours().minutes(31).fieldwise(),
188
/// );
189
///
190
/// # Ok::<(), Box<dyn std::error::Error>>(())
191
/// ```
192
///
193
/// # Rounding timestamps
194
///
195
/// A `Timestamp` can be rounded based on a [`TimestampRound`] configuration of
196
/// smallest units, rounding increment and rounding mode. Here's an example
197
/// showing how to round to the nearest third hour:
198
///
199
/// ```
200
/// use jiff::{Timestamp, TimestampRound, Unit};
201
///
202
/// let ts: Timestamp = "2024-06-19 16:27:29.999999999Z".parse()?;
203
/// assert_eq!(
204
///     ts.round(TimestampRound::new().smallest(Unit::Hour).increment(3))?,
205
///     "2024-06-19 15Z".parse::<Timestamp>()?,
206
/// );
207
/// // Or alternatively, make use of the `From<(Unit, i64)> for TimestampRound`
208
/// // trait implementation:
209
/// assert_eq!(
210
///     ts.round((Unit::Hour, 3))?.to_string(),
211
///     "2024-06-19T15:00:00Z",
212
/// );
213
///
214
/// # Ok::<(), Box<dyn std::error::Error>>(())
215
/// ```
216
///
217
/// See [`Timestamp::round`] for more details.
218
///
219
/// # An instant in time
220
///
221
/// Unlike a [`civil::DateTime`](crate::civil::DateTime), a `Timestamp`
222
/// _always_ corresponds, unambiguously, to a precise instant in time (to
223
/// nanosecond precision). This means that attaching a time zone to a timestamp
224
/// is always unambiguous because there's never any question as to which
225
/// instant it refers to. This is true even for gaps in civil time.
226
///
227
/// For example, in `America/New_York`, clocks were moved ahead one hour
228
/// at clock time `2024-03-10 02:00:00`. That is, the 2 o'clock hour never
229
/// appeared on clocks in the `America/New_York` region. Since parsing a
230
/// timestamp always requires an offset, the time it refers to is unambiguous.
231
/// We can see this by writing a clock time, `02:30`, that never existed but
232
/// with two different offsets:
233
///
234
/// ```
235
/// use jiff::Timestamp;
236
///
237
/// // All we're doing here is attaching an offset to a civil datetime.
238
/// // There is no time zone information here, and thus there is no
239
/// // accounting for ambiguity due to daylight saving time transitions.
240
/// let before_hour_jump: Timestamp = "2024-03-10 02:30-04".parse()?;
241
/// let after_hour_jump: Timestamp = "2024-03-10 02:30-05".parse()?;
242
/// // This shows the instant in time in UTC.
243
/// assert_eq!(before_hour_jump.to_string(), "2024-03-10T06:30:00Z");
244
/// assert_eq!(after_hour_jump.to_string(), "2024-03-10T07:30:00Z");
245
///
246
/// // Now let's attach each instant to an `America/New_York` time zone.
247
/// let zdt_before = before_hour_jump.in_tz("America/New_York")?;
248
/// let zdt_after = after_hour_jump.in_tz("America/New_York")?;
249
/// // And now we can see that even though the original instant refers to
250
/// // the 2 o'clock hour, since that hour never existed on the clocks in
251
/// // `America/New_York`, an instant with a time zone correctly adjusts.
252
/// assert_eq!(
253
///     zdt_before.to_string(),
254
///     "2024-03-10T01:30:00-05:00[America/New_York]",
255
/// );
256
/// assert_eq!(
257
///     zdt_after.to_string(),
258
///     "2024-03-10T03:30:00-04:00[America/New_York]",
259
/// );
260
///
261
/// # Ok::<(), Box<dyn std::error::Error>>(())
262
/// ```
263
///
264
/// In the example above, there is never a step that is incorrect or has an
265
/// alternative answer. Every step is unambiguous because we never involve
266
/// any [`civil`](crate::civil) datetimes.
267
///
268
/// But note that if the datetime string you're parsing from lacks an offset,
269
/// then it *could* be ambiguous even if a time zone is specified. In this
270
/// case, parsing will always fail:
271
///
272
/// ```
273
/// use jiff::Timestamp;
274
///
275
/// let result = "2024-06-30 08:30[America/New_York]".parse::<Timestamp>();
276
/// assert_eq!(
277
///     result.unwrap_err().to_string(),
278
///     "failed to find offset component, \
279
///      which is required for parsing a timestamp",
280
/// );
281
/// ```
282
///
283
/// # Converting a civil datetime to a timestamp
284
///
285
/// Sometimes you want to convert the "time on the clock" to a precise instant
286
/// in time. One way to do this was demonstrated in the previous section, but
287
/// it only works if you know your current time zone offset:
288
///
289
/// ```
290
/// use jiff::Timestamp;
291
///
292
/// let ts: Timestamp = "2024-06-30 08:36-04".parse()?;
293
/// assert_eq!(ts.to_string(), "2024-06-30T12:36:00Z");
294
///
295
/// # Ok::<(), Box<dyn std::error::Error>>(())
296
/// ```
297
///
298
/// The above happened to be the precise instant in time I wrote the example.
299
/// Since I happened to know the offset, this worked okay. But what if I
300
/// didn't? We could instead construct a civil datetime and attach a time zone
301
/// to it. This will create a [`Zoned`] value, from which we can access the
302
/// timestamp:
303
///
304
/// ```
305
/// use jiff::civil::date;
306
///
307
/// let clock = date(2024, 6, 30).at(8, 36, 0, 0).in_tz("America/New_York")?;
308
/// assert_eq!(clock.timestamp().to_string(), "2024-06-30T12:36:00Z");
309
///
310
/// # Ok::<(), Box<dyn std::error::Error>>(())
311
/// ```
312
#[derive(Clone, Copy)]
313
pub struct Timestamp {
314
    dur: JTimestamp,
315
}
316
317
impl Timestamp {
318
    /// The minimum representable timestamp.
319
    ///
320
    /// The minimum is chosen such that it can be combined with
321
    /// any legal [`Offset`](crate::tz::Offset) and turned into a
322
    /// [`civil::DateTime`](crate::civil::DateTime).
323
    ///
324
    /// # Example
325
    ///
326
    /// ```
327
    /// use jiff::{civil::date, tz::Offset, Timestamp};
328
    ///
329
    /// let dt = Offset::MIN.to_datetime(Timestamp::MIN);
330
    /// assert_eq!(dt, date(-9999, 1, 1).at(0, 0, 0, 0));
331
    /// ```
332
    pub const MIN: Timestamp = Timestamp { dur: JTimestamp::MIN };
333
334
    /// The maximum representable timestamp.
335
    ///
336
    /// The maximum is chosen such that it can be combined with
337
    /// any legal [`Offset`](crate::tz::Offset) and turned into a
338
    /// [`civil::DateTime`](crate::civil::DateTime).
339
    ///
340
    /// # Example
341
    ///
342
    /// ```
343
    /// use jiff::{civil::date, tz::Offset, Timestamp};
344
    ///
345
    /// let dt = Offset::MAX.to_datetime(Timestamp::MAX);
346
    /// assert_eq!(dt, date(9999, 12, 31).at(23, 59, 59, 999_999_999));
347
    /// ```
348
    pub const MAX: Timestamp = Timestamp { dur: JTimestamp::MAX };
349
350
    /// The Unix epoch represented as a timestamp.
351
    ///
352
    /// The Unix epoch corresponds to the instant at `1970-01-01T00:00:00Z`.
353
    /// As a timestamp, it corresponds to `0` nanoseconds.
354
    ///
355
    /// A timestamp is positive if and only if it is greater than the Unix
356
    /// epoch. A timestamp is negative if and only if it is less than the Unix
357
    /// epoch.
358
    pub const UNIX_EPOCH: Timestamp =
359
        Timestamp { dur: JTimestamp::UNIX_EPOCH };
360
361
    /// Returns the current system time as a timestamp.
362
    ///
363
    /// # Panics
364
    ///
365
    /// This panics if the system clock is set to a time value outside of the
366
    /// range `-009999-01-01T00:00:00Z..=9999-12-31T11:59:59.999999999Z`. The
367
    /// justification here is that it is reasonable to expect the system clock
368
    /// to be set to a somewhat sane, if imprecise, value.
369
    ///
370
    /// If you want to get the current Unix time fallibly, use
371
    /// [`Timestamp::try_from`] with a `std::time::SystemTime` as input.
372
    ///
373
    /// This may also panic when `SystemTime::now()` itself panics. The most
374
    /// common context in which this happens is on the `wasm32-unknown-unknown`
375
    /// target. If you're using that target in the context of the web (for
376
    /// example, via `wasm-pack`), and you're an application, then you should
377
    /// enable Jiff's `js` feature. This will automatically instruct Jiff in
378
    /// this very specific circumstance to execute JavaScript code to determine
379
    /// the current time from the web browser.
380
    ///
381
    /// # Example
382
    ///
383
    /// ```
384
    /// use jiff::Timestamp;
385
    ///
386
    /// assert!(Timestamp::now() > Timestamp::UNIX_EPOCH);
387
    /// ```
388
    #[cfg(feature = "std")]
389
0
    pub fn now() -> Timestamp {
390
0
        Timestamp::try_from(crate::now::system_time())
391
0
            .expect("system time is valid")
392
0
    }
393
394
    /// Creates a new instant in time represented as a timestamp.
395
    ///
396
    /// While a timestamp is logically a count of nanoseconds since the Unix
397
    /// epoch, this constructor provides a convenience way of constructing
398
    /// the timestamp from two components: seconds and fractional seconds
399
    /// expressed as nanoseconds.
400
    ///
401
    /// The signs of `second` and `nanosecond` need not be the same.
402
    ///
403
    /// # Errors
404
    ///
405
    /// This returns an error if the given components would correspond to
406
    /// an instant outside the supported range. Also, `nanosecond` is limited
407
    /// to the range `-999,999,999..=999,999,999`.
408
    ///
409
    /// # Example
410
    ///
411
    /// This example shows the instant in time 123,456,789 seconds after the
412
    /// Unix epoch:
413
    ///
414
    /// ```
415
    /// use jiff::Timestamp;
416
    ///
417
    /// assert_eq!(
418
    ///     Timestamp::new(123_456_789, 0)?.to_string(),
419
    ///     "1973-11-29T21:33:09Z",
420
    /// );
421
    ///
422
    /// # Ok::<(), Box<dyn std::error::Error>>(())
423
    /// ```
424
    ///
425
    /// # Example: normalized sign
426
    ///
427
    /// This example shows how `second` and `nanosecond` are resolved when
428
    /// their signs differ.
429
    ///
430
    /// ```
431
    /// use jiff::Timestamp;
432
    ///
433
    /// let ts = Timestamp::new(2, -999_999_999)?;
434
    /// assert_eq!(ts.as_second(), 1);
435
    /// assert_eq!(ts.subsec_nanosecond(), 1);
436
    ///
437
    /// let ts = Timestamp::new(-2, 999_999_999)?;
438
    /// assert_eq!(ts.as_second(), -1);
439
    /// assert_eq!(ts.subsec_nanosecond(), -1);
440
    ///
441
    /// # Ok::<(), Box<dyn std::error::Error>>(())
442
    /// ```
443
    ///
444
    /// # Example: limits
445
    ///
446
    /// The minimum timestamp has nanoseconds set to zero, while the maximum
447
    /// timestamp has nanoseconds set to `999,999,999`:
448
    ///
449
    /// ```
450
    /// use jiff::Timestamp;
451
    ///
452
    /// assert_eq!(Timestamp::MIN.subsec_nanosecond(), 0);
453
    /// assert_eq!(Timestamp::MAX.subsec_nanosecond(), 999_999_999);
454
    /// ```
455
    ///
456
    /// As a consequence, nanoseconds cannot be negative when a timestamp has
457
    /// minimal seconds:
458
    ///
459
    /// ```
460
    /// use jiff::Timestamp;
461
    ///
462
    /// assert!(Timestamp::new(Timestamp::MIN.as_second(), -1).is_err());
463
    /// // But they can be positive!
464
    /// let one_ns_more = Timestamp::new(Timestamp::MIN.as_second(), 1)?;
465
    /// assert_eq!(
466
    ///     one_ns_more.to_string(),
467
    ///     "-009999-01-02T01:59:59.000000001Z",
468
    /// );
469
    /// // Or, when combined with a minimal offset:
470
    /// assert_eq!(
471
    ///     jiff::tz::Offset::MIN.to_datetime(one_ns_more).to_string(),
472
    ///     "-009999-01-01T00:00:00.000000001",
473
    /// );
474
    ///
475
    /// # Ok::<(), Box<dyn std::error::Error>>(())
476
    /// ```
477
    #[inline]
478
72.2k
    pub fn new(second: i64, nanosecond: i32) -> Result<Timestamp, Error> {
479
72.2k
        let dur =
480
72.2k
            JTimestamp::new(second, nanosecond).map_err(Error::jcore_range)?;
481
72.2k
        Ok(Timestamp { dur })
482
72.2k
    }
Unexecuted instantiation: <jiff::timestamp::Timestamp>::new
Unexecuted instantiation: <jiff::timestamp::Timestamp>::new
<jiff::timestamp::Timestamp>::new
Line
Count
Source
478
72.2k
    pub fn new(second: i64, nanosecond: i32) -> Result<Timestamp, Error> {
479
72.2k
        let dur =
480
72.2k
            JTimestamp::new(second, nanosecond).map_err(Error::jcore_range)?;
481
72.2k
        Ok(Timestamp { dur })
482
72.2k
    }
<jiff::timestamp::Timestamp>::new
Line
Count
Source
478
6
    pub fn new(second: i64, nanosecond: i32) -> Result<Timestamp, Error> {
479
6
        let dur =
480
6
            JTimestamp::new(second, nanosecond).map_err(Error::jcore_range)?;
481
6
        Ok(Timestamp { dur })
482
6
    }
483
484
    /// Creates a new `Timestamp` value in a `const` context.
485
    ///
486
    /// # Panics
487
    ///
488
    /// This routine panics when [`Timestamp::new`] would return an error.
489
    /// That is, when the given components would correspond to
490
    /// an instant outside the supported range. Also, `nanosecond` is limited
491
    /// to the range `-999,999,999..=999,999,999`.
492
    ///
493
    /// # Example
494
    ///
495
    /// This example shows the instant in time 123,456,789 seconds after the
496
    /// Unix epoch:
497
    ///
498
    /// ```
499
    /// use jiff::Timestamp;
500
    ///
501
    /// assert_eq!(
502
    ///     Timestamp::constant(123_456_789, 0).to_string(),
503
    ///     "1973-11-29T21:33:09Z",
504
    /// );
505
    /// ```
506
    #[inline]
507
0
    pub const fn constant(second: i64, nanosecond: i32) -> Timestamp {
508
0
        let dur = constant::unwrapr!(
509
0
            JTimestamp::new(second, nanosecond),
510
0
            "invalid timestamp"
511
        );
512
0
        Timestamp { dur }
513
0
    }
514
515
    /// Creates a new instant in time from the number of seconds elapsed since
516
    /// the Unix epoch.
517
    ///
518
    /// When `second` is negative, it corresponds to an instant in time before
519
    /// the Unix epoch. A smaller number corresponds to an instant in time
520
    /// further into the past.
521
    ///
522
    /// # Errors
523
    ///
524
    /// This returns an error if the given second corresponds to a timestamp
525
    /// outside of the [`Timestamp::MIN`] and [`Timestamp::MAX`] boundaries.
526
    ///
527
    /// It is a semver guarantee that the only way for this to return an error
528
    /// is if the given value is out of range. That is, when it is less than
529
    /// `Timestamp::MIN` or greater than `Timestamp::MAX`.
530
    ///
531
    /// # Example
532
    ///
533
    /// This example shows the instants in time 1 second immediately after and
534
    /// before the Unix epoch:
535
    ///
536
    /// ```
537
    /// use jiff::Timestamp;
538
    ///
539
    /// assert_eq!(
540
    ///     Timestamp::from_second(1)?.to_string(),
541
    ///     "1970-01-01T00:00:01Z",
542
    /// );
543
    /// assert_eq!(
544
    ///     Timestamp::from_second(-1)?.to_string(),
545
    ///     "1969-12-31T23:59:59Z",
546
    /// );
547
    ///
548
    /// # Ok::<(), Box<dyn std::error::Error>>(())
549
    /// ```
550
    ///
551
    /// # Example: saturating construction
552
    ///
553
    /// If you need a way to build a `Timestamp` value that saturates to
554
    /// the minimum and maximum values supported by Jiff, then this is
555
    /// guaranteed to work:
556
    ///
557
    /// ```
558
    /// use jiff::Timestamp;
559
    ///
560
    /// fn from_second_saturating(seconds: i64) -> Timestamp {
561
    ///     Timestamp::from_second(seconds).unwrap_or_else(|_| {
562
    ///         if seconds < 0 {
563
    ///             Timestamp::MIN
564
    ///         } else {
565
    ///             Timestamp::MAX
566
    ///         }
567
    ///     })
568
    /// }
569
    ///
570
    /// assert_eq!(from_second_saturating(0), Timestamp::UNIX_EPOCH);
571
    /// assert_eq!(
572
    ///     from_second_saturating(-999999999999999999),
573
    ///     Timestamp::MIN
574
    /// );
575
    /// assert_eq!(
576
    ///     from_second_saturating(999999999999999999),
577
    ///     Timestamp::MAX
578
    /// );
579
    /// ```
580
    #[inline]
581
0
    pub fn from_second(second: i64) -> Result<Timestamp, Error> {
582
0
        JTimestamp::from_second(second)
583
0
            .map(|dur| Timestamp { dur })
584
0
            .map_err(Error::jcore_range)
585
0
    }
Unexecuted instantiation: <jiff::timestamp::Timestamp>::from_second
Unexecuted instantiation: <jiff::timestamp::Timestamp>::from_second
586
587
    /// Creates a new instant in time from the number of milliseconds elapsed
588
    /// since the Unix epoch.
589
    ///
590
    /// When `millisecond` is negative, it corresponds to an instant in time
591
    /// before the Unix epoch. A smaller number corresponds to an instant in
592
    /// time further into the past.
593
    ///
594
    /// # Errors
595
    ///
596
    /// This returns an error if the given millisecond corresponds to a
597
    /// timestamp outside of the [`Timestamp::MIN`] and [`Timestamp::MAX`]
598
    /// boundaries.
599
    ///
600
    /// It is a semver guarantee that the only way for this to return an error
601
    /// is if the given value is out of range. That is, when it is less than
602
    /// `Timestamp::MIN` or greater than `Timestamp::MAX`.
603
    ///
604
    /// # Example
605
    ///
606
    /// This example shows the instants in time 1 millisecond immediately after
607
    /// and before the Unix epoch:
608
    ///
609
    /// ```
610
    /// use jiff::Timestamp;
611
    ///
612
    /// assert_eq!(
613
    ///     Timestamp::from_millisecond(1)?.to_string(),
614
    ///     "1970-01-01T00:00:00.001Z",
615
    /// );
616
    /// assert_eq!(
617
    ///     Timestamp::from_millisecond(-1)?.to_string(),
618
    ///     "1969-12-31T23:59:59.999Z",
619
    /// );
620
    ///
621
    /// # Ok::<(), Box<dyn std::error::Error>>(())
622
    /// ```
623
    ///
624
    /// # Example: saturating construction
625
    ///
626
    /// If you need a way to build a `Timestamp` value that saturates to
627
    /// the minimum and maximum values supported by Jiff, then this is
628
    /// guaranteed to work:
629
    ///
630
    /// ```
631
    /// use jiff::Timestamp;
632
    ///
633
    /// fn from_millisecond_saturating(millis: i64) -> Timestamp {
634
    ///     Timestamp::from_millisecond(millis).unwrap_or_else(|_| {
635
    ///         if millis < 0 {
636
    ///             Timestamp::MIN
637
    ///         } else {
638
    ///             Timestamp::MAX
639
    ///         }
640
    ///     })
641
    /// }
642
    ///
643
    /// assert_eq!(from_millisecond_saturating(0), Timestamp::UNIX_EPOCH);
644
    /// assert_eq!(
645
    ///     from_millisecond_saturating(-999999999999999999),
646
    ///     Timestamp::MIN
647
    /// );
648
    /// assert_eq!(
649
    ///     from_millisecond_saturating(999999999999999999),
650
    ///     Timestamp::MAX
651
    /// );
652
    /// ```
653
    #[inline]
654
0
    pub fn from_millisecond(millisecond: i64) -> Result<Timestamp, Error> {
655
0
        JTimestamp::from_millisecond(millisecond)
656
0
            .map(|dur| Timestamp { dur })
Unexecuted instantiation: <jiff::timestamp::Timestamp>::from_millisecond::{closure#0}
Unexecuted instantiation: <jiff::timestamp::Timestamp>::from_millisecond::{closure#0}
657
0
            .map_err(Error::jcore_range)
658
0
    }
Unexecuted instantiation: <jiff::timestamp::Timestamp>::from_millisecond
Unexecuted instantiation: <jiff::timestamp::Timestamp>::from_millisecond
659
660
    /// Creates a new instant in time from the number of microseconds elapsed
661
    /// since the Unix epoch.
662
    ///
663
    /// When `microsecond` is negative, it corresponds to an instant in time
664
    /// before the Unix epoch. A smaller number corresponds to an instant in
665
    /// time further into the past.
666
    ///
667
    /// # Errors
668
    ///
669
    /// This returns an error if the given microsecond corresponds to a
670
    /// timestamp outside of the [`Timestamp::MIN`] and [`Timestamp::MAX`]
671
    /// boundaries.
672
    ///
673
    /// It is a semver guarantee that the only way for this to return an error
674
    /// is if the given value is out of range. That is, when it is less than
675
    /// `Timestamp::MIN` or greater than `Timestamp::MAX`.
676
    ///
677
    /// # Example
678
    ///
679
    /// This example shows the instants in time 1 microsecond immediately after
680
    /// and before the Unix epoch:
681
    ///
682
    /// ```
683
    /// use jiff::Timestamp;
684
    ///
685
    /// assert_eq!(
686
    ///     Timestamp::from_microsecond(1)?.to_string(),
687
    ///     "1970-01-01T00:00:00.000001Z",
688
    /// );
689
    /// assert_eq!(
690
    ///     Timestamp::from_microsecond(-1)?.to_string(),
691
    ///     "1969-12-31T23:59:59.999999Z",
692
    /// );
693
    ///
694
    /// # Ok::<(), Box<dyn std::error::Error>>(())
695
    /// ```
696
    ///
697
    /// # Example: saturating construction
698
    ///
699
    /// If you need a way to build a `Timestamp` value that saturates to
700
    /// the minimum and maximum values supported by Jiff, then this is
701
    /// guaranteed to work:
702
    ///
703
    /// ```
704
    /// use jiff::Timestamp;
705
    ///
706
    /// fn from_microsecond_saturating(micros: i64) -> Timestamp {
707
    ///     Timestamp::from_microsecond(micros).unwrap_or_else(|_| {
708
    ///         if micros < 0 {
709
    ///             Timestamp::MIN
710
    ///         } else {
711
    ///             Timestamp::MAX
712
    ///         }
713
    ///     })
714
    /// }
715
    ///
716
    /// assert_eq!(from_microsecond_saturating(0), Timestamp::UNIX_EPOCH);
717
    /// assert_eq!(
718
    ///     from_microsecond_saturating(-999999999999999999),
719
    ///     Timestamp::MIN
720
    /// );
721
    /// assert_eq!(
722
    ///     from_microsecond_saturating(999999999999999999),
723
    ///     Timestamp::MAX
724
    /// );
725
    /// ```
726
    #[inline]
727
0
    pub fn from_microsecond(microsecond: i64) -> Result<Timestamp, Error> {
728
0
        JTimestamp::from_microsecond(microsecond)
729
0
            .map(|dur| Timestamp { dur })
730
0
            .map_err(Error::jcore_range)
731
0
    }
732
733
    /// Creates a new instant in time from the number of nanoseconds elapsed
734
    /// since the Unix epoch.
735
    ///
736
    /// When `nanosecond` is negative, it corresponds to an instant in time
737
    /// before the Unix epoch. A smaller number corresponds to an instant in
738
    /// time further into the past.
739
    ///
740
    /// # Errors
741
    ///
742
    /// This returns an error if the given nanosecond corresponds to a
743
    /// timestamp outside of the [`Timestamp::MIN`] and [`Timestamp::MAX`]
744
    /// boundaries.
745
    ///
746
    /// It is a semver guarantee that the only way for this to return an error
747
    /// is if the given value is out of range. That is, when it is less than
748
    /// `Timestamp::MIN` or greater than `Timestamp::MAX`.
749
    ///
750
    /// # Example
751
    ///
752
    /// This example shows the instants in time 1 nanosecond immediately after
753
    /// and before the Unix epoch:
754
    ///
755
    /// ```
756
    /// use jiff::Timestamp;
757
    ///
758
    /// assert_eq!(
759
    ///     Timestamp::from_nanosecond(1)?.to_string(),
760
    ///     "1970-01-01T00:00:00.000000001Z",
761
    /// );
762
    /// assert_eq!(
763
    ///     Timestamp::from_nanosecond(-1)?.to_string(),
764
    ///     "1969-12-31T23:59:59.999999999Z",
765
    /// );
766
    ///
767
    /// # Ok::<(), Box<dyn std::error::Error>>(())
768
    /// ```
769
    ///
770
    /// # Example: saturating construction
771
    ///
772
    /// If you need a way to build a `Timestamp` value that saturates to
773
    /// the minimum and maximum values supported by Jiff, then this is
774
    /// guaranteed to work:
775
    ///
776
    /// ```
777
    /// use jiff::Timestamp;
778
    ///
779
    /// fn from_nanosecond_saturating(nanos: i128) -> Timestamp {
780
    ///     Timestamp::from_nanosecond(nanos).unwrap_or_else(|_| {
781
    ///         if nanos < 0 {
782
    ///             Timestamp::MIN
783
    ///         } else {
784
    ///             Timestamp::MAX
785
    ///         }
786
    ///     })
787
    /// }
788
    ///
789
    /// assert_eq!(from_nanosecond_saturating(0), Timestamp::UNIX_EPOCH);
790
    /// assert_eq!(
791
    ///     from_nanosecond_saturating(-9999999999999999999999999999999999),
792
    ///     Timestamp::MIN
793
    /// );
794
    /// assert_eq!(
795
    ///     from_nanosecond_saturating(9999999999999999999999999999999999),
796
    ///     Timestamp::MAX
797
    /// );
798
    /// ```
799
    #[inline]
800
0
    pub fn from_nanosecond(nanosecond: i128) -> Result<Timestamp, Error> {
801
0
        JTimestamp::from_nanosecond(nanosecond)
802
0
            .map(|dur| Timestamp { dur })
803
0
            .map_err(Error::jcore_range)
804
0
    }
805
806
    /// Creates a new timestamp from a `Duration` with the given sign since the
807
    /// Unix epoch.
808
    ///
809
    /// Positive durations result in a timestamp after the Unix epoch. Negative
810
    /// durations result in a timestamp before the Unix epoch.
811
    ///
812
    /// # Errors
813
    ///
814
    /// This returns an error if the given duration corresponds to a timestamp
815
    /// outside of the [`Timestamp::MIN`] and [`Timestamp::MAX`] boundaries.
816
    ///
817
    /// It is a semver guarantee that the only way for this to return an error
818
    /// is if the given value is out of range. That is, when it is less than
819
    /// `Timestamp::MIN` or greater than `Timestamp::MAX`.
820
    ///
821
    /// # Example
822
    ///
823
    /// How one might construct a `Timestamp` from a `SystemTime`:
824
    ///
825
    /// ```
826
    /// use std::time::SystemTime;
827
    /// use jiff::{SignedDuration, Timestamp};
828
    ///
829
    /// let unix_epoch = SystemTime::UNIX_EPOCH;
830
    /// let now = SystemTime::now();
831
    /// let duration = SignedDuration::system_until(unix_epoch, now)?;
832
    /// let ts = Timestamp::from_duration(duration)?;
833
    /// assert!(ts > Timestamp::UNIX_EPOCH);
834
    ///
835
    /// # Ok::<(), Box<dyn std::error::Error>>(())
836
    /// ```
837
    ///
838
    /// Of course, one should just use [`Timestamp::try_from`] for this
839
    /// instead. Indeed, the above example is copied almost exactly from the
840
    /// `TryFrom` implementation.
841
    ///
842
    /// # Example: out of bounds
843
    ///
844
    /// This example shows how some of the boundary conditions are dealt with.
845
    ///
846
    /// ```
847
    /// use jiff::{SignedDuration, Timestamp};
848
    ///
849
    /// // OK, we get the minimum timestamp supported by Jiff:
850
    /// let duration = SignedDuration::new(-377705023201, 0);
851
    /// let ts = Timestamp::from_duration(duration)?;
852
    /// assert_eq!(ts, Timestamp::MIN);
853
    ///
854
    /// // We use the minimum number of seconds, but even subtracting
855
    /// // one more nanosecond after it will result in an error.
856
    /// let duration = SignedDuration::new(-377705023201, -1);
857
    /// assert_eq!(
858
    ///     Timestamp::from_duration(duration).unwrap_err().to_string(),
859
    ///     "parameter 'Unix timestamp seconds' is not in \
860
    ///      the required range of -377705023201..=253402207200",
861
    /// );
862
    ///
863
    /// # Ok::<(), Box<dyn std::error::Error>>(())
864
    /// ```
865
    ///
866
    /// # Example: saturating construction
867
    ///
868
    /// If you need a way to build a `Timestamp` value that saturates to
869
    /// the minimum and maximum values supported by Jiff, then this is
870
    /// guaranteed to work:
871
    ///
872
    /// ```
873
    /// use jiff::{SignedDuration, Timestamp};
874
    ///
875
    /// fn from_duration_saturating(dur: SignedDuration) -> Timestamp {
876
    ///     Timestamp::from_duration(dur).unwrap_or_else(|_| {
877
    ///         if dur.is_negative() {
878
    ///             Timestamp::MIN
879
    ///         } else {
880
    ///             Timestamp::MAX
881
    ///         }
882
    ///     })
883
    /// }
884
    ///
885
    /// assert_eq!(
886
    ///     from_duration_saturating(SignedDuration::ZERO),
887
    ///     Timestamp::UNIX_EPOCH,
888
    /// );
889
    /// assert_eq!(
890
    ///     from_duration_saturating(SignedDuration::from_secs(-999999999999)),
891
    ///     Timestamp::MIN
892
    /// );
893
    /// assert_eq!(
894
    ///     from_duration_saturating(SignedDuration::from_secs(999999999999)),
895
    ///     Timestamp::MAX
896
    /// );
897
    /// ```
898
    #[inline]
899
72.2k
    pub fn from_duration(
900
72.2k
        duration: SignedDuration,
901
72.2k
    ) -> Result<Timestamp, Error> {
902
        // N.B. We could do less work here since we know the signed duration
903
        // is well formed (i.e., `|nanos| < 1 second` is always true).
904
72.2k
        Timestamp::new(duration.as_secs(), duration.subsec_nanos())
905
72.2k
    }
Unexecuted instantiation: <jiff::timestamp::Timestamp>::from_duration
Unexecuted instantiation: <jiff::timestamp::Timestamp>::from_duration
<jiff::timestamp::Timestamp>::from_duration
Line
Count
Source
899
72.2k
    pub fn from_duration(
900
72.2k
        duration: SignedDuration,
901
72.2k
    ) -> Result<Timestamp, Error> {
902
        // N.B. We could do less work here since we know the signed duration
903
        // is well formed (i.e., `|nanos| < 1 second` is always true).
904
72.2k
        Timestamp::new(duration.as_secs(), duration.subsec_nanos())
905
72.2k
    }
<jiff::timestamp::Timestamp>::from_duration
Line
Count
Source
899
6
    pub fn from_duration(
900
6
        duration: SignedDuration,
901
6
    ) -> Result<Timestamp, Error> {
902
        // N.B. We could do less work here since we know the signed duration
903
        // is well formed (i.e., `|nanos| < 1 second` is always true).
904
6
        Timestamp::new(duration.as_secs(), duration.subsec_nanos())
905
6
    }
906
907
    /// Returns this timestamp as a number of seconds since the Unix epoch.
908
    ///
909
    /// This only returns the number of whole seconds. That is, if there are
910
    /// any fractional seconds in this timestamp, then they are truncated.
911
    ///
912
    /// # Example
913
    ///
914
    /// ```
915
    /// use jiff::Timestamp;
916
    ///
917
    /// let ts = Timestamp::new(5, 123_456_789)?;
918
    /// assert_eq!(ts.as_second(), 5);
919
    /// let ts = Timestamp::new(5, 999_999_999)?;
920
    /// assert_eq!(ts.as_second(), 5);
921
    ///
922
    /// let ts = Timestamp::new(-5, -123_456_789)?;
923
    /// assert_eq!(ts.as_second(), -5);
924
    /// let ts = Timestamp::new(-5, -999_999_999)?;
925
    /// assert_eq!(ts.as_second(), -5);
926
    ///
927
    /// # Ok::<(), Box<dyn std::error::Error>>(())
928
    /// ```
929
    #[inline]
930
0
    pub fn as_second(self) -> i64 {
931
0
        self.dur.as_second()
932
0
    }
933
934
    /// Returns this timestamp as a number of milliseconds since the Unix
935
    /// epoch.
936
    ///
937
    /// This only returns the number of whole milliseconds. That is, if there
938
    /// are any fractional milliseconds in this timestamp, then they are
939
    /// truncated.
940
    ///
941
    /// # Example
942
    ///
943
    /// ```
944
    /// use jiff::Timestamp;
945
    ///
946
    /// let ts = Timestamp::new(5, 123_456_789)?;
947
    /// assert_eq!(ts.as_millisecond(), 5_123);
948
    /// let ts = Timestamp::new(5, 999_999_999)?;
949
    /// assert_eq!(ts.as_millisecond(), 5_999);
950
    ///
951
    /// let ts = Timestamp::new(-5, -123_456_789)?;
952
    /// assert_eq!(ts.as_millisecond(), -5_123);
953
    /// let ts = Timestamp::new(-5, -999_999_999)?;
954
    /// assert_eq!(ts.as_millisecond(), -5_999);
955
    ///
956
    /// # Ok::<(), Box<dyn std::error::Error>>(())
957
    /// ```
958
    #[inline]
959
0
    pub fn as_millisecond(self) -> i64 {
960
0
        self.dur.as_millisecond()
961
0
    }
Unexecuted instantiation: <jiff::timestamp::Timestamp>::as_millisecond
Unexecuted instantiation: <jiff::timestamp::Timestamp>::as_millisecond
962
963
    /// Returns this timestamp as a number of microseconds since the Unix
964
    /// epoch.
965
    ///
966
    /// This only returns the number of whole microseconds. That is, if there
967
    /// are any fractional microseconds in this timestamp, then they are
968
    /// truncated.
969
    ///
970
    /// # Example
971
    ///
972
    /// ```
973
    /// use jiff::Timestamp;
974
    ///
975
    /// let ts = Timestamp::new(5, 123_456_789)?;
976
    /// assert_eq!(ts.as_microsecond(), 5_123_456);
977
    /// let ts = Timestamp::new(5, 999_999_999)?;
978
    /// assert_eq!(ts.as_microsecond(), 5_999_999);
979
    ///
980
    /// let ts = Timestamp::new(-5, -123_456_789)?;
981
    /// assert_eq!(ts.as_microsecond(), -5_123_456);
982
    /// let ts = Timestamp::new(-5, -999_999_999)?;
983
    /// assert_eq!(ts.as_microsecond(), -5_999_999);
984
    ///
985
    /// # Ok::<(), Box<dyn std::error::Error>>(())
986
    /// ```
987
    #[inline]
988
0
    pub fn as_microsecond(self) -> i64 {
989
0
        self.dur.as_microsecond()
990
0
    }
991
992
    /// Returns this timestamp as a number of nanoseconds since the Unix
993
    /// epoch.
994
    ///
995
    /// Since a `Timestamp` has a nanosecond precision, the nanoseconds
996
    /// returned here represent this timestamp losslessly. That is, the
997
    /// nanoseconds returned can be used with [`Timestamp::from_nanosecond`] to
998
    /// create an identical timestamp with no loss of precision.
999
    ///
1000
    /// # Example
1001
    ///
1002
    /// ```
1003
    /// use jiff::Timestamp;
1004
    ///
1005
    /// let ts = Timestamp::new(5, 123_456_789)?;
1006
    /// assert_eq!(ts.as_nanosecond(), 5_123_456_789);
1007
    /// let ts = Timestamp::new(5, 999_999_999)?;
1008
    /// assert_eq!(ts.as_nanosecond(), 5_999_999_999);
1009
    ///
1010
    /// let ts = Timestamp::new(-5, -123_456_789)?;
1011
    /// assert_eq!(ts.as_nanosecond(), -5_123_456_789);
1012
    /// let ts = Timestamp::new(-5, -999_999_999)?;
1013
    /// assert_eq!(ts.as_nanosecond(), -5_999_999_999);
1014
    ///
1015
    /// # Ok::<(), Box<dyn std::error::Error>>(())
1016
    /// ```
1017
    #[inline]
1018
0
    pub fn as_nanosecond(self) -> i128 {
1019
0
        self.dur.as_nanosecond()
1020
0
    }
1021
1022
    /// Returns the fractional second component of this timestamp in units
1023
    /// of milliseconds.
1024
    ///
1025
    /// It is guaranteed that this will never return a value that is greater
1026
    /// than 1 second (or less than -1 second).
1027
    ///
1028
    /// This only returns the number of whole milliseconds. That is, if there
1029
    /// are any fractional milliseconds in this timestamp, then they are
1030
    /// truncated.
1031
    ///
1032
    /// # Example
1033
    ///
1034
    /// ```
1035
    /// use jiff::Timestamp;
1036
    ///
1037
    /// let ts = Timestamp::new(5, 123_456_789)?;
1038
    /// assert_eq!(ts.subsec_millisecond(), 123);
1039
    /// let ts = Timestamp::new(5, 999_999_999)?;
1040
    /// assert_eq!(ts.subsec_millisecond(), 999);
1041
    ///
1042
    /// let ts = Timestamp::new(-5, -123_456_789)?;
1043
    /// assert_eq!(ts.subsec_millisecond(), -123);
1044
    /// let ts = Timestamp::new(-5, -999_999_999)?;
1045
    /// assert_eq!(ts.subsec_millisecond(), -999);
1046
    ///
1047
    /// # Ok::<(), Box<dyn std::error::Error>>(())
1048
    /// ```
1049
    #[inline]
1050
0
    pub fn subsec_millisecond(self) -> i32 {
1051
0
        self.dur.subsec_millisecond()
1052
0
    }
1053
1054
    /// Returns the fractional second component of this timestamp in units of
1055
    /// microseconds.
1056
    ///
1057
    /// It is guaranteed that this will never return a value that is greater
1058
    /// than 1 second (or less than -1 second).
1059
    ///
1060
    /// This only returns the number of whole microseconds. That is, if there
1061
    /// are any fractional microseconds in this timestamp, then they are
1062
    /// truncated.
1063
    ///
1064
    /// # Example
1065
    ///
1066
    /// ```
1067
    /// use jiff::Timestamp;
1068
    ///
1069
    /// let ts = Timestamp::new(5, 123_456_789)?;
1070
    /// assert_eq!(ts.subsec_microsecond(), 123_456);
1071
    /// let ts = Timestamp::new(5, 999_999_999)?;
1072
    /// assert_eq!(ts.subsec_microsecond(), 999_999);
1073
    ///
1074
    /// let ts = Timestamp::new(-5, -123_456_789)?;
1075
    /// assert_eq!(ts.subsec_microsecond(), -123_456);
1076
    /// let ts = Timestamp::new(-5, -999_999_999)?;
1077
    /// assert_eq!(ts.subsec_microsecond(), -999_999);
1078
    ///
1079
    /// # Ok::<(), Box<dyn std::error::Error>>(())
1080
    /// ```
1081
    #[inline]
1082
0
    pub fn subsec_microsecond(self) -> i32 {
1083
0
        self.dur.subsec_microsecond()
1084
0
    }
1085
1086
    /// Returns the fractional second component of this timestamp in units of
1087
    /// nanoseconds.
1088
    ///
1089
    /// It is guaranteed that this will never return a value that is greater
1090
    /// than 1 second (or less than -1 second).
1091
    ///
1092
    /// # Example
1093
    ///
1094
    /// ```
1095
    /// use jiff::Timestamp;
1096
    ///
1097
    /// let ts = Timestamp::new(5, 123_456_789)?;
1098
    /// assert_eq!(ts.subsec_nanosecond(), 123_456_789);
1099
    /// let ts = Timestamp::new(5, 999_999_999)?;
1100
    /// assert_eq!(ts.subsec_nanosecond(), 999_999_999);
1101
    ///
1102
    /// let ts = Timestamp::new(-5, -123_456_789)?;
1103
    /// assert_eq!(ts.subsec_nanosecond(), -123_456_789);
1104
    /// let ts = Timestamp::new(-5, -999_999_999)?;
1105
    /// assert_eq!(ts.subsec_nanosecond(), -999_999_999);
1106
    ///
1107
    /// # Ok::<(), Box<dyn std::error::Error>>(())
1108
    /// ```
1109
    #[inline]
1110
0
    pub fn subsec_nanosecond(self) -> i32 {
1111
0
        self.dur.subsec_nanosecond()
1112
0
    }
Unexecuted instantiation: <jiff::timestamp::Timestamp>::subsec_nanosecond
Unexecuted instantiation: <jiff::timestamp::Timestamp>::subsec_nanosecond
1113
1114
    /// Returns this timestamp as a [`SignedDuration`] since the Unix epoch.
1115
    ///
1116
    /// # Example
1117
    ///
1118
    /// ```
1119
    /// use jiff::{SignedDuration, Timestamp};
1120
    ///
1121
    /// assert_eq!(
1122
    ///     Timestamp::UNIX_EPOCH.as_duration(),
1123
    ///     SignedDuration::ZERO,
1124
    /// );
1125
    /// assert_eq!(
1126
    ///     Timestamp::new(5, 123_456_789)?.as_duration(),
1127
    ///     SignedDuration::new(5, 123_456_789),
1128
    /// );
1129
    /// assert_eq!(
1130
    ///     Timestamp::new(-5, -123_456_789)?.as_duration(),
1131
    ///     SignedDuration::new(-5, -123_456_789),
1132
    /// );
1133
    ///
1134
    /// # Ok::<(), Box<dyn std::error::Error>>(())
1135
    /// ```
1136
    #[inline]
1137
0
    pub fn as_duration(self) -> SignedDuration {
1138
        // OK because a `Timestamp` has a strictly smaller range than a duration,
1139
        // _and_ because we know `|nanos| < 1` as well.
1140
0
        SignedDuration::new_unchecked(
1141
0
            self.dur.as_second(),
1142
0
            self.dur.subsec_nanosecond(),
1143
        )
1144
0
    }
Unexecuted instantiation: <jiff::timestamp::Timestamp>::as_duration
Unexecuted instantiation: <jiff::timestamp::Timestamp>::as_duration
1145
1146
    /// Returns the sign of this timestamp.
1147
    ///
1148
    /// This can return one of three possible values:
1149
    ///
1150
    /// * `0` when this timestamp is precisely equivalent to
1151
    /// [`Timestamp::UNIX_EPOCH`].
1152
    /// * `1` when this timestamp occurs after the Unix epoch.
1153
    /// * `-1` when this timestamp occurs before the Unix epoch.
1154
    ///
1155
    /// The sign returned is guaranteed to match the sign of all "getter"
1156
    /// methods on `Timestamp`. For example, [`Timestamp::as_second`] and
1157
    /// [`Timestamp::subsec_nanosecond`]. This is true even if the signs
1158
    /// of the `second` and `nanosecond` components were mixed when given to
1159
    /// the [`Timestamp::new`] constructor.
1160
    ///
1161
    /// # Example
1162
    ///
1163
    /// ```
1164
    /// use jiff::Timestamp;
1165
    ///
1166
    /// let ts = Timestamp::new(5, -999_999_999)?;
1167
    /// assert_eq!(ts.signum(), 1);
1168
    /// // The mixed signs were normalized away!
1169
    /// assert_eq!(ts.as_second(), 4);
1170
    /// assert_eq!(ts.subsec_nanosecond(), 1);
1171
    ///
1172
    /// // The same applies for negative timestamps.
1173
    /// let ts = Timestamp::new(-5, 999_999_999)?;
1174
    /// assert_eq!(ts.signum(), -1);
1175
    /// assert_eq!(ts.as_second(), -4);
1176
    /// assert_eq!(ts.subsec_nanosecond(), -1);
1177
    ///
1178
    /// # Ok::<(), Box<dyn std::error::Error>>(())
1179
    /// ```
1180
    #[inline]
1181
0
    pub fn signum(self) -> i8 {
1182
0
        self.dur.signum()
1183
0
    }
1184
1185
    /// Returns true if and only if this timestamp corresponds to the instant
1186
    /// in time known as the Unix epoch.
1187
    ///
1188
    /// # Example
1189
    ///
1190
    /// ```
1191
    /// use jiff::Timestamp;
1192
    ///
1193
    /// assert!(Timestamp::UNIX_EPOCH.is_zero());
1194
    /// ```
1195
    #[inline]
1196
0
    pub fn is_zero(self) -> bool {
1197
0
        self.dur.is_zero()
1198
0
    }
1199
1200
    /// Creates a [`Zoned`] value by attaching a time zone for the given name
1201
    /// to this instant in time.
1202
    ///
1203
    /// The name given is resolved to a [`TimeZone`] by using the default
1204
    /// [`TimeZoneDatabase`](crate::tz::TimeZoneDatabase) created by
1205
    /// [`tz::db`](crate::tz::db). Indeed, this is a convenience function
1206
    /// for [`Timestamp::to_zoned`] where the time zone database lookup
1207
    /// is done automatically.
1208
    ///
1209
    /// Assuming the time zone name could be resolved to a [`TimeZone`], this
1210
    /// routine is otherwise infallible and never results in any ambiguity
1211
    /// since both a [`Timestamp`] and a [`Zoned`] correspond to precise
1212
    /// instant in time. This is unlike
1213
    /// [`civil::DateTime::to_zoned`](crate::civil::DateTime::to_zoned),
1214
    /// where a civil datetime might correspond to more than one instant in
1215
    /// time (i.e., a fold, typically DST ending) or no instants in time (i.e.,
1216
    /// a gap, typically DST starting).
1217
    ///
1218
    /// # Errors
1219
    ///
1220
    /// This returns an error when the given time zone name could not be found
1221
    /// in the default time zone database.
1222
    ///
1223
    /// # Example
1224
    ///
1225
    /// This is a simple example of converting the instant that is `123,456,789`
1226
    /// seconds after the Unix epoch to an instant that is aware of its time
1227
    /// zone:
1228
    ///
1229
    /// ```
1230
    /// use jiff::Timestamp;
1231
    ///
1232
    /// let ts = Timestamp::new(123_456_789, 0).unwrap();
1233
    /// let zdt = ts.in_tz("America/New_York")?;
1234
    /// assert_eq!(zdt.to_string(), "1973-11-29T16:33:09-05:00[America/New_York]");
1235
    ///
1236
    /// # Ok::<(), Box<dyn std::error::Error>>(())
1237
    /// ```
1238
    ///
1239
    /// This can be used to answer questions like, "What time was it at the
1240
    /// Unix epoch in Tasmania?"
1241
    ///
1242
    /// ```
1243
    /// use jiff::Timestamp;
1244
    ///
1245
    /// // Time zone database lookups are case insensitive!
1246
    /// let zdt = Timestamp::UNIX_EPOCH.in_tz("australia/tasmania")?;
1247
    /// assert_eq!(zdt.to_string(), "1970-01-01T11:00:00+11:00[Australia/Tasmania]");
1248
    ///
1249
    /// # Ok::<(), Box<dyn std::error::Error>>(())
1250
    /// ```
1251
    ///
1252
    /// # Example: errors
1253
    ///
1254
    /// This routine can return an error when the time zone is unrecognized:
1255
    ///
1256
    /// ```
1257
    /// use jiff::Timestamp;
1258
    ///
1259
    /// assert!(Timestamp::UNIX_EPOCH.in_tz("does not exist").is_err());
1260
    /// ```
1261
    #[inline]
1262
0
    pub fn in_tz(self, time_zone_name: &str) -> Result<Zoned, Error> {
1263
0
        let tz = crate::tz::db().get(time_zone_name)?;
1264
0
        Ok(self.to_zoned(tz))
1265
0
    }
1266
1267
    /// Creates a [`Zoned`] value by attaching the given time zone to this
1268
    /// instant in time.
1269
    ///
1270
    /// This is infallible and never results in any ambiguity since both a
1271
    /// [`Timestamp`] and a [`Zoned`] correspond to precise instant in time.
1272
    /// This is unlike
1273
    /// [`civil::DateTime::to_zoned`](crate::civil::DateTime::to_zoned),
1274
    /// where a civil datetime might correspond to more than one instant in
1275
    /// time (i.e., a fold, typically DST ending) or no instants in time (i.e.,
1276
    /// a gap, typically DST starting).
1277
    ///
1278
    /// In the common case of a time zone being represented as a name string,
1279
    /// like `Australia/Tasmania`, consider using [`Timestamp::in_tz`]
1280
    /// instead.
1281
    ///
1282
    /// # Example
1283
    ///
1284
    /// This example shows how to create a zoned value with a fixed time zone
1285
    /// offset:
1286
    ///
1287
    /// ```
1288
    /// use jiff::{tz::{self, TimeZone}, Timestamp};
1289
    ///
1290
    /// let ts = Timestamp::new(123_456_789, 0).unwrap();
1291
    /// let tz = TimeZone::fixed(tz::offset(-4));
1292
    /// let zdt = ts.to_zoned(tz);
1293
    /// // A time zone annotation is still included in the printable version
1294
    /// // of the Zoned value, but it is fixed to a particular offset.
1295
    /// assert_eq!(zdt.to_string(), "1973-11-29T17:33:09-04:00[-04:00]");
1296
    /// ```
1297
    ///
1298
    /// # Example: POSIX time zone strings
1299
    ///
1300
    /// This example shows how to create a time zone from a POSIX time zone
1301
    /// string that describes the transition to and from daylight saving
1302
    /// time for `America/St_Johns`. In particular, this rule uses non-zero
1303
    /// minutes, which is atypical.
1304
    ///
1305
    /// ```
1306
    /// use jiff::{tz::TimeZone, Timestamp};
1307
    ///
1308
    /// let ts = Timestamp::new(123_456_789, 0)?;
1309
    /// let tz = TimeZone::posix("NST3:30NDT,M3.2.0,M11.1.0")?;
1310
    /// let zdt = ts.to_zoned(tz);
1311
    /// // There isn't any agreed upon mechanism for transmitting a POSIX time
1312
    /// // zone string within an RFC 9557 TZ annotation, so Jiff just emits the
1313
    /// // offset. In practice, POSIX TZ strings are rarely user facing anyway.
1314
    /// // (They are still in widespread use as an implementation detail of the
1315
    /// // IANA Time Zone Database however.)
1316
    /// assert_eq!(zdt.to_string(), "1973-11-29T18:03:09-03:30[-03:30]");
1317
    ///
1318
    /// # Ok::<(), Box<dyn std::error::Error>>(())
1319
    /// ```
1320
    #[inline]
1321
0
    pub fn to_zoned(self, tz: TimeZone) -> Zoned {
1322
0
        Zoned::new(self, tz)
1323
0
    }
Unexecuted instantiation: <jiff::timestamp::Timestamp>::to_zoned
Unexecuted instantiation: <jiff::timestamp::Timestamp>::to_zoned
1324
1325
    /// Add the given span of time to this timestamp.
1326
    ///
1327
    /// This operation accepts three different duration types: [`Span`],
1328
    /// [`SignedDuration`] or [`std::time::Duration`]. This is achieved via
1329
    /// `From` trait implementations for the [`TimestampArithmetic`] type.
1330
    ///
1331
    /// # Properties
1332
    ///
1333
    /// Given a timestamp `ts1` and a span `s`, and assuming `ts2 = ts1 + s`
1334
    /// exists, it follows then that `ts1 = ts2 - s` for all values of `ts1`
1335
    /// and `s` that sum to a valid `ts2`.
1336
    ///
1337
    /// In short, subtracting the given span from the sum returned by this
1338
    /// function is guaranteed to result in precisely the original timestamp.
1339
    ///
1340
    /// # Errors
1341
    ///
1342
    /// If the sum would overflow the minimum or maximum timestamp values, then
1343
    /// an error is returned.
1344
    ///
1345
    /// This also returns an error if the given duration is a `Span` with any
1346
    /// non-zero units greater than hours. If you want to use bigger units,
1347
    /// convert this timestamp to a `Zoned` and use [`Zoned::checked_add`].
1348
    /// This error occurs because a `Timestamp` has no time zone attached to
1349
    /// it, and thus cannot unambiguously resolve the length of a single day.
1350
    ///
1351
    /// # Example
1352
    ///
1353
    /// This shows how to add `5` hours to the Unix epoch:
1354
    ///
1355
    /// ```
1356
    /// use jiff::{Timestamp, ToSpan};
1357
    ///
1358
    /// let ts = Timestamp::UNIX_EPOCH.checked_add(5.hours())?;
1359
    /// assert_eq!(ts.to_string(), "1970-01-01T05:00:00Z");
1360
    ///
1361
    /// # Ok::<(), Box<dyn std::error::Error>>(())
1362
    /// ```
1363
    ///
1364
    /// # Example: negative spans are supported
1365
    ///
1366
    /// This shows how to add `-5` hours to the Unix epoch. This is the same
1367
    /// as subtracting `5` hours from the Unix epoch.
1368
    ///
1369
    /// ```
1370
    /// use jiff::{Timestamp, ToSpan};
1371
    ///
1372
    /// let ts = Timestamp::UNIX_EPOCH.checked_add(-5.hours())?;
1373
    /// assert_eq!(ts.to_string(), "1969-12-31T19:00:00Z");
1374
    ///
1375
    /// # Ok::<(), Box<dyn std::error::Error>>(())
1376
    /// ```
1377
    ///
1378
    /// # Example: available via addition operator
1379
    ///
1380
    /// This routine can be used via the `+` operator. Note though that if it
1381
    /// fails, it will result in a panic.
1382
    ///
1383
    /// ```
1384
    /// use jiff::{Timestamp, ToSpan};
1385
    ///
1386
    /// let ts1 = Timestamp::new(2_999_999_999, 0)?;
1387
    /// assert_eq!(ts1.to_string(), "2065-01-24T05:19:59Z");
1388
    ///
1389
    /// let ts2 = ts1 + 1.hour().minutes(30).nanoseconds(123);
1390
    /// assert_eq!(ts2.to_string(), "2065-01-24T06:49:59.000000123Z");
1391
    ///
1392
    /// # Ok::<(), Box<dyn std::error::Error>>(())
1393
    /// ```
1394
    ///
1395
    /// # Example: error on overflow
1396
    ///
1397
    /// ```
1398
    /// use jiff::{Timestamp, ToSpan};
1399
    ///
1400
    /// let ts = Timestamp::MAX;
1401
    /// assert_eq!(ts.to_string(), "9999-12-30T22:00:00.999999999Z");
1402
    /// assert!(ts.checked_add(1.second()).is_err());
1403
    /// assert!(ts.checked_add(1.nanosecond()).is_err());
1404
    /// assert!(ts.checked_add(
1405
    ///     175_307_616.hours().minutes(10_518_456_960i64).seconds(631_107_417_600i64),
1406
    /// ).is_err());
1407
    ///
1408
    /// let ts = Timestamp::MIN;
1409
    /// assert_eq!(ts.to_string(), "-009999-01-02T01:59:59Z");
1410
    /// assert!(ts.checked_add(-1.second()).is_err());
1411
    /// assert!(ts.checked_add(-1.nanosecond()).is_err());
1412
    /// ```
1413
    ///
1414
    /// # Example: adding absolute durations
1415
    ///
1416
    /// This shows how to add signed and unsigned absolute durations to a
1417
    /// `Timestamp`.
1418
    ///
1419
    /// ```
1420
    /// use std::time::Duration;
1421
    ///
1422
    /// use jiff::{SignedDuration, Timestamp};
1423
    ///
1424
    /// let ts1 = Timestamp::new(2_999_999_999, 0)?;
1425
    /// assert_eq!(ts1.to_string(), "2065-01-24T05:19:59Z");
1426
    ///
1427
    /// let dur = SignedDuration::new(60 * 60 + 30 * 60, 123);
1428
    /// assert_eq!(
1429
    ///     ts1.checked_add(dur)?.to_string(),
1430
    ///     "2065-01-24T06:49:59.000000123Z",
1431
    /// );
1432
    ///
1433
    /// let dur = Duration::new(60 * 60 + 30 * 60, 123);
1434
    /// assert_eq!(
1435
    ///     ts1.checked_add(dur)?.to_string(),
1436
    ///     "2065-01-24T06:49:59.000000123Z",
1437
    /// );
1438
    ///
1439
    /// # Ok::<(), Box<dyn std::error::Error>>(())
1440
    /// ```
1441
    #[inline]
1442
0
    pub fn checked_add<A: Into<TimestampArithmetic>>(
1443
0
        self,
1444
0
        duration: A,
1445
0
    ) -> Result<Timestamp, Error> {
1446
0
        let duration: TimestampArithmetic = duration.into();
1447
0
        duration.checked_add(self)
1448
0
    }
Unexecuted instantiation: <jiff::timestamp::Timestamp>::checked_add::<core::time::Duration>
Unexecuted instantiation: <jiff::timestamp::Timestamp>::checked_add::<jiff::signed_duration::SignedDuration>
Unexecuted instantiation: <jiff::timestamp::Timestamp>::checked_add::<jiff::span::Span>
Unexecuted instantiation: <jiff::timestamp::Timestamp>::checked_add::<&jiff::span::Span>
1449
1450
    #[inline]
1451
0
    fn checked_add_span(self, span: &Span) -> Result<Timestamp, Error> {
1452
0
        if let Some(err) = span.smallest_non_time_non_zero_unit_error() {
1453
0
            return Err(err);
1454
0
        }
1455
0
        if span.is_zero() {
1456
0
            return Ok(self);
1457
0
        }
1458
        // The common case is probably a span without fractional seconds, so
1459
        // we specialize for that since it requires a fair bit less math.
1460
        //
1461
        // Note that this only works when *both* the span and timestamp lack
1462
        // fractional seconds.
1463
0
        if self.subsec_nanosecond() == 0 && !span.has_fractional_seconds() {
1464
0
            let dur = self
1465
0
                .dur
1466
0
                .checked_add_seconds(span.to_hms_seconds())
1467
0
                .map_err(Error::jcore_range)
1468
0
                .context(E::OverflowAddSpan)?;
1469
0
            return Ok(Timestamp { dur });
1470
0
        }
1471
0
        let sum = self
1472
0
            .as_duration()
1473
0
            .checked_add(span.to_invariant_duration())
1474
0
            .ok_or(E::OverflowAddSpan)?;
1475
0
        Timestamp::from_duration(sum)
1476
0
    }
Unexecuted instantiation: <jiff::timestamp::Timestamp>::checked_add_span
Unexecuted instantiation: <jiff::timestamp::Timestamp>::checked_add_span
1477
1478
    #[inline]
1479
0
    fn checked_add_duration(
1480
0
        self,
1481
0
        duration: SignedDuration,
1482
0
    ) -> Result<Timestamp, Error> {
1483
0
        let start = self.as_duration();
1484
0
        let end = start.checked_add(duration).ok_or(E::OverflowAddDuration)?;
1485
0
        Timestamp::from_duration(end)
1486
0
    }
Unexecuted instantiation: <jiff::timestamp::Timestamp>::checked_add_duration
Unexecuted instantiation: <jiff::timestamp::Timestamp>::checked_add_duration
1487
1488
    /// This routine is identical to [`Timestamp::checked_add`] with the
1489
    /// duration negated.
1490
    ///
1491
    /// # Errors
1492
    ///
1493
    /// This has the same error conditions as [`Timestamp::checked_add`].
1494
    ///
1495
    /// # Example
1496
    ///
1497
    /// This routine can be used via the `-` operator. Note though that if it
1498
    /// fails, it will result in a panic.
1499
    ///
1500
    /// ```
1501
    /// use jiff::{SignedDuration, Timestamp, ToSpan};
1502
    ///
1503
    /// let ts1 = Timestamp::new(2_999_999_999, 0)?;
1504
    /// assert_eq!(ts1.to_string(), "2065-01-24T05:19:59Z");
1505
    ///
1506
    /// let ts2 = ts1 - 1.hour().minutes(30).nanoseconds(123);
1507
    /// assert_eq!(ts2.to_string(), "2065-01-24T03:49:58.999999877Z");
1508
    ///
1509
    /// # Ok::<(), Box<dyn std::error::Error>>(())
1510
    /// ```
1511
    ///
1512
    /// # Example: use with [`SignedDuration`] and [`std::time::Duration`]
1513
    ///
1514
    /// ```
1515
    /// use std::time::Duration;
1516
    ///
1517
    /// use jiff::{SignedDuration, Timestamp};
1518
    ///
1519
    /// let ts1 = Timestamp::new(2_999_999_999, 0)?;
1520
    /// assert_eq!(ts1.to_string(), "2065-01-24T05:19:59Z");
1521
    ///
1522
    /// let dur = SignedDuration::new(60 * 60 + 30 * 60, 123);
1523
    /// assert_eq!(
1524
    ///     ts1.checked_sub(dur)?.to_string(),
1525
    ///     "2065-01-24T03:49:58.999999877Z",
1526
    /// );
1527
    ///
1528
    /// let dur = Duration::new(60 * 60 + 30 * 60, 123);
1529
    /// assert_eq!(
1530
    ///     ts1.checked_sub(dur)?.to_string(),
1531
    ///     "2065-01-24T03:49:58.999999877Z",
1532
    /// );
1533
    ///
1534
    /// # Ok::<(), Box<dyn std::error::Error>>(())
1535
    /// ```
1536
    #[inline]
1537
0
    pub fn checked_sub<A: Into<TimestampArithmetic>>(
1538
0
        self,
1539
0
        duration: A,
1540
0
    ) -> Result<Timestamp, Error> {
1541
0
        let duration: TimestampArithmetic = duration.into();
1542
0
        duration.checked_neg().and_then(|ta| ta.checked_add(self))
Unexecuted instantiation: <jiff::timestamp::Timestamp>::checked_sub::<core::time::Duration>::{closure#0}
Unexecuted instantiation: <jiff::timestamp::Timestamp>::checked_sub::<_>::{closure#0}
1543
0
    }
Unexecuted instantiation: <jiff::timestamp::Timestamp>::checked_sub::<core::time::Duration>
Unexecuted instantiation: <jiff::timestamp::Timestamp>::checked_sub::<_>
1544
1545
    /// This routine is identical to [`Timestamp::checked_add`], except the
1546
    /// result saturates on overflow. That is, instead of overflow, either
1547
    /// [`Timestamp::MIN`] or [`Timestamp::MAX`] is returned.
1548
    ///
1549
    /// # Errors
1550
    ///
1551
    /// This returns an error if the given `Span` contains any non-zero units
1552
    /// greater than hours.
1553
    ///
1554
    /// # Example
1555
    ///
1556
    /// This example shows that arithmetic saturates on overflow.
1557
    ///
1558
    /// ```
1559
    /// use jiff::{SignedDuration, Timestamp, ToSpan};
1560
    ///
1561
    /// assert_eq!(
1562
    ///     Timestamp::MAX,
1563
    ///     Timestamp::MAX.saturating_add(1.nanosecond())?,
1564
    /// );
1565
    /// assert_eq!(
1566
    ///     Timestamp::MIN,
1567
    ///     Timestamp::MIN.saturating_add(-1.nanosecond())?,
1568
    /// );
1569
    /// assert_eq!(
1570
    ///     Timestamp::MAX,
1571
    ///     Timestamp::UNIX_EPOCH.saturating_add(SignedDuration::MAX)?,
1572
    /// );
1573
    /// assert_eq!(
1574
    ///     Timestamp::MIN,
1575
    ///     Timestamp::UNIX_EPOCH.saturating_add(SignedDuration::MIN)?,
1576
    /// );
1577
    /// assert_eq!(
1578
    ///     Timestamp::MAX,
1579
    ///     Timestamp::UNIX_EPOCH.saturating_add(std::time::Duration::MAX)?,
1580
    /// );
1581
    ///
1582
    /// # Ok::<(), Box<dyn std::error::Error>>(())
1583
    /// ```
1584
    #[inline]
1585
0
    pub fn saturating_add<A: Into<TimestampArithmetic>>(
1586
0
        self,
1587
0
        duration: A,
1588
0
    ) -> Result<Timestamp, Error> {
1589
0
        let duration: TimestampArithmetic = duration.into();
1590
0
        duration.saturating_add(self)
1591
0
    }
1592
1593
    /// This routine is identical to [`Timestamp::saturating_add`] with the
1594
    /// span parameter negated.
1595
    ///
1596
    /// # Errors
1597
    ///
1598
    /// This returns an error if the given `Span` contains any non-zero units
1599
    /// greater than hours.
1600
    ///
1601
    /// # Example
1602
    ///
1603
    /// This example shows that arithmetic saturates on overflow.
1604
    ///
1605
    /// ```
1606
    /// use jiff::{SignedDuration, Timestamp, ToSpan};
1607
    ///
1608
    /// assert_eq!(
1609
    ///     Timestamp::MIN,
1610
    ///     Timestamp::MIN.saturating_sub(1.nanosecond())?,
1611
    /// );
1612
    /// assert_eq!(
1613
    ///     Timestamp::MAX,
1614
    ///     Timestamp::MAX.saturating_sub(-1.nanosecond())?,
1615
    /// );
1616
    /// assert_eq!(
1617
    ///     Timestamp::MIN,
1618
    ///     Timestamp::UNIX_EPOCH.saturating_sub(SignedDuration::MAX)?,
1619
    /// );
1620
    /// assert_eq!(
1621
    ///     Timestamp::MAX,
1622
    ///     Timestamp::UNIX_EPOCH.saturating_sub(SignedDuration::MIN)?,
1623
    /// );
1624
    /// assert_eq!(
1625
    ///     Timestamp::MIN,
1626
    ///     Timestamp::UNIX_EPOCH.saturating_sub(std::time::Duration::MAX)?,
1627
    /// );
1628
    ///
1629
    /// # Ok::<(), Box<dyn std::error::Error>>(())
1630
    /// ```
1631
    #[inline]
1632
0
    pub fn saturating_sub<A: Into<TimestampArithmetic>>(
1633
0
        self,
1634
0
        duration: A,
1635
0
    ) -> Result<Timestamp, Error> {
1636
0
        let duration: TimestampArithmetic = duration.into();
1637
0
        let Ok(duration) = duration.checked_neg() else {
1638
0
            return Ok(Timestamp::MIN);
1639
        };
1640
0
        self.saturating_add(duration)
1641
0
    }
1642
1643
    /// Returns a span representing the elapsed time from this timestamp until
1644
    /// the given `other` timestamp.
1645
    ///
1646
    /// When `other` occurs before this timestamp, then the span returned will
1647
    /// be negative.
1648
    ///
1649
    /// Depending on the input provided, the span returned is rounded. It may
1650
    /// also be balanced up to bigger units than the default. By default,
1651
    /// the span returned is balanced such that the biggest possible unit is
1652
    /// seconds.
1653
    ///
1654
    /// This operation is configured by providing a [`TimestampDifference`]
1655
    /// value. Since this routine accepts anything that implements
1656
    /// `Into<TimestampDifference>`, once can pass a `Timestamp` directly.
1657
    /// One can also pass a `(Unit, Timestamp)`, where `Unit` is treated as
1658
    /// [`TimestampDifference::largest`].
1659
    ///
1660
    /// # Properties
1661
    ///
1662
    /// It is guaranteed that if the returned span is subtracted from `other`,
1663
    /// and if no rounding is requested, then the original timestamp will be
1664
    /// returned.
1665
    ///
1666
    /// This routine is equivalent to `self.since(other).map(|span| -span)`
1667
    /// if no rounding options are set. If rounding options are set, then
1668
    /// it's equivalent to
1669
    /// `self.since(other_without_rounding_options).map(|span| -span)`,
1670
    /// followed by a call to [`Span::round`] with the appropriate rounding
1671
    /// options set. This is because the negation of a span can result in
1672
    /// different rounding results depending on the rounding mode.
1673
    ///
1674
    /// # Errors
1675
    ///
1676
    /// An error can occur in some cases when the requested configuration
1677
    /// would result in a span that is beyond allowable limits. For example,
1678
    /// the nanosecond component of a span cannot represent the span of
1679
    /// time between the minimum and maximum timestamps supported by Jiff.
1680
    /// Therefore, if one requests a span with its largest unit set to
1681
    /// [`Unit::Nanosecond`], then it's possible for this routine to fail.
1682
    ///
1683
    /// An error can also occur if `TimestampDifference` is misconfigured. For
1684
    /// example, if the smallest unit provided is bigger than the largest unit,
1685
    /// or if the largest unit provided is bigger than hours. (To use bigger
1686
    /// units with an instant in time, use [`Zoned::until`] instead.)
1687
    ///
1688
    /// It is guaranteed that if one provides a timestamp with the default
1689
    /// [`TimestampDifference`] configuration, then this routine will never
1690
    /// fail.
1691
    ///
1692
    /// # Example
1693
    ///
1694
    /// ```
1695
    /// use jiff::{Timestamp, ToSpan};
1696
    ///
1697
    /// let earlier: Timestamp = "2006-08-24T22:30:00Z".parse()?;
1698
    /// let later: Timestamp = "2019-01-31 21:00:00Z".parse()?;
1699
    /// assert_eq!(earlier.until(later)?, 392509800.seconds().fieldwise());
1700
    ///
1701
    /// // Flipping the timestamps is fine, but you'll get a negative span.
1702
    /// assert_eq!(later.until(earlier)?, -392509800.seconds().fieldwise());
1703
    ///
1704
    /// # Ok::<(), Box<dyn std::error::Error>>(())
1705
    /// ```
1706
    ///
1707
    /// # Example: using bigger units
1708
    ///
1709
    /// This example shows how to expand the span returned to bigger units.
1710
    /// This makes use of a `From<(Unit, Timestamp)> for TimestampDifference`
1711
    /// trait implementation.
1712
    ///
1713
    /// ```
1714
    /// use jiff::{Timestamp, ToSpan, Unit};
1715
    ///
1716
    /// let ts1: Timestamp = "1995-12-07T03:24:30.000003500Z".parse()?;
1717
    /// let ts2: Timestamp = "2019-01-31 15:30:00Z".parse()?;
1718
    ///
1719
    /// // The default limits durations to using "seconds" as the biggest unit.
1720
    /// let span = ts1.until(ts2)?;
1721
    /// assert_eq!(span.to_string(), "PT730641929.9999965S");
1722
    ///
1723
    /// // But we can ask for units all the way up to hours.
1724
    /// let span = ts1.until((Unit::Hour, ts2))?;
1725
    /// assert_eq!(span.to_string(), "PT202956H5M29.9999965S");
1726
    ///
1727
    /// # Ok::<(), Box<dyn std::error::Error>>(())
1728
    /// ```
1729
    ///
1730
    /// # Example: rounding the result
1731
    ///
1732
    /// This shows how one might find the difference between two timestamps and
1733
    /// have the result rounded such that sub-seconds are removed.
1734
    ///
1735
    /// In this case, we need to hand-construct a [`TimestampDifference`]
1736
    /// in order to gain full configurability.
1737
    ///
1738
    /// ```
1739
    /// use jiff::{Timestamp, TimestampDifference, ToSpan, Unit};
1740
    ///
1741
    /// let ts1: Timestamp = "1995-12-07 03:24:30.000003500Z".parse()?;
1742
    /// let ts2: Timestamp = "2019-01-31 15:30:00Z".parse()?;
1743
    ///
1744
    /// let span = ts1.until(
1745
    ///     TimestampDifference::from(ts2).smallest(Unit::Second),
1746
    /// )?;
1747
    /// assert_eq!(span.to_string(), "PT730641929S");
1748
    ///
1749
    /// // We can combine smallest and largest units too!
1750
    /// let span = ts1.until(
1751
    ///     TimestampDifference::from(ts2)
1752
    ///         .smallest(Unit::Second)
1753
    ///         .largest(Unit::Hour),
1754
    /// )?;
1755
    /// assert_eq!(span.to_string(), "PT202956H5M29S");
1756
    /// # Ok::<(), Box<dyn std::error::Error>>(())
1757
    /// ```
1758
    #[inline]
1759
0
    pub fn until<A: Into<TimestampDifference>>(
1760
0
        self,
1761
0
        other: A,
1762
0
    ) -> Result<Span, Error> {
1763
0
        let args: TimestampDifference = other.into();
1764
0
        let span = args.until_with_largest_unit(self)?;
1765
0
        if args.rounding_may_change_span() {
1766
0
            span.round(args.round)
1767
        } else {
1768
0
            Ok(span)
1769
        }
1770
0
    }
1771
1772
    /// This routine is identical to [`Timestamp::until`], but the order of the
1773
    /// parameters is flipped.
1774
    ///
1775
    /// # Errors
1776
    ///
1777
    /// This has the same error conditions as [`Timestamp::until`].
1778
    ///
1779
    /// # Example
1780
    ///
1781
    /// This routine can be used via the `-` operator. Since the default
1782
    /// configuration is used and because a `Span` can represent the difference
1783
    /// between any two possible timestamps, it will never panic.
1784
    ///
1785
    /// ```
1786
    /// use jiff::{Timestamp, ToSpan};
1787
    ///
1788
    /// let earlier: Timestamp = "2006-08-24T22:30:00Z".parse()?;
1789
    /// let later: Timestamp = "2019-01-31 21:00:00Z".parse()?;
1790
    /// assert_eq!(later - earlier, 392509800.seconds().fieldwise());
1791
    ///
1792
    /// # Ok::<(), Box<dyn std::error::Error>>(())
1793
    /// ```
1794
    #[inline]
1795
0
    pub fn since<A: Into<TimestampDifference>>(
1796
0
        self,
1797
0
        other: A,
1798
0
    ) -> Result<Span, Error> {
1799
0
        let args: TimestampDifference = other.into();
1800
0
        let span = -args.until_with_largest_unit(self)?;
1801
0
        if args.rounding_may_change_span() {
1802
0
            span.round(args.round)
1803
        } else {
1804
0
            Ok(span)
1805
        }
1806
0
    }
1807
1808
    /// Returns an absolute duration representing the elapsed time from this
1809
    /// timestamp until the given `other` timestamp.
1810
    ///
1811
    /// When `other` occurs before this timestamp, then the duration returned
1812
    /// will be negative.
1813
    ///
1814
    /// Unlike [`Timestamp::until`], this always returns a duration
1815
    /// corresponding to a 96-bit integer of nanoseconds between two
1816
    /// timestamps.
1817
    ///
1818
    /// # Fallibility
1819
    ///
1820
    /// This routine never panics or returns an error. Since there are no
1821
    /// configuration options that can be incorrectly provided, no error is
1822
    /// possible when calling this routine. In contrast, [`Timestamp::until`]
1823
    /// can return an error in some cases due to misconfiguration. But like
1824
    /// this routine, [`Timestamp::until`] never panics or returns an error in
1825
    /// its default configuration.
1826
    ///
1827
    /// # When should I use this versus [`Timestamp::until`]?
1828
    ///
1829
    /// See the type documentation for [`SignedDuration`] for the section on
1830
    /// when one should use [`Span`] and when one should use `SignedDuration`.
1831
    /// In short, use `Span` (and therefore `Timestamp::until`) unless you have
1832
    /// a specific reason to do otherwise.
1833
    ///
1834
    /// # Example
1835
    ///
1836
    /// ```
1837
    /// use jiff::{Timestamp, SignedDuration};
1838
    ///
1839
    /// let earlier: Timestamp = "2006-08-24T22:30:00Z".parse()?;
1840
    /// let later: Timestamp = "2019-01-31 21:00:00Z".parse()?;
1841
    /// assert_eq!(
1842
    ///     earlier.duration_until(later),
1843
    ///     SignedDuration::from_secs(392509800),
1844
    /// );
1845
    ///
1846
    /// // Flipping the timestamps is fine, but you'll get a negative span.
1847
    /// assert_eq!(
1848
    ///     later.duration_until(earlier),
1849
    ///     SignedDuration::from_secs(-392509800),
1850
    /// );
1851
    ///
1852
    /// # Ok::<(), Box<dyn std::error::Error>>(())
1853
    /// ```
1854
    ///
1855
    /// # Example: difference with [`Timestamp::until`]
1856
    ///
1857
    /// The primary difference between this routine and
1858
    /// `Timestamp::until`, other than the return type, is that this
1859
    /// routine is likely to be faster. Namely, it does simple 96-bit
1860
    /// integer math, where as `Timestamp::until` has to do a bit more
1861
    /// work to deal with the different types of units on a `Span`.
1862
    ///
1863
    /// Additionally, since the difference between two timestamps is always
1864
    /// expressed in units of hours or smaller, and units of hours or smaller
1865
    /// are always uniform, there is no "expressive" difference between this
1866
    /// routine and `Timestamp::until`. Because of this, one can always
1867
    /// convert between `Span` and `SignedDuration` as returned by methods
1868
    /// on `Timestamp` without a relative datetime:
1869
    ///
1870
    /// ```
1871
    /// use jiff::{SignedDuration, Span, Timestamp};
1872
    ///
1873
    /// let ts1: Timestamp = "2024-02-28T00:00:00Z".parse()?;
1874
    /// let ts2: Timestamp = "2024-03-01T00:00:00Z".parse()?;
1875
    /// let dur = ts1.duration_until(ts2);
1876
    /// // Guaranteed to never fail because the duration
1877
    /// // between two civil times never exceeds the limits
1878
    /// // of a `Span`.
1879
    /// let span = Span::try_from(dur).unwrap();
1880
    /// assert_eq!(format!("{span:#}"), "172800s");
1881
    /// // Guaranteed to succeed and always return the original
1882
    /// // duration because the units are always hours or smaller,
1883
    /// // and thus uniform. This means a relative datetime is
1884
    /// // never required to do this conversion.
1885
    /// let dur = SignedDuration::try_from(span).unwrap();
1886
    /// assert_eq!(dur, SignedDuration::from_secs(172_800));
1887
    ///
1888
    /// # Ok::<(), Box<dyn std::error::Error>>(())
1889
    /// ```
1890
    ///
1891
    /// This conversion guarantee also applies to [`Timestamp::until`] since it
1892
    /// always returns a balanced span. That is, it never returns spans like
1893
    /// `1 second 1000 milliseconds`. (Those cannot be losslessly converted to
1894
    /// a `SignedDuration` since a `SignedDuration` is only represented as a
1895
    /// single 96-bit integer of nanoseconds.)
1896
    #[inline]
1897
0
    pub fn duration_until(self, other: Timestamp) -> SignedDuration {
1898
0
        SignedDuration::timestamp_until(self, other)
1899
0
    }
1900
1901
    /// This routine is identical to [`Timestamp::duration_until`], but the
1902
    /// order of the parameters is flipped.
1903
    ///
1904
    /// # Example
1905
    ///
1906
    /// ```
1907
    /// use jiff::{SignedDuration, Timestamp};
1908
    ///
1909
    /// let earlier: Timestamp = "2006-08-24T22:30:00Z".parse()?;
1910
    /// let later: Timestamp = "2019-01-31 21:00:00Z".parse()?;
1911
    /// assert_eq!(
1912
    ///     later.duration_since(earlier),
1913
    ///     SignedDuration::from_secs(392509800),
1914
    /// );
1915
    ///
1916
    /// # Ok::<(), Box<dyn std::error::Error>>(())
1917
    /// ```
1918
    #[inline]
1919
0
    pub fn duration_since(self, other: Timestamp) -> SignedDuration {
1920
0
        SignedDuration::timestamp_until(other, self)
1921
0
    }
1922
1923
    /// Rounds this timestamp according to the [`TimestampRound`] configuration
1924
    /// given.
1925
    ///
1926
    /// The principal option is [`TimestampRound::smallest`], which allows
1927
    /// one to configure the smallest units in the returned timestamp.
1928
    /// Rounding is what determines whether the specified smallest unit
1929
    /// should keep its current value or whether it should be incremented.
1930
    /// Moreover, the amount it should be incremented can be configured via
1931
    /// [`TimestampRound::increment`]. Finally, the rounding strategy itself
1932
    /// can be configured via [`TimestampRound::mode`].
1933
    ///
1934
    /// Note that this routine is generic and accepts anything that
1935
    /// implements `Into<TimestampRound>`. Some notable implementations are:
1936
    ///
1937
    /// * `From<Unit> for TimestampRound`, which will automatically create a
1938
    /// `TimestampRound::new().smallest(unit)` from the unit provided.
1939
    /// * `From<(Unit, i64)> for TimestampRound`, which will automatically
1940
    /// create a `TimestampRound::new().smallest(unit).increment(number)` from
1941
    /// the unit and increment provided.
1942
    ///
1943
    /// # Errors
1944
    ///
1945
    /// This returns an error if the smallest unit configured on the given
1946
    /// [`TimestampRound`] is bigger than hours.
1947
    ///
1948
    /// The rounding increment, when combined with the smallest unit (which
1949
    /// defaults to [`Unit::Nanosecond`]), must divide evenly into `86,400`
1950
    /// seconds (one 24-hour civil day). For example, increments of both
1951
    /// 45 seconds and 15 minutes are allowed, but 7 seconds and 25 minutes are
1952
    /// both not allowed.
1953
    ///
1954
    /// # Example
1955
    ///
1956
    /// This is a basic example that demonstrates rounding a timestamp to the
1957
    /// nearest hour. This also demonstrates calling this method with the
1958
    /// smallest unit directly, instead of constructing a `TimestampRound`
1959
    /// manually.
1960
    ///
1961
    /// ```
1962
    /// use jiff::{Timestamp, Unit};
1963
    ///
1964
    /// let ts: Timestamp = "2024-06-19 15:30:00Z".parse()?;
1965
    /// assert_eq!(
1966
    ///     ts.round(Unit::Hour)?.to_string(),
1967
    ///     "2024-06-19T16:00:00Z",
1968
    /// );
1969
    /// let ts: Timestamp = "2024-06-19 15:29:59Z".parse()?;
1970
    /// assert_eq!(
1971
    ///     ts.round(Unit::Hour)?.to_string(),
1972
    ///     "2024-06-19T15:00:00Z",
1973
    /// );
1974
    ///
1975
    /// # Ok::<(), Box<dyn std::error::Error>>(())
1976
    /// ```
1977
    ///
1978
    /// # Example: changing the rounding mode
1979
    ///
1980
    /// The default rounding mode is [`RoundMode::HalfExpand`], which
1981
    /// breaks ties by rounding away from zero. But other modes like
1982
    /// [`RoundMode::Trunc`] can be used too:
1983
    ///
1984
    /// ```
1985
    /// use jiff::{RoundMode, Timestamp, TimestampRound, Unit};
1986
    ///
1987
    /// // The default will round up to the next hour for any time past the
1988
    /// // 30 minute mark, but using truncation rounding will always round
1989
    /// // down.
1990
    /// let ts: Timestamp = "2024-06-19 15:30:00Z".parse()?;
1991
    /// assert_eq!(
1992
    ///     ts.round(
1993
    ///         TimestampRound::new()
1994
    ///             .smallest(Unit::Hour)
1995
    ///             .mode(RoundMode::Trunc),
1996
    ///     )?.to_string(),
1997
    ///     "2024-06-19T15:00:00Z",
1998
    /// );
1999
    ///
2000
    /// # Ok::<(), Box<dyn std::error::Error>>(())
2001
    /// ```
2002
    ///
2003
    /// # Example: rounding to the nearest 5 minute increment
2004
    ///
2005
    /// ```
2006
    /// use jiff::{Timestamp, Unit};
2007
    ///
2008
    /// // rounds down
2009
    /// let ts: Timestamp = "2024-06-19T15:27:29.999999999Z".parse()?;
2010
    /// assert_eq!(
2011
    ///     ts.round((Unit::Minute, 5))?.to_string(),
2012
    ///     "2024-06-19T15:25:00Z",
2013
    /// );
2014
    /// // rounds up
2015
    /// let ts: Timestamp = "2024-06-19T15:27:30Z".parse()?;
2016
    /// assert_eq!(
2017
    ///     ts.round((Unit::Minute, 5))?.to_string(),
2018
    ///     "2024-06-19T15:30:00Z",
2019
    /// );
2020
    ///
2021
    /// # Ok::<(), Box<dyn std::error::Error>>(())
2022
    /// ```
2023
    #[inline]
2024
0
    pub fn round<R: Into<TimestampRound>>(
2025
0
        self,
2026
0
        options: R,
2027
0
    ) -> Result<Timestamp, Error> {
2028
0
        let options: TimestampRound = options.into();
2029
0
        options.round(self)
2030
0
    }
2031
2032
    /// Return an iterator of periodic timestamps determined by the given span.
2033
    ///
2034
    /// The given span may be negative, in which case, the iterator will move
2035
    /// backwards through time. The iterator won't stop until either the span
2036
    /// itself overflows, or it would otherwise exceed the minimum or maximum
2037
    /// `Timestamp` value.
2038
    ///
2039
    /// # Example: when to check a glucose monitor
2040
    ///
2041
    /// When my cat had diabetes, my veterinarian installed a glucose monitor
2042
    /// and instructed me to scan it about every 5 hours. This example lists
2043
    /// all of the times I need to scan it for the 2 days following its
2044
    /// installation:
2045
    ///
2046
    /// ```
2047
    /// use jiff::{Timestamp, ToSpan};
2048
    ///
2049
    /// let start: Timestamp = "2023-07-15 16:30:00-04".parse()?;
2050
    /// let end = start.checked_add(48.hours())?;
2051
    /// let mut scan_times = vec![];
2052
    /// for ts in start.series(5.hours()).take_while(|&ts| ts <= end) {
2053
    ///     scan_times.push(ts);
2054
    /// }
2055
    /// assert_eq!(scan_times, vec![
2056
    ///     "2023-07-15 16:30:00-04:00".parse::<Timestamp>()?,
2057
    ///     "2023-07-15 21:30:00-04:00".parse::<Timestamp>()?,
2058
    ///     "2023-07-16 02:30:00-04:00".parse::<Timestamp>()?,
2059
    ///     "2023-07-16 07:30:00-04:00".parse::<Timestamp>()?,
2060
    ///     "2023-07-16 12:30:00-04:00".parse::<Timestamp>()?,
2061
    ///     "2023-07-16 17:30:00-04:00".parse::<Timestamp>()?,
2062
    ///     "2023-07-16 22:30:00-04:00".parse::<Timestamp>()?,
2063
    ///     "2023-07-17 03:30:00-04:00".parse::<Timestamp>()?,
2064
    ///     "2023-07-17 08:30:00-04:00".parse::<Timestamp>()?,
2065
    ///     "2023-07-17 13:30:00-04:00".parse::<Timestamp>()?,
2066
    /// ]);
2067
    ///
2068
    /// # Ok::<(), Box<dyn std::error::Error>>(())
2069
    /// ```
2070
    #[inline]
2071
0
    pub fn series(self, period: Span) -> TimestampSeries {
2072
0
        TimestampSeries::new(self, period)
2073
0
    }
2074
}
2075
2076
/// Parsing and formatting APIs.
2077
impl Timestamp {
2078
    /// Parses a timestamp (expressed as broken down time) in `input` matching
2079
    /// the given `format`.
2080
    ///
2081
    /// The format string uses a "printf"-style API where conversion
2082
    /// specifiers can be used as place holders to match components of
2083
    /// a datetime. For details on the specifiers supported, see the
2084
    /// [`fmt::strtime`] module documentation.
2085
    ///
2086
    /// # Errors
2087
    ///
2088
    /// This returns an error when parsing failed. This might happen because
2089
    /// the format string itself was invalid, or because the input didn't match
2090
    /// the format string.
2091
    ///
2092
    /// This also returns an error if there wasn't sufficient information to
2093
    /// construct a timestamp. For example, if an offset wasn't parsed. (The
2094
    /// offset is needed to turn the civil time parsed into a precise instant
2095
    /// in time.)
2096
    ///
2097
    /// # Example
2098
    ///
2099
    /// This example shows how to parse a datetime string into a timestamp:
2100
    ///
2101
    /// ```
2102
    /// use jiff::Timestamp;
2103
    ///
2104
    /// let ts = Timestamp::strptime("%F %H:%M %:z", "2024-07-14 21:14 -04:00")?;
2105
    /// assert_eq!(ts.to_string(), "2024-07-15T01:14:00Z");
2106
    ///
2107
    /// # Ok::<(), Box<dyn std::error::Error>>(())
2108
    /// ```
2109
    #[inline]
2110
0
    pub fn strptime(
2111
0
        format: impl AsRef<[u8]>,
2112
0
        input: impl AsRef<[u8]>,
2113
0
    ) -> Result<Timestamp, Error> {
2114
0
        fmt::strtime::parse(format, input).and_then(|tm| tm.to_timestamp())
2115
0
    }
2116
2117
    /// Formats this timestamp according to the given `format`.
2118
    ///
2119
    /// The format string uses a "printf"-style API where conversion
2120
    /// specifiers can be used as place holders to format components of
2121
    /// a datetime. For details on the specifiers supported, see the
2122
    /// [`fmt::strtime`] module documentation.
2123
    ///
2124
    /// # Errors and panics
2125
    ///
2126
    /// This will never error or panic. In particular,
2127
    /// [lenient mode](crate::fmt::strtime::Config::lenient) is enabled, which
2128
    /// means that all possible strings have some non-error interpretation.
2129
    /// Note that because of this, and since Jiff may add new conversion
2130
    /// specifiers in the future, the behavior of a format string may change
2131
    /// when it would otherwise be invalid.
2132
    ///
2133
    /// To format in a way that surfaces errors, use either
2134
    /// [`fmt::strtime::format`] or [`fmt::strtime::BrokenDownTime::format`].
2135
    ///
2136
    /// # Example
2137
    ///
2138
    /// This shows how to format a timestamp into a human readable datetime
2139
    /// in UTC:
2140
    ///
2141
    /// ```
2142
    /// use jiff::{civil::date, Timestamp};
2143
    ///
2144
    /// let ts = Timestamp::from_second(86_400)?;
2145
    /// let string = ts.strftime("%a %b %e %I:%M:%S %p UTC %Y").to_string();
2146
    /// assert_eq!(string, "Fri Jan  2 12:00:00 AM UTC 1970");
2147
    ///
2148
    /// # Ok::<(), Box<dyn std::error::Error>>(())
2149
    /// ```
2150
    ///
2151
    /// # Example: errors are silently ignored
2152
    ///
2153
    /// If the formatting string is malformed in some way, then it is silently
2154
    /// ignored. For example, when using an invalid formatting directive:
2155
    ///
2156
    /// ```
2157
    /// use jiff::Timestamp;
2158
    ///
2159
    /// let ts = Timestamp::UNIX_EPOCH;
2160
    /// let string = ts.strftime("%Y %").to_string();
2161
    /// assert_eq!(string, "1970 %");
2162
    /// ```
2163
    ///
2164
    /// If one wants to surface errors from a formatting string, use a lower
2165
    /// level API:
2166
    ///
2167
    /// ```
2168
    /// use jiff::Timestamp;
2169
    ///
2170
    /// let ts = Timestamp::UNIX_EPOCH;
2171
    /// assert_eq!(
2172
    ///     jiff::fmt::strtime::format("%Y %", ts).unwrap_err().to_string(),
2173
    ///     "strftime formatting failed: invalid format string, \
2174
    ///      expected byte after `%`, but found end of format string",
2175
    /// );
2176
    /// ```
2177
    #[inline]
2178
0
    pub fn strftime<'f, F: 'f + ?Sized + AsRef<[u8]>>(
2179
0
        &self,
2180
0
        format: &'f F,
2181
0
    ) -> fmt::strtime::Display<'f> {
2182
0
        fmt::strtime::Display { fmt: format.as_ref(), tm: (*self).into() }
2183
0
    }
Unexecuted instantiation: <jiff::timestamp::Timestamp>::strftime::<str>
Unexecuted instantiation: <jiff::timestamp::Timestamp>::strftime::<_>
2184
2185
    /// Format a `Timestamp` datetime into a string with the given offset.
2186
    ///
2187
    /// This will format to an RFC 3339 compatible string with an offset.
2188
    ///
2189
    /// This will never use either `Z` (for Zulu time) or `-00:00` as an
2190
    /// offset. This is because Zulu time (and `-00:00`) mean "the time in UTC
2191
    /// is known, but the offset to local time is unknown." Since this routine
2192
    /// accepts an explicit offset, the offset is known. For example,
2193
    /// `Offset::UTC` will be formatted as `+00:00`.
2194
    ///
2195
    /// To format an RFC 3339 string in Zulu time, use the default
2196
    /// [`std::fmt::Display`] trait implementation on `Timestamp`.
2197
    ///
2198
    /// # Example
2199
    ///
2200
    /// ```
2201
    /// use jiff::{tz, Timestamp};
2202
    ///
2203
    /// let ts = Timestamp::from_second(1)?;
2204
    /// assert_eq!(
2205
    ///     ts.display_with_offset(tz::offset(-5)).to_string(),
2206
    ///     "1969-12-31T19:00:01-05:00",
2207
    /// );
2208
    ///
2209
    /// # Ok::<(), Box<dyn std::error::Error>>(())
2210
    /// ```
2211
    #[inline]
2212
0
    pub fn display_with_offset(
2213
0
        &self,
2214
0
        offset: Offset,
2215
0
    ) -> TimestampDisplayWithOffset {
2216
0
        TimestampDisplayWithOffset { timestamp: *self, offset }
2217
0
    }
Unexecuted instantiation: <jiff::timestamp::Timestamp>::display_with_offset
Unexecuted instantiation: <jiff::timestamp::Timestamp>::display_with_offset
2218
}
2219
2220
/// Internal APIs.
2221
impl Timestamp {
2222
    #[inline]
2223
0
    pub(crate) const fn to_jcore(&self) -> JTimestamp {
2224
0
        self.dur
2225
0
    }
Unexecuted instantiation: <jiff::timestamp::Timestamp>::to_jcore
Unexecuted instantiation: <jiff::timestamp::Timestamp>::to_jcore
Unexecuted instantiation: <jiff::timestamp::Timestamp>::to_jcore
Unexecuted instantiation: <jiff::timestamp::Timestamp>::to_jcore
2226
2227
    #[inline]
2228
0
    pub(crate) const fn from_jcore(timestamp: JTimestamp) -> Timestamp {
2229
0
        Timestamp { dur: timestamp }
2230
0
    }
Unexecuted instantiation: <jiff::timestamp::Timestamp>::from_jcore
Unexecuted instantiation: <jiff::timestamp::Timestamp>::from_jcore
2231
}
2232
2233
impl Default for Timestamp {
2234
    #[inline]
2235
0
    fn default() -> Timestamp {
2236
0
        Timestamp::UNIX_EPOCH
2237
0
    }
2238
}
2239
2240
/// Converts a `Timestamp` datetime into a human readable datetime string.
2241
///
2242
/// (This `Debug` representation currently emits the same string as the
2243
/// `Display` representation, but this is not a guarantee.)
2244
///
2245
/// Options currently supported:
2246
///
2247
/// * [`std::fmt::Formatter::precision`] can be set to control the precision
2248
/// of the fractional second component.
2249
///
2250
/// # Example
2251
///
2252
/// ```
2253
/// use jiff::Timestamp;
2254
///
2255
/// let ts = Timestamp::new(1_123_456_789, 123_000_000)?;
2256
/// assert_eq!(
2257
///     format!("{ts:.6?}"),
2258
///     "2005-08-07T23:19:49.123000Z",
2259
/// );
2260
/// // Precision values greater than 9 are clamped to 9.
2261
/// assert_eq!(
2262
///     format!("{ts:.300?}"),
2263
///     "2005-08-07T23:19:49.123000000Z",
2264
/// );
2265
/// // A precision of 0 implies the entire fractional
2266
/// // component is always truncated.
2267
/// assert_eq!(
2268
///     format!("{ts:.0?}"),
2269
///     "2005-08-07T23:19:49Z",
2270
/// );
2271
///
2272
/// # Ok::<(), Box<dyn std::error::Error>>(())
2273
/// ```
2274
impl core::fmt::Debug for Timestamp {
2275
    #[inline]
2276
0
    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
2277
0
        core::fmt::Display::fmt(self, f)
2278
0
    }
2279
}
2280
2281
/// Converts a `Timestamp` datetime into a RFC 3339 compliant string.
2282
///
2283
/// Since a `Timestamp` never has an offset associated with it and is always
2284
/// in UTC, the string emitted by this trait implementation uses `Z` for "Zulu"
2285
/// time. The significance of Zulu time is prescribed by RFC 9557 and means
2286
/// that "the time in UTC is known, but the offset to local time is unknown."
2287
/// If you need to emit an RFC 3339 compliant string with a specific offset,
2288
/// then use [`Timestamp::display_with_offset`].
2289
///
2290
/// # Formatting options supported
2291
///
2292
/// * [`std::fmt::Formatter::precision`] can be set to control the precision
2293
/// of the fractional second component. When not set, the minimum precision
2294
/// required to losslessly render the value is used.
2295
///
2296
/// # Example
2297
///
2298
/// This shows the default rendering:
2299
///
2300
/// ```
2301
/// use jiff::Timestamp;
2302
///
2303
/// // No fractional seconds.
2304
/// let ts = Timestamp::from_second(1_123_456_789)?;
2305
/// assert_eq!(format!("{ts}"), "2005-08-07T23:19:49Z");
2306
///
2307
/// // With fractional seconds.
2308
/// let ts = Timestamp::new(1_123_456_789, 123_000_000)?;
2309
/// assert_eq!(format!("{ts}"), "2005-08-07T23:19:49.123Z");
2310
///
2311
/// # Ok::<(), Box<dyn std::error::Error>>(())
2312
/// ```
2313
///
2314
/// # Example: setting the precision
2315
///
2316
/// ```
2317
/// use jiff::Timestamp;
2318
///
2319
/// let ts = Timestamp::new(1_123_456_789, 123_000_000)?;
2320
/// assert_eq!(
2321
///     format!("{ts:.6}"),
2322
///     "2005-08-07T23:19:49.123000Z",
2323
/// );
2324
/// // Precision values greater than 9 are clamped to 9.
2325
/// assert_eq!(
2326
///     format!("{ts:.300}"),
2327
///     "2005-08-07T23:19:49.123000000Z",
2328
/// );
2329
/// // A precision of 0 implies the entire fractional
2330
/// // component is always truncated.
2331
/// assert_eq!(
2332
///     format!("{ts:.0}"),
2333
///     "2005-08-07T23:19:49Z",
2334
/// );
2335
///
2336
/// # Ok::<(), Box<dyn std::error::Error>>(())
2337
/// ```
2338
impl core::fmt::Display for Timestamp {
2339
    #[inline]
2340
0
    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
2341
        use crate::fmt::StdFmtWrite;
2342
2343
0
        let precision =
2344
0
            f.precision().map(|p| u8::try_from(p).unwrap_or(u8::MAX));
2345
0
        temporal::DateTimePrinter::new()
2346
0
            .precision(precision)
2347
0
            .print_timestamp(self, StdFmtWrite(f))
2348
0
            .map_err(|_| core::fmt::Error)
2349
0
    }
Unexecuted instantiation: <jiff::timestamp::Timestamp as core::fmt::Display>::fmt
Unexecuted instantiation: <jiff::timestamp::Timestamp as core::fmt::Display>::fmt
2350
}
2351
2352
impl core::str::FromStr for Timestamp {
2353
    type Err = Error;
2354
2355
    #[inline]
2356
0
    fn from_str(string: &str) -> Result<Timestamp, Error> {
2357
0
        DEFAULT_DATETIME_PARSER.parse_timestamp(string)
2358
0
    }
Unexecuted instantiation: <jiff::timestamp::Timestamp as core::str::traits::FromStr>::from_str
Unexecuted instantiation: <jiff::timestamp::Timestamp as core::str::traits::FromStr>::from_str
2359
}
2360
2361
impl Eq for Timestamp {}
2362
2363
impl PartialEq for Timestamp {
2364
    #[inline]
2365
2
    fn eq(&self, rhs: &Timestamp) -> bool {
2366
2
        self.dur == rhs.dur
2367
2
    }
2368
}
2369
2370
impl Ord for Timestamp {
2371
    #[inline]
2372
0
    fn cmp(&self, rhs: &Timestamp) -> core::cmp::Ordering {
2373
0
        self.dur.cmp(&rhs.dur)
2374
0
    }
2375
}
2376
2377
impl PartialOrd for Timestamp {
2378
    #[inline]
2379
0
    fn partial_cmp(&self, rhs: &Timestamp) -> Option<core::cmp::Ordering> {
2380
0
        Some(self.cmp(rhs))
2381
0
    }
2382
}
2383
2384
impl core::hash::Hash for Timestamp {
2385
    #[inline]
2386
0
    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
2387
0
        self.dur.hash(state);
2388
0
    }
2389
}
2390
2391
/// Adds a span of time to a timestamp.
2392
///
2393
/// This uses checked arithmetic and panics when it fails. To handle arithmetic
2394
/// without panics, use [`Timestamp::checked_add`]. Note that the failure
2395
/// condition includes overflow and using a `Span` with non-zero units greater
2396
/// than hours.
2397
impl core::ops::Add<Span> for Timestamp {
2398
    type Output = Timestamp;
2399
2400
    #[inline]
2401
0
    fn add(self, rhs: Span) -> Timestamp {
2402
0
        self.checked_add_span(&rhs).expect("adding span to timestamp failed")
2403
0
    }
2404
}
2405
2406
/// Adds a span of time to a timestamp in place.
2407
///
2408
/// This uses checked arithmetic and panics when it fails. To handle arithmetic
2409
/// without panics, use [`Timestamp::checked_add`]. Note that the failure
2410
/// condition includes overflow and using a `Span` with non-zero units greater
2411
/// than hours.
2412
impl core::ops::AddAssign<Span> for Timestamp {
2413
    #[inline]
2414
0
    fn add_assign(&mut self, rhs: Span) {
2415
0
        *self = *self + rhs
2416
0
    }
2417
}
2418
2419
/// Subtracts a span of time from a timestamp.
2420
///
2421
/// This uses checked arithmetic and panics when it fails. To handle arithmetic
2422
/// without panics, use [`Timestamp::checked_sub`]. Note that the failure
2423
/// condition includes overflow and using a `Span` with non-zero units greater
2424
/// than hours.
2425
impl core::ops::Sub<Span> for Timestamp {
2426
    type Output = Timestamp;
2427
2428
    #[inline]
2429
0
    fn sub(self, rhs: Span) -> Timestamp {
2430
0
        self.checked_add_span(&rhs.negate())
2431
0
            .expect("subtracting span from timestamp failed")
2432
0
    }
2433
}
2434
2435
/// Subtracts a span of time from a timestamp in place.
2436
///
2437
/// This uses checked arithmetic and panics when it fails. To handle arithmetic
2438
/// without panics, use [`Timestamp::checked_sub`]. Note that the failure
2439
/// condition includes overflow and using a `Span` with non-zero units greater
2440
/// than hours.
2441
impl core::ops::SubAssign<Span> for Timestamp {
2442
    #[inline]
2443
0
    fn sub_assign(&mut self, rhs: Span) {
2444
0
        *self = *self - rhs
2445
0
    }
2446
}
2447
2448
/// Computes the span of time between two timestamps.
2449
///
2450
/// This will return a negative span when the timestamp being subtracted is
2451
/// greater.
2452
///
2453
/// Since this uses the default configuration for calculating a span between
2454
/// two timestamps (no rounding and largest units is seconds), this will never
2455
/// panic or fail in any way.
2456
///
2457
/// To configure the largest unit or enable rounding, use [`Timestamp::since`].
2458
impl core::ops::Sub for Timestamp {
2459
    type Output = Span;
2460
2461
    #[inline]
2462
0
    fn sub(self, rhs: Timestamp) -> Span {
2463
0
        self.since(rhs).expect("since never fails when given Timestamp")
2464
0
    }
2465
}
2466
2467
/// Adds a signed duration of time to a timestamp.
2468
///
2469
/// This uses checked arithmetic and panics on overflow. To handle overflow
2470
/// without panics, use [`Timestamp::checked_add`].
2471
impl core::ops::Add<SignedDuration> for Timestamp {
2472
    type Output = Timestamp;
2473
2474
    #[inline]
2475
0
    fn add(self, rhs: SignedDuration) -> Timestamp {
2476
0
        self.checked_add_duration(rhs)
2477
0
            .expect("adding signed duration to timestamp overflowed")
2478
0
    }
2479
}
2480
2481
/// Adds a signed duration of time to a timestamp in place.
2482
///
2483
/// This uses checked arithmetic and panics on overflow. To handle overflow
2484
/// without panics, use [`Timestamp::checked_add`].
2485
impl core::ops::AddAssign<SignedDuration> for Timestamp {
2486
    #[inline]
2487
0
    fn add_assign(&mut self, rhs: SignedDuration) {
2488
0
        *self = *self + rhs
2489
0
    }
2490
}
2491
2492
/// Subtracts a signed duration of time from a timestamp.
2493
///
2494
/// This uses checked arithmetic and panics on overflow. To handle overflow
2495
/// without panics, use [`Timestamp::checked_sub`].
2496
impl core::ops::Sub<SignedDuration> for Timestamp {
2497
    type Output = Timestamp;
2498
2499
    #[inline]
2500
0
    fn sub(self, rhs: SignedDuration) -> Timestamp {
2501
0
        let rhs = rhs
2502
0
            .checked_neg()
2503
0
            .expect("signed duration negation resulted in overflow");
2504
0
        self.checked_add_duration(rhs)
2505
0
            .expect("subtracting signed duration from timestamp overflowed")
2506
0
    }
2507
}
2508
2509
/// Subtracts a signed duration of time from a timestamp in place.
2510
///
2511
/// This uses checked arithmetic and panics on overflow. To handle overflow
2512
/// without panics, use [`Timestamp::checked_sub`].
2513
impl core::ops::SubAssign<SignedDuration> for Timestamp {
2514
    #[inline]
2515
0
    fn sub_assign(&mut self, rhs: SignedDuration) {
2516
0
        *self = *self - rhs
2517
0
    }
2518
}
2519
2520
/// Adds an unsigned duration of time to a timestamp.
2521
///
2522
/// This uses checked arithmetic and panics on overflow. To handle overflow
2523
/// without panics, use [`Timestamp::checked_add`].
2524
impl core::ops::Add<UnsignedDuration> for Timestamp {
2525
    type Output = Timestamp;
2526
2527
    #[inline]
2528
0
    fn add(self, rhs: UnsignedDuration) -> Timestamp {
2529
0
        self.checked_add(rhs)
2530
0
            .expect("adding unsigned duration to timestamp overflowed")
2531
0
    }
2532
}
2533
2534
/// Adds an unsigned duration of time to a timestamp in place.
2535
///
2536
/// This uses checked arithmetic and panics on overflow. To handle overflow
2537
/// without panics, use [`Timestamp::checked_add`].
2538
impl core::ops::AddAssign<UnsignedDuration> for Timestamp {
2539
    #[inline]
2540
0
    fn add_assign(&mut self, rhs: UnsignedDuration) {
2541
0
        *self = *self + rhs
2542
0
    }
2543
}
2544
2545
/// Subtracts an unsigned duration of time from a timestamp.
2546
///
2547
/// This uses checked arithmetic and panics on overflow. To handle overflow
2548
/// without panics, use [`Timestamp::checked_sub`].
2549
impl core::ops::Sub<UnsignedDuration> for Timestamp {
2550
    type Output = Timestamp;
2551
2552
    #[inline]
2553
0
    fn sub(self, rhs: UnsignedDuration) -> Timestamp {
2554
0
        self.checked_sub(rhs)
2555
0
            .expect("subtracting unsigned duration from timestamp overflowed")
2556
0
    }
2557
}
2558
2559
/// Subtracts an unsigned duration of time from a timestamp in place.
2560
///
2561
/// This uses checked arithmetic and panics on overflow. To handle overflow
2562
/// without panics, use [`Timestamp::checked_sub`].
2563
impl core::ops::SubAssign<UnsignedDuration> for Timestamp {
2564
    #[inline]
2565
0
    fn sub_assign(&mut self, rhs: UnsignedDuration) {
2566
0
        *self = *self - rhs
2567
0
    }
2568
}
2569
2570
impl From<Zoned> for Timestamp {
2571
    #[inline]
2572
0
    fn from(zdt: Zoned) -> Timestamp {
2573
0
        zdt.timestamp()
2574
0
    }
2575
}
2576
2577
impl<'a> From<&'a Zoned> for Timestamp {
2578
    #[inline]
2579
0
    fn from(zdt: &'a Zoned) -> Timestamp {
2580
0
        zdt.timestamp()
2581
0
    }
2582
}
2583
2584
#[cfg(feature = "std")]
2585
impl From<Timestamp> for std::time::SystemTime {
2586
    #[inline]
2587
0
    fn from(time: Timestamp) -> std::time::SystemTime {
2588
0
        let unix_epoch = std::time::SystemTime::UNIX_EPOCH;
2589
0
        let sdur = time.as_duration();
2590
0
        let dur = sdur.unsigned_abs();
2591
        // These are guaranteed to succeed because we assume that SystemTime
2592
        // uses at least 64 bits for the time, and our durations are capped via
2593
        // the range on UnixSeconds.
2594
0
        if sdur.is_negative() {
2595
0
            unix_epoch.checked_sub(dur).expect("duration too big (negative)")
2596
        } else {
2597
0
            unix_epoch.checked_add(dur).expect("duration too big (positive)")
2598
        }
2599
0
    }
Unexecuted instantiation: <std::time::SystemTime as core::convert::From<jiff::timestamp::Timestamp>>::from
Unexecuted instantiation: <std::time::SystemTime as core::convert::From<jiff::timestamp::Timestamp>>::from
2600
}
2601
2602
#[cfg(feature = "std")]
2603
impl TryFrom<std::time::SystemTime> for Timestamp {
2604
    type Error = Error;
2605
2606
    #[inline]
2607
72.2k
    fn try_from(
2608
72.2k
        system_time: std::time::SystemTime,
2609
72.2k
    ) -> Result<Timestamp, Error> {
2610
72.2k
        let unix_epoch = std::time::SystemTime::UNIX_EPOCH;
2611
72.2k
        let dur = SignedDuration::system_until(unix_epoch, system_time)?;
2612
72.2k
        Timestamp::from_duration(dur)
2613
72.2k
    }
Unexecuted instantiation: <jiff::timestamp::Timestamp as core::convert::TryFrom<std::time::SystemTime>>::try_from
Unexecuted instantiation: <jiff::timestamp::Timestamp as core::convert::TryFrom<std::time::SystemTime>>::try_from
<jiff::timestamp::Timestamp as core::convert::TryFrom<std::time::SystemTime>>::try_from
Line
Count
Source
2607
72.2k
    fn try_from(
2608
72.2k
        system_time: std::time::SystemTime,
2609
72.2k
    ) -> Result<Timestamp, Error> {
2610
72.2k
        let unix_epoch = std::time::SystemTime::UNIX_EPOCH;
2611
72.2k
        let dur = SignedDuration::system_until(unix_epoch, system_time)?;
2612
72.2k
        Timestamp::from_duration(dur)
2613
72.2k
    }
<jiff::timestamp::Timestamp as core::convert::TryFrom<std::time::SystemTime>>::try_from
Line
Count
Source
2607
6
    fn try_from(
2608
6
        system_time: std::time::SystemTime,
2609
6
    ) -> Result<Timestamp, Error> {
2610
6
        let unix_epoch = std::time::SystemTime::UNIX_EPOCH;
2611
6
        let dur = SignedDuration::system_until(unix_epoch, system_time)?;
2612
6
        Timestamp::from_duration(dur)
2613
6
    }
2614
}
2615
2616
#[cfg(feature = "defmt")]
2617
impl defmt::Format for Timestamp {
2618
    fn format(&self, f: defmt::Formatter) {
2619
        use crate::fmt::{temporal::DEFAULT_DATETIME_PRINTER, DefmtWrite};
2620
2621
        defmt::unwrap!(
2622
            DEFAULT_DATETIME_PRINTER.print_timestamp(self, DefmtWrite(f))
2623
        );
2624
    }
2625
}
2626
2627
#[cfg(feature = "serde")]
2628
impl serde_core::Serialize for Timestamp {
2629
    #[inline]
2630
0
    fn serialize<S: serde_core::Serializer>(
2631
0
        &self,
2632
0
        serializer: S,
2633
0
    ) -> Result<S::Ok, S::Error> {
2634
0
        serializer.collect_str(self)
2635
0
    }
2636
}
2637
2638
#[cfg(feature = "serde")]
2639
impl<'de> serde_core::Deserialize<'de> for Timestamp {
2640
    #[inline]
2641
0
    fn deserialize<D: serde_core::Deserializer<'de>>(
2642
0
        deserializer: D,
2643
0
    ) -> Result<Timestamp, D::Error> {
2644
        use serde_core::de;
2645
2646
        struct TimestampVisitor;
2647
2648
        impl<'de> de::Visitor<'de> for TimestampVisitor {
2649
            type Value = Timestamp;
2650
2651
0
            fn expecting(
2652
0
                &self,
2653
0
                f: &mut core::fmt::Formatter,
2654
0
            ) -> core::fmt::Result {
2655
0
                f.write_str("a timestamp string")
2656
0
            }
2657
2658
            #[inline]
2659
0
            fn visit_bytes<E: de::Error>(
2660
0
                self,
2661
0
                value: &[u8],
2662
0
            ) -> Result<Timestamp, E> {
2663
0
                DEFAULT_DATETIME_PARSER
2664
0
                    .parse_timestamp(value)
2665
0
                    .map_err(de::Error::custom)
2666
0
            }
2667
2668
            #[inline]
2669
0
            fn visit_str<E: de::Error>(
2670
0
                self,
2671
0
                value: &str,
2672
0
            ) -> Result<Timestamp, E> {
2673
0
                self.visit_bytes(value.as_bytes())
2674
0
            }
2675
        }
2676
2677
0
        deserializer.deserialize_str(TimestampVisitor)
2678
0
    }
2679
}
2680
2681
#[cfg(test)]
2682
impl quickcheck::Arbitrary for Timestamp {
2683
    fn arbitrary(g: &mut quickcheck::Gen) -> Timestamp {
2684
        use crate::util::b;
2685
2686
        let secs = b::UnixEpochSeconds::arbitrary(g);
2687
        let mut nanos = b::SignedSubsecNanosecond::arbitrary(g);
2688
        // nanoseconds must be zero for the minimum second value,
2689
        // so just clamp it to 0.
2690
        if secs == b::UnixEpochSeconds::MIN && nanos < 0 {
2691
            nanos = 0;
2692
        }
2693
        Timestamp::new(secs, nanos).unwrap_or_default()
2694
    }
2695
2696
    fn shrink(&self) -> alloc::boxed::Box<dyn Iterator<Item = Self>> {
2697
        use crate::util::b;
2698
2699
        let secs = self.as_second();
2700
        let nanos = self.subsec_nanosecond();
2701
        alloc::boxed::Box::new((secs, nanos).shrink().filter_map(
2702
            |(secs, nanos)| {
2703
                let secs = b::UnixEpochSeconds::check(secs).ok()?;
2704
                let nanos = b::SignedSubsecNanosecond::check(nanos).ok()?;
2705
                if secs == b::UnixEpochSeconds::MIN && nanos > 0 {
2706
                    None
2707
                } else {
2708
                    Timestamp::new(secs, nanos).ok()
2709
                }
2710
            },
2711
        ))
2712
    }
2713
}
2714
2715
/// A type for formatting a [`Timestamp`] with a specific offset.
2716
///
2717
/// This type is created by the [`Timestamp::display_with_offset`] method.
2718
///
2719
/// Like the [`std::fmt::Display`] trait implementation for `Timestamp`, this
2720
/// always emits an RFC 3339 compliant string. Unlike `Timestamp`'s `Display`
2721
/// trait implementation, which always uses `Z` or "Zulu" time, this always
2722
/// uses an offset.
2723
///
2724
/// # Formatting options supported
2725
///
2726
/// * [`std::fmt::Formatter::precision`] can be set to control the precision
2727
/// of the fractional second component.
2728
///
2729
/// # Example
2730
///
2731
/// ```
2732
/// use jiff::{tz, Timestamp};
2733
///
2734
/// let offset = tz::offset(-5);
2735
/// let ts = Timestamp::new(1_123_456_789, 123_000_000)?;
2736
/// assert_eq!(
2737
///     format!("{ts:.6}", ts = ts.display_with_offset(offset)),
2738
///     "2005-08-07T18:19:49.123000-05:00",
2739
/// );
2740
/// // Precision values greater than 9 are clamped to 9.
2741
/// assert_eq!(
2742
///     format!("{ts:.300}", ts = ts.display_with_offset(offset)),
2743
///     "2005-08-07T18:19:49.123000000-05:00",
2744
/// );
2745
/// // A precision of 0 implies the entire fractional
2746
/// // component is always truncated.
2747
/// assert_eq!(
2748
///     format!("{ts:.0}", ts = ts.display_with_offset(tz::Offset::UTC)),
2749
///     "2005-08-07T23:19:49+00:00",
2750
/// );
2751
///
2752
/// # Ok::<(), Box<dyn std::error::Error>>(())
2753
/// ```
2754
#[derive(Clone, Copy, Debug)]
2755
pub struct TimestampDisplayWithOffset {
2756
    timestamp: Timestamp,
2757
    offset: Offset,
2758
}
2759
2760
impl core::fmt::Display for TimestampDisplayWithOffset {
2761
    #[inline]
2762
0
    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
2763
        use crate::fmt::StdFmtWrite;
2764
2765
0
        let precision =
2766
0
            f.precision().map(|p| u8::try_from(p).unwrap_or(u8::MAX));
Unexecuted instantiation: <jiff::timestamp::TimestampDisplayWithOffset as core::fmt::Display>::fmt::{closure#0}
Unexecuted instantiation: <jiff::timestamp::TimestampDisplayWithOffset as core::fmt::Display>::fmt::{closure#0}
2767
0
        temporal::DateTimePrinter::new()
2768
0
            .precision(precision)
2769
0
            .print_timestamp_with_offset(
2770
0
                &self.timestamp,
2771
0
                self.offset,
2772
0
                StdFmtWrite(f),
2773
            )
2774
0
            .map_err(|_| core::fmt::Error)
2775
0
    }
Unexecuted instantiation: <jiff::timestamp::TimestampDisplayWithOffset as core::fmt::Display>::fmt
Unexecuted instantiation: <jiff::timestamp::TimestampDisplayWithOffset as core::fmt::Display>::fmt
2776
}
2777
2778
/// An iterator over periodic timestamps, created by [`Timestamp::series`].
2779
///
2780
/// It is exhausted when the next value would exceed the limits of a [`Span`]
2781
/// or [`Timestamp`] value.
2782
///
2783
/// This iterator is created by [`Timestamp::series`].
2784
#[derive(Clone, Debug)]
2785
pub struct TimestampSeries {
2786
    ts: Timestamp,
2787
    duration: Option<SignedDuration>,
2788
}
2789
2790
impl TimestampSeries {
2791
    #[inline]
2792
0
    fn new(ts: Timestamp, period: Span) -> TimestampSeries {
2793
0
        let duration = SignedDuration::try_from(period).ok();
2794
0
        TimestampSeries { ts, duration }
2795
0
    }
2796
}
2797
2798
impl Iterator for TimestampSeries {
2799
    type Item = Timestamp;
2800
2801
    #[inline]
2802
0
    fn next(&mut self) -> Option<Timestamp> {
2803
0
        let duration = self.duration?;
2804
0
        let this = self.ts;
2805
0
        self.ts = self.ts.checked_add_duration(duration).ok()?;
2806
0
        Some(this)
2807
0
    }
2808
}
2809
2810
impl core::iter::FusedIterator for TimestampSeries {}
2811
2812
/// Options for [`Timestamp::checked_add`] and [`Timestamp::checked_sub`].
2813
///
2814
/// This type provides a way to ergonomically add one of a few different
2815
/// duration types to a [`Timestamp`].
2816
///
2817
/// The main way to construct values of this type is with its `From` trait
2818
/// implementations:
2819
///
2820
/// * `From<Span> for TimestampArithmetic` adds (or subtracts) the given span
2821
/// to the receiver timestamp.
2822
/// * `From<SignedDuration> for TimestampArithmetic` adds (or subtracts)
2823
/// the given signed duration to the receiver timestamp.
2824
/// * `From<std::time::Duration> for TimestampArithmetic` adds (or subtracts)
2825
/// the given unsigned duration to the receiver timestamp.
2826
///
2827
/// # Example
2828
///
2829
/// ```
2830
/// use std::time::Duration;
2831
///
2832
/// use jiff::{SignedDuration, Timestamp, ToSpan};
2833
///
2834
/// let ts: Timestamp = "2024-02-28T00:00:00Z".parse()?;
2835
/// assert_eq!(
2836
///     ts.checked_add(48.hours())?,
2837
///     "2024-03-01T00:00:00Z".parse()?,
2838
/// );
2839
/// assert_eq!(
2840
///     ts.checked_add(SignedDuration::from_hours(48))?,
2841
///     "2024-03-01T00:00:00Z".parse()?,
2842
/// );
2843
/// assert_eq!(
2844
///     ts.checked_add(Duration::from_secs(48 * 60 * 60))?,
2845
///     "2024-03-01T00:00:00Z".parse()?,
2846
/// );
2847
///
2848
/// # Ok::<(), Box<dyn std::error::Error>>(())
2849
/// ```
2850
#[derive(Clone, Copy, Debug)]
2851
pub struct TimestampArithmetic {
2852
    duration: Duration,
2853
}
2854
2855
impl TimestampArithmetic {
2856
    #[inline]
2857
0
    fn checked_add(self, ts: Timestamp) -> Result<Timestamp, Error> {
2858
0
        match self.duration.to_signed()? {
2859
0
            SDuration::Span(span) => ts.checked_add_span(span),
2860
0
            SDuration::Absolute(sdur) => ts.checked_add_duration(sdur),
2861
        }
2862
0
    }
Unexecuted instantiation: <jiff::timestamp::TimestampArithmetic>::checked_add
Unexecuted instantiation: <jiff::timestamp::TimestampArithmetic>::checked_add
2863
2864
    #[inline]
2865
0
    fn saturating_add(self, ts: Timestamp) -> Result<Timestamp, Error> {
2866
0
        let Ok(signed) = self.duration.to_signed() else {
2867
0
            return Ok(Timestamp::MAX);
2868
        };
2869
0
        let result = match signed {
2870
0
            SDuration::Span(span) => {
2871
0
                if let Some(err) = span.smallest_non_time_non_zero_unit_error()
2872
                {
2873
0
                    return Err(err);
2874
0
                }
2875
0
                ts.checked_add_span(span)
2876
            }
2877
0
            SDuration::Absolute(sdur) => ts.checked_add_duration(sdur),
2878
        };
2879
0
        Ok(result.unwrap_or_else(|_| {
2880
0
            if self.is_negative() {
2881
0
                Timestamp::MIN
2882
            } else {
2883
0
                Timestamp::MAX
2884
            }
2885
0
        }))
2886
0
    }
2887
2888
    #[inline]
2889
0
    fn checked_neg(self) -> Result<TimestampArithmetic, Error> {
2890
0
        let duration = self.duration.checked_neg()?;
2891
0
        Ok(TimestampArithmetic { duration })
2892
0
    }
Unexecuted instantiation: <jiff::timestamp::TimestampArithmetic>::checked_neg
Unexecuted instantiation: <jiff::timestamp::TimestampArithmetic>::checked_neg
2893
2894
    #[inline]
2895
0
    fn is_negative(&self) -> bool {
2896
0
        self.duration.is_negative()
2897
0
    }
2898
}
2899
2900
impl From<Span> for TimestampArithmetic {
2901
0
    fn from(span: Span) -> TimestampArithmetic {
2902
0
        let duration = Duration::from(span);
2903
0
        TimestampArithmetic { duration }
2904
0
    }
2905
}
2906
2907
impl From<SignedDuration> for TimestampArithmetic {
2908
0
    fn from(sdur: SignedDuration) -> TimestampArithmetic {
2909
0
        let duration = Duration::from(sdur);
2910
0
        TimestampArithmetic { duration }
2911
0
    }
2912
}
2913
2914
impl From<UnsignedDuration> for TimestampArithmetic {
2915
0
    fn from(udur: UnsignedDuration) -> TimestampArithmetic {
2916
0
        let duration = Duration::from(udur);
2917
0
        TimestampArithmetic { duration }
2918
0
    }
2919
}
2920
2921
impl<'a> From<&'a Span> for TimestampArithmetic {
2922
0
    fn from(span: &'a Span) -> TimestampArithmetic {
2923
0
        TimestampArithmetic::from(*span)
2924
0
    }
2925
}
2926
2927
impl<'a> From<&'a SignedDuration> for TimestampArithmetic {
2928
0
    fn from(sdur: &'a SignedDuration) -> TimestampArithmetic {
2929
0
        TimestampArithmetic::from(*sdur)
2930
0
    }
2931
}
2932
2933
impl<'a> From<&'a UnsignedDuration> for TimestampArithmetic {
2934
0
    fn from(udur: &'a UnsignedDuration) -> TimestampArithmetic {
2935
0
        TimestampArithmetic::from(*udur)
2936
0
    }
2937
}
2938
2939
/// Options for [`Timestamp::since`] and [`Timestamp::until`].
2940
///
2941
/// This type provides a way to configure the calculation of
2942
/// spans between two [`Timestamp`] values. In particular, both
2943
/// `Timestamp::since` and `Timestamp::until` accept anything that implements
2944
/// `Into<TimestampDifference>`. There are a few key trait implementations that
2945
/// make this convenient:
2946
///
2947
/// * `From<Timestamp> for TimestampDifference` will construct a
2948
/// configuration consisting of just the timestamp. So for example,
2949
/// `timestamp1.until(timestamp2)` will return the span from `timestamp1` to
2950
/// `timestamp2`.
2951
/// * `From<Zoned> for TimestampDifference` will construct a configuration
2952
/// consisting of the timestamp from the given zoned datetime. So for example,
2953
/// `timestamp.since(zoned)` returns the span from `zoned.to_timestamp()` to
2954
/// `timestamp`.
2955
/// * `From<(Unit, Timestamp)>` is a convenient way to specify the largest
2956
/// units that should be present on the span returned. By default, the largest
2957
/// units are seconds. Using this trait implementation is equivalent to
2958
/// `TimestampDifference::new(timestamp).largest(unit)`.
2959
/// * `From<(Unit, Zoned)>` is like the one above, but with the time from
2960
/// the given zoned datetime.
2961
///
2962
/// One can also provide a `TimestampDifference` value directly. Doing so
2963
/// is necessary to use the rounding features of calculating a span. For
2964
/// example, setting the smallest unit (defaults to [`Unit::Nanosecond`]), the
2965
/// rounding mode (defaults to [`RoundMode::Trunc`]) and the rounding increment
2966
/// (defaults to `1`). The defaults are selected such that no rounding occurs.
2967
///
2968
/// Rounding a span as part of calculating it is provided as a convenience.
2969
/// Callers may choose to round the span as a distinct step via
2970
/// [`Span::round`].
2971
///
2972
/// # Example
2973
///
2974
/// This example shows how to round a span between two timestamps to the
2975
/// nearest half-hour, with ties breaking away from zero.
2976
///
2977
/// ```
2978
/// use jiff::{RoundMode, Timestamp, TimestampDifference, ToSpan, Unit};
2979
///
2980
/// let ts1 = "2024-03-15 08:14:00.123456789Z".parse::<Timestamp>()?;
2981
/// let ts2 = "2024-03-22 15:00Z".parse::<Timestamp>()?;
2982
/// let span = ts1.until(
2983
///     TimestampDifference::new(ts2)
2984
///         .smallest(Unit::Minute)
2985
///         .largest(Unit::Hour)
2986
///         .mode(RoundMode::HalfExpand)
2987
///         .increment(30),
2988
/// )?;
2989
/// assert_eq!(format!("{span:#}"), "175h");
2990
///
2991
/// // One less minute, and because of the HalfExpand mode, the span would
2992
/// // get rounded down.
2993
/// let ts2 = "2024-03-22 14:59Z".parse::<Timestamp>()?;
2994
/// let span = ts1.until(
2995
///     TimestampDifference::new(ts2)
2996
///         .smallest(Unit::Minute)
2997
///         .largest(Unit::Hour)
2998
///         .mode(RoundMode::HalfExpand)
2999
///         .increment(30),
3000
/// )?;
3001
/// assert_eq!(span, 174.hours().minutes(30).fieldwise());
3002
///
3003
/// # Ok::<(), Box<dyn std::error::Error>>(())
3004
/// ```
3005
#[derive(Clone, Copy, Debug)]
3006
pub struct TimestampDifference {
3007
    timestamp: Timestamp,
3008
    round: SpanRound<'static>,
3009
}
3010
3011
impl TimestampDifference {
3012
    /// Create a new default configuration for computing the span between
3013
    /// the given timestamp and some other time (specified as the receiver in
3014
    /// [`Timestamp::since`] or [`Timestamp::until`]).
3015
    #[inline]
3016
0
    pub fn new(timestamp: Timestamp) -> TimestampDifference {
3017
        // We use truncation rounding by default since it seems that's
3018
        // what is generally expected when computing the difference between
3019
        // datetimes.
3020
        //
3021
        // See: https://github.com/tc39/proposal-temporal/issues/1122
3022
0
        let round = SpanRound::new().mode(RoundMode::Trunc);
3023
0
        TimestampDifference { timestamp, round }
3024
0
    }
3025
3026
    /// Set the smallest units allowed in the span returned.
3027
    ///
3028
    /// # Errors
3029
    ///
3030
    /// The smallest units must be no greater than the largest units. If this
3031
    /// is violated, then computing a span with this configuration will result
3032
    /// in an error.
3033
    ///
3034
    /// The largest unit must also be no greater than `Unit::Hour`.
3035
    ///
3036
    /// # Example
3037
    ///
3038
    /// This shows how to round a span between two timestamps to units no less
3039
    /// than seconds.
3040
    ///
3041
    /// ```
3042
    /// use jiff::{RoundMode, Timestamp, TimestampDifference, ToSpan, Unit};
3043
    ///
3044
    /// let ts1 = "2024-03-15 08:14:02.5001Z".parse::<Timestamp>()?;
3045
    /// let ts2 = "2024-03-15T08:16:03.0001Z".parse::<Timestamp>()?;
3046
    /// let span = ts1.until(
3047
    ///     TimestampDifference::new(ts2)
3048
    ///         .smallest(Unit::Second)
3049
    ///         .mode(RoundMode::HalfExpand),
3050
    /// )?;
3051
    /// assert_eq!(span, 121.seconds().fieldwise());
3052
    ///
3053
    /// // Because of the rounding mode, a small less-than-1-second increase in
3054
    /// // the first timestamp can change the result of rounding.
3055
    /// let ts1 = "2024-03-15 08:14:02.5002Z".parse::<Timestamp>()?;
3056
    /// let span = ts1.until(
3057
    ///     TimestampDifference::new(ts2)
3058
    ///         .smallest(Unit::Second)
3059
    ///         .mode(RoundMode::HalfExpand),
3060
    /// )?;
3061
    /// assert_eq!(span, 120.seconds().fieldwise());
3062
    ///
3063
    /// # Ok::<(), Box<dyn std::error::Error>>(())
3064
    /// ```
3065
    #[inline]
3066
0
    pub fn smallest(self, unit: Unit) -> TimestampDifference {
3067
0
        TimestampDifference { round: self.round.smallest(unit), ..self }
3068
0
    }
3069
3070
    /// Set the largest units allowed in the span returned.
3071
    ///
3072
    /// When a largest unit is not specified, computing a span between
3073
    /// timestamps behaves as if it were set to [`Unit::Second`]. Unless
3074
    /// [`TimestampDifference::smallest`] is bigger than `Unit::Second`, then
3075
    /// the largest unit is set to the smallest unit.
3076
    ///
3077
    /// # Errors
3078
    ///
3079
    /// The largest units, when set, must be at least as big as the smallest
3080
    /// units (which defaults to [`Unit::Nanosecond`]). If this is violated,
3081
    /// then computing a span with this configuration will result in an error.
3082
    ///
3083
    /// The largest unit must also be no greater than `Unit::Hour`.
3084
    ///
3085
    /// # Example
3086
    ///
3087
    /// This shows how to round a span between two timestamps to units no
3088
    /// bigger than seconds.
3089
    ///
3090
    /// ```
3091
    /// use jiff::{Timestamp, TimestampDifference, ToSpan, Unit};
3092
    ///
3093
    /// let ts1 = "2024-03-15 08:14Z".parse::<Timestamp>()?;
3094
    /// let ts2 = "2030-11-22 08:30Z".parse::<Timestamp>()?;
3095
    /// let span = ts1.until(
3096
    ///     TimestampDifference::new(ts2).largest(Unit::Second),
3097
    /// )?;
3098
    /// assert_eq!(format!("{span:#}"), "211076160s");
3099
    ///
3100
    /// # Ok::<(), Box<dyn std::error::Error>>(())
3101
    /// ```
3102
    #[inline]
3103
0
    pub fn largest(self, unit: Unit) -> TimestampDifference {
3104
0
        TimestampDifference { round: self.round.largest(unit), ..self }
3105
0
    }
3106
3107
    /// Set the rounding mode.
3108
    ///
3109
    /// This defaults to [`RoundMode::Trunc`] since it's plausible that
3110
    /// rounding "up" in the context of computing the span between
3111
    /// two timestamps could be surprising in a number of cases. The
3112
    /// [`RoundMode::HalfExpand`] mode corresponds to typical rounding you
3113
    /// might have learned about in school. But a variety of other rounding
3114
    /// modes exist.
3115
    ///
3116
    /// # Example
3117
    ///
3118
    /// This shows how to always round "up" towards positive infinity.
3119
    ///
3120
    /// ```
3121
    /// use jiff::{RoundMode, Timestamp, TimestampDifference, ToSpan, Unit};
3122
    ///
3123
    /// let ts1 = "2024-03-15 08:10Z".parse::<Timestamp>()?;
3124
    /// let ts2 = "2024-03-15 08:11Z".parse::<Timestamp>()?;
3125
    /// let span = ts1.until(
3126
    ///     TimestampDifference::new(ts2)
3127
    ///         .smallest(Unit::Hour)
3128
    ///         .mode(RoundMode::Ceil),
3129
    /// )?;
3130
    /// // Only one minute elapsed, but we asked to always round up!
3131
    /// assert_eq!(span, 1.hour().fieldwise());
3132
    ///
3133
    /// // Since `Ceil` always rounds toward positive infinity, the behavior
3134
    /// // flips for a negative span.
3135
    /// let span = ts1.since(
3136
    ///     TimestampDifference::new(ts2)
3137
    ///         .smallest(Unit::Hour)
3138
    ///         .mode(RoundMode::Ceil),
3139
    /// )?;
3140
    /// assert_eq!(span, 0.hour().fieldwise());
3141
    ///
3142
    /// # Ok::<(), Box<dyn std::error::Error>>(())
3143
    /// ```
3144
    #[inline]
3145
0
    pub fn mode(self, mode: RoundMode) -> TimestampDifference {
3146
0
        TimestampDifference { round: self.round.mode(mode), ..self }
3147
0
    }
3148
3149
    /// Set the rounding increment for the smallest unit.
3150
    ///
3151
    /// The default value is `1`. Other values permit rounding the smallest
3152
    /// unit to the nearest integer increment specified. For example, if the
3153
    /// smallest unit is set to [`Unit::Minute`], then a rounding increment of
3154
    /// `30` would result in rounding in increments of a half hour. That is,
3155
    /// the only minute value that could result would be `0` or `30`.
3156
    ///
3157
    /// # Errors
3158
    ///
3159
    /// The rounding increment must divide evenly into the next highest unit
3160
    /// after the smallest unit configured (and must not be equivalent to it).
3161
    /// For example, if the smallest unit is [`Unit::Nanosecond`], then *some*
3162
    /// of the valid values for the rounding increment are `1`, `2`, `4`, `5`,
3163
    /// `100` and `500`. Namely, any integer that divides evenly into `1,000`
3164
    /// nanoseconds since there are `1,000` nanoseconds in the next highest
3165
    /// unit (microseconds).
3166
    ///
3167
    /// In all cases, the increment must be greater than zero and less than or
3168
    /// equal to `1_000_000_000`.
3169
    ///
3170
    /// The error will occur when computing the span, and not when setting
3171
    /// the increment here.
3172
    ///
3173
    /// # Example
3174
    ///
3175
    /// This shows how to round the span between two timestamps to the nearest
3176
    /// 5 minute increment.
3177
    ///
3178
    /// ```
3179
    /// use jiff::{RoundMode, Timestamp, TimestampDifference, ToSpan, Unit};
3180
    ///
3181
    /// let ts1 = "2024-03-15 08:19Z".parse::<Timestamp>()?;
3182
    /// let ts2 = "2024-03-15 12:52Z".parse::<Timestamp>()?;
3183
    /// let span = ts1.until(
3184
    ///     TimestampDifference::new(ts2)
3185
    ///         .smallest(Unit::Minute)
3186
    ///         .increment(5)
3187
    ///         .mode(RoundMode::HalfExpand),
3188
    /// )?;
3189
    /// assert_eq!(span.to_string(), "PT275M");
3190
    ///
3191
    /// # Ok::<(), Box<dyn std::error::Error>>(())
3192
    /// ```
3193
    #[inline]
3194
0
    pub fn increment(self, increment: i64) -> TimestampDifference {
3195
0
        TimestampDifference { round: self.round.increment(increment), ..self }
3196
0
    }
3197
3198
    /// Returns true if and only if this configuration could change the span
3199
    /// via rounding.
3200
    #[inline]
3201
0
    fn rounding_may_change_span(&self) -> bool {
3202
0
        self.round.rounding_may_change_span()
3203
0
    }
3204
3205
    /// Returns the span of time from `ts1` to the timestamp in this
3206
    /// configuration. The biggest units allowed are determined by the
3207
    /// `smallest` and `largest` settings, but defaults to `Unit::Second`.
3208
    #[inline]
3209
0
    fn until_with_largest_unit(&self, t1: Timestamp) -> Result<Span, Error> {
3210
0
        let t2 = self.timestamp;
3211
0
        let largest = self
3212
0
            .round
3213
0
            .get_largest()
3214
0
            .unwrap_or_else(|| self.round.get_smallest().max(Unit::Second));
3215
0
        if largest >= Unit::Day {
3216
0
            return Err(Error::from(
3217
0
                UnitConfigError::RoundToUnitUnsupported { unit: largest },
3218
0
            ));
3219
0
        }
3220
3221
0
        let diff = t2.as_duration() - t1.as_duration();
3222
        // This can fail when `largest` is nanoseconds since not all intervals
3223
        // can be represented by a single i64 in units of nanoseconds.
3224
0
        Span::from_invariant_duration(largest, diff)
3225
0
    }
3226
}
3227
3228
impl From<Timestamp> for TimestampDifference {
3229
    #[inline]
3230
0
    fn from(ts: Timestamp) -> TimestampDifference {
3231
0
        TimestampDifference::new(ts)
3232
0
    }
3233
}
3234
3235
impl From<Zoned> for TimestampDifference {
3236
    #[inline]
3237
0
    fn from(zdt: Zoned) -> TimestampDifference {
3238
0
        TimestampDifference::new(Timestamp::from(zdt))
3239
0
    }
3240
}
3241
3242
impl<'a> From<&'a Zoned> for TimestampDifference {
3243
    #[inline]
3244
0
    fn from(zdt: &'a Zoned) -> TimestampDifference {
3245
0
        TimestampDifference::from(Timestamp::from(zdt))
3246
0
    }
3247
}
3248
3249
impl From<(Unit, Timestamp)> for TimestampDifference {
3250
    #[inline]
3251
0
    fn from((largest, ts): (Unit, Timestamp)) -> TimestampDifference {
3252
0
        TimestampDifference::from(ts).largest(largest)
3253
0
    }
3254
}
3255
3256
impl From<(Unit, Zoned)> for TimestampDifference {
3257
    #[inline]
3258
0
    fn from((largest, zdt): (Unit, Zoned)) -> TimestampDifference {
3259
0
        TimestampDifference::from((largest, Timestamp::from(zdt)))
3260
0
    }
3261
}
3262
3263
impl<'a> From<(Unit, &'a Zoned)> for TimestampDifference {
3264
    #[inline]
3265
0
    fn from((largest, zdt): (Unit, &'a Zoned)) -> TimestampDifference {
3266
0
        TimestampDifference::from((largest, Timestamp::from(zdt)))
3267
0
    }
3268
}
3269
3270
/// Options for [`Timestamp::round`].
3271
///
3272
/// This type provides a way to configure the rounding of a timestamp. In
3273
/// particular, `Timestamp::round` accepts anything that implements the
3274
/// `Into<TimestampRound>` trait. There are some trait implementations that
3275
/// therefore make calling `Timestamp::round` in some common cases more
3276
/// ergonomic:
3277
///
3278
/// * `From<Unit> for TimestampRound` will construct a rounding
3279
/// configuration that rounds to the unit given. Specifically,
3280
/// `TimestampRound::new().smallest(unit)`.
3281
/// * `From<(Unit, i64)> for TimestampRound` is like the one above, but also
3282
/// specifies the rounding increment for [`TimestampRound::increment`].
3283
///
3284
/// Note that in the default configuration, no rounding occurs.
3285
///
3286
/// # Example
3287
///
3288
/// This example shows how to round a timestamp to the nearest second:
3289
///
3290
/// ```
3291
/// use jiff::{Timestamp, Unit};
3292
///
3293
/// let ts: Timestamp = "2024-06-20 16:24:59.5Z".parse()?;
3294
/// assert_eq!(
3295
///     ts.round(Unit::Second)?.to_string(),
3296
///     // The second rounds up and causes minutes to increase.
3297
///     "2024-06-20T16:25:00Z",
3298
/// );
3299
///
3300
/// # Ok::<(), Box<dyn std::error::Error>>(())
3301
/// ```
3302
///
3303
/// The above makes use of the fact that `Unit` implements
3304
/// `Into<TimestampRound>`. If you want to change the rounding mode to, say,
3305
/// truncation, then you'll need to construct a `TimestampRound` explicitly
3306
/// since there are no convenience `Into` trait implementations for
3307
/// [`RoundMode`].
3308
///
3309
/// ```
3310
/// use jiff::{RoundMode, Timestamp, TimestampRound, Unit};
3311
///
3312
/// let ts: Timestamp = "2024-06-20 16:24:59.5Z".parse()?;
3313
/// assert_eq!(
3314
///     ts.round(
3315
///         TimestampRound::new().smallest(Unit::Second).mode(RoundMode::Trunc),
3316
///     )?.to_string(),
3317
///     // The second just gets truncated as if it wasn't there.
3318
///     "2024-06-20T16:24:59Z",
3319
/// );
3320
///
3321
/// # Ok::<(), Box<dyn std::error::Error>>(())
3322
/// ```
3323
#[derive(Clone, Copy, Debug)]
3324
pub struct TimestampRound {
3325
    smallest: Unit,
3326
    mode: RoundMode,
3327
    increment: i64,
3328
}
3329
3330
impl TimestampRound {
3331
    /// Create a new default configuration for rounding a [`Timestamp`].
3332
    #[inline]
3333
0
    pub fn new() -> TimestampRound {
3334
0
        TimestampRound {
3335
0
            smallest: Unit::Nanosecond,
3336
0
            mode: RoundMode::HalfExpand,
3337
0
            increment: 1,
3338
0
        }
3339
0
    }
3340
3341
    /// Set the smallest units allowed in the timestamp returned after
3342
    /// rounding.
3343
    ///
3344
    /// Any units below the smallest configured unit will be used, along with
3345
    /// the rounding increment and rounding mode, to determine the value of the
3346
    /// smallest unit. For example, when rounding `2024-06-20T03:25:30Z` to the
3347
    /// nearest minute, the `30` second unit will result in rounding the minute
3348
    /// unit of `25` up to `26` and zeroing out everything below minutes.
3349
    ///
3350
    /// This defaults to [`Unit::Nanosecond`].
3351
    ///
3352
    /// # Errors
3353
    ///
3354
    /// The smallest units must be no greater than [`Unit::Hour`].
3355
    ///
3356
    /// # Example
3357
    ///
3358
    /// ```
3359
    /// use jiff::{Timestamp, TimestampRound, Unit};
3360
    ///
3361
    /// let ts: Timestamp = "2024-06-20T03:25:30Z".parse()?;
3362
    /// assert_eq!(
3363
    ///     ts.round(TimestampRound::new().smallest(Unit::Minute))?.to_string(),
3364
    ///     "2024-06-20T03:26:00Z",
3365
    /// );
3366
    /// // Or, utilize the `From<Unit> for TimestampRound` impl:
3367
    /// assert_eq!(
3368
    ///     ts.round(Unit::Minute)?.to_string(),
3369
    ///     "2024-06-20T03:26:00Z",
3370
    /// );
3371
    ///
3372
    /// # Ok::<(), Box<dyn std::error::Error>>(())
3373
    /// ```
3374
    #[inline]
3375
0
    pub fn smallest(self, unit: Unit) -> TimestampRound {
3376
0
        TimestampRound { smallest: unit, ..self }
3377
0
    }
3378
3379
    /// Set the rounding mode.
3380
    ///
3381
    /// This defaults to [`RoundMode::HalfExpand`], which rounds away from
3382
    /// zero. It matches the kind of rounding you might have been taught in
3383
    /// school.
3384
    ///
3385
    /// # Example
3386
    ///
3387
    /// This shows how to always round timestamps up towards positive infinity.
3388
    ///
3389
    /// ```
3390
    /// use jiff::{RoundMode, Timestamp, TimestampRound, Unit};
3391
    ///
3392
    /// let ts: Timestamp = "2024-06-20 03:25:01Z".parse()?;
3393
    /// assert_eq!(
3394
    ///     ts.round(
3395
    ///         TimestampRound::new()
3396
    ///             .smallest(Unit::Minute)
3397
    ///             .mode(RoundMode::Ceil),
3398
    ///     )?.to_string(),
3399
    ///     "2024-06-20T03:26:00Z",
3400
    /// );
3401
    ///
3402
    /// # Ok::<(), Box<dyn std::error::Error>>(())
3403
    /// ```
3404
    #[inline]
3405
0
    pub fn mode(self, mode: RoundMode) -> TimestampRound {
3406
0
        TimestampRound { mode, ..self }
3407
0
    }
3408
3409
    /// Set the rounding increment for the smallest unit.
3410
    ///
3411
    /// The default value is `1`. Other values permit rounding the smallest
3412
    /// unit to the nearest integer increment specified. For example, if the
3413
    /// smallest unit is set to [`Unit::Minute`], then a rounding increment of
3414
    /// `30` would result in rounding in increments of a half hour. That is,
3415
    /// the only minute value that could result would be `0` or `30`.
3416
    ///
3417
    /// # Errors
3418
    ///
3419
    /// The rounding increment, when combined with the smallest unit (which
3420
    /// defaults to [`Unit::Nanosecond`]), must divide evenly into `86,400`
3421
    /// seconds (one 24-hour civil day). For example, increments of both
3422
    /// 45 seconds and 15 minutes are allowed, but 7 seconds and 25 minutes are
3423
    /// both not allowed.
3424
    ///
3425
    /// In all cases, the increment must be greater than zero and less than or
3426
    /// equal to `1_000_000_000`. Note that this means, for example, one
3427
    /// cannot round to the nearest `43_200_000_000_000` nanosecond, despite
3428
    /// the fact that it divides evenly into `86_400_000_000_000` seconds.
3429
    ///
3430
    /// # Example
3431
    ///
3432
    /// This example shows how to round a timestamp to the nearest 10 minute
3433
    /// increment.
3434
    ///
3435
    /// ```
3436
    /// use jiff::{RoundMode, Timestamp, TimestampRound, Unit};
3437
    ///
3438
    /// let ts: Timestamp = "2024-06-20 03:24:59Z".parse()?;
3439
    /// assert_eq!(
3440
    ///     ts.round((Unit::Minute, 10))?.to_string(),
3441
    ///     "2024-06-20T03:20:00Z",
3442
    /// );
3443
    ///
3444
    /// # Ok::<(), Box<dyn std::error::Error>>(())
3445
    /// ```
3446
    #[inline]
3447
0
    pub fn increment(self, increment: i64) -> TimestampRound {
3448
0
        TimestampRound { increment, ..self }
3449
0
    }
3450
3451
    /// Does the actual rounding.
3452
0
    pub(crate) fn round(
3453
0
        &self,
3454
0
        timestamp: Timestamp,
3455
0
    ) -> Result<Timestamp, Error> {
3456
0
        let increment =
3457
0
            Increment::for_timestamp(self.smallest, self.increment)?;
3458
0
        Timestamp::from_duration(
3459
0
            increment.round(self.mode, timestamp.as_duration())?,
3460
        )
3461
0
    }
3462
}
3463
3464
impl Default for TimestampRound {
3465
    #[inline]
3466
0
    fn default() -> TimestampRound {
3467
0
        TimestampRound::new()
3468
0
    }
3469
}
3470
3471
impl From<Unit> for TimestampRound {
3472
    #[inline]
3473
0
    fn from(unit: Unit) -> TimestampRound {
3474
0
        TimestampRound::default().smallest(unit)
3475
0
    }
3476
}
3477
3478
impl From<(Unit, i64)> for TimestampRound {
3479
    #[inline]
3480
0
    fn from((unit, increment): (Unit, i64)) -> TimestampRound {
3481
0
        TimestampRound::from(unit).increment(increment)
3482
0
    }
3483
}
3484
3485
#[cfg(test)]
3486
mod tests {
3487
    use alloc::string::ToString;
3488
3489
    use std::io::Cursor;
3490
3491
    use crate::{
3492
        civil::{self, datetime},
3493
        tz::Offset,
3494
        util::b,
3495
        ToSpan,
3496
    };
3497
3498
    use super::*;
3499
3500
    fn mktime(seconds: i64, nanos: i32) -> Timestamp {
3501
        Timestamp::new(seconds, nanos).unwrap()
3502
    }
3503
3504
    fn mkdt(
3505
        year: i16,
3506
        month: i8,
3507
        day: i8,
3508
        hour: i8,
3509
        minute: i8,
3510
        second: i8,
3511
        nano: i32,
3512
    ) -> civil::DateTime {
3513
        let date = civil::Date::new(year, month, day).unwrap();
3514
        let time = civil::Time::new(hour, minute, second, nano).unwrap();
3515
        civil::DateTime::from_parts(date, time)
3516
    }
3517
3518
    #[test]
3519
    fn to_datetime_specific_examples() {
3520
        let tests = [
3521
            ((b::UnixEpochSeconds::MIN, 0), (-9999, 1, 2, 1, 59, 59, 0)),
3522
            (
3523
                (b::UnixEpochSeconds::MIN + 1, -999_999_999),
3524
                (-9999, 1, 2, 1, 59, 59, 1),
3525
            ),
3526
            ((-1, 1), (1969, 12, 31, 23, 59, 59, 1)),
3527
            ((b::UnixEpochSeconds::MAX, 0), (9999, 12, 30, 22, 0, 0, 0)),
3528
            ((b::UnixEpochSeconds::MAX - 1, 0), (9999, 12, 30, 21, 59, 59, 0)),
3529
            (
3530
                (b::UnixEpochSeconds::MAX - 1, 999_999_999),
3531
                (9999, 12, 30, 21, 59, 59, 999_999_999),
3532
            ),
3533
            (
3534
                (b::UnixEpochSeconds::MAX, 999_999_999),
3535
                (9999, 12, 30, 22, 0, 0, 999_999_999),
3536
            ),
3537
            ((-2, -1), (1969, 12, 31, 23, 59, 57, 999_999_999)),
3538
            ((-86398, -1), (1969, 12, 31, 0, 0, 1, 999_999_999)),
3539
            ((-86399, -1), (1969, 12, 31, 0, 0, 0, 999_999_999)),
3540
            ((-86400, -1), (1969, 12, 30, 23, 59, 59, 999_999_999)),
3541
        ];
3542
        for (t, dt) in tests {
3543
            let timestamp = mktime(t.0, t.1);
3544
            let datetime = mkdt(dt.0, dt.1, dt.2, dt.3, dt.4, dt.5, dt.6);
3545
            assert_eq!(
3546
                Offset::UTC.to_datetime(timestamp),
3547
                datetime,
3548
                "timestamp: {t:?}"
3549
            );
3550
            assert_eq!(
3551
                timestamp,
3552
                datetime.to_zoned(TimeZone::UTC).unwrap().timestamp(),
3553
                "datetime: {datetime:?}"
3554
            );
3555
        }
3556
    }
3557
3558
    #[test]
3559
    fn to_datetime_many_seconds_in_some_days() {
3560
        let days = [
3561
            i64::from(b::UnixEpochDays::MIN),
3562
            -1000,
3563
            -5,
3564
            23,
3565
            2000,
3566
            i64::from(b::UnixEpochDays::MAX),
3567
        ];
3568
        let seconds = [
3569
            -86_400, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4,
3570
            5, 6, 7, 8, 9, 10, 86_400,
3571
        ];
3572
        let nanos = [0, 1, 5, 999_999_999];
3573
        for day in days {
3574
            let midpoint = day * 86_400;
3575
            for second in seconds {
3576
                let second = midpoint + second;
3577
                if b::UnixEpochSeconds::check(second).is_err() {
3578
                    continue;
3579
                }
3580
                for nano in nanos {
3581
                    if second == b::UnixEpochSeconds::MIN && nano != 0 {
3582
                        continue;
3583
                    }
3584
                    let t = Timestamp::new(second, nano).unwrap();
3585
                    let Ok(got) =
3586
                        Offset::UTC.to_datetime(t).to_zoned(TimeZone::UTC)
3587
                    else {
3588
                        continue;
3589
                    };
3590
                    assert_eq!(t, got.timestamp());
3591
                }
3592
            }
3593
        }
3594
    }
3595
3596
    #[test]
3597
    fn invalid_time() {
3598
        assert!(Timestamp::new(b::UnixEpochSeconds::MIN, -1).is_err());
3599
        assert!(
3600
            Timestamp::new(b::UnixEpochSeconds::MIN, -999_999_999).is_err()
3601
        );
3602
        // These are greater than the minimum and thus okay!
3603
        assert!(Timestamp::new(b::UnixEpochSeconds::MIN, 1).is_ok());
3604
        assert!(Timestamp::new(b::UnixEpochSeconds::MIN, 999_999_999).is_ok());
3605
    }
3606
3607
    #[cfg(target_pointer_width = "64")]
3608
    #[test]
3609
    fn timestamp_size() {
3610
        #[cfg(debug_assertions)]
3611
        {
3612
            assert_eq!(16, core::mem::size_of::<Timestamp>());
3613
        }
3614
        #[cfg(not(debug_assertions))]
3615
        {
3616
            assert_eq!(16, core::mem::size_of::<Timestamp>());
3617
        }
3618
    }
3619
3620
    #[test]
3621
    fn nanosecond_roundtrip_boundaries() {
3622
        let inst = Timestamp::MIN;
3623
        let nanos = inst.as_nanosecond();
3624
        assert_eq!(0, nanos % (jcore::constants::NANOS_PER_SEC as i128));
3625
        let got = Timestamp::from_nanosecond(nanos).unwrap();
3626
        assert_eq!(inst, got);
3627
3628
        let inst = Timestamp::MAX;
3629
        let nanos = inst.as_nanosecond();
3630
        assert_eq!(
3631
            b::SignedSubsecNanosecond::MAX as i128,
3632
            nanos % (jcore::constants::NANOS_PER_SEC as i128)
3633
        );
3634
        let got = Timestamp::from_nanosecond(nanos).unwrap();
3635
        assert_eq!(inst, got);
3636
    }
3637
3638
    #[test]
3639
    fn timestamp_saturating_add() {
3640
        insta::assert_snapshot!(
3641
            Timestamp::MIN.saturating_add(Span::new().days(1)).unwrap_err(),
3642
            @"operation can only be performed with units of hours or smaller, but found non-zero 'day' units (operations on `jiff::Timestamp`, `jiff::tz::Offset` and `jiff::civil::Time` don't support calendar units in a `jiff::Span`)",
3643
        )
3644
    }
3645
3646
    #[test]
3647
    fn timestamp_saturating_sub() {
3648
        insta::assert_snapshot!(
3649
            Timestamp::MAX.saturating_sub(Span::new().days(1)).unwrap_err(),
3650
            @"operation can only be performed with units of hours or smaller, but found non-zero 'day' units (operations on `jiff::Timestamp`, `jiff::tz::Offset` and `jiff::civil::Time` don't support calendar units in a `jiff::Span`)",
3651
        )
3652
    }
3653
3654
    quickcheck::quickcheck! {
3655
        fn prop_unix_seconds_roundtrip(t: Timestamp) -> quickcheck::TestResult {
3656
            let dt = t.to_zoned(TimeZone::UTC).datetime();
3657
            let Ok(got) = dt.to_zoned(TimeZone::UTC) else {
3658
                return quickcheck::TestResult::discard();
3659
            };
3660
            quickcheck::TestResult::from_bool(t == got.timestamp())
3661
        }
3662
3663
        fn prop_nanos_roundtrip_unix(t: Timestamp) -> bool {
3664
            let nanos = t.as_nanosecond();
3665
            let got = Timestamp::from_nanosecond(nanos).unwrap();
3666
            t == got
3667
        }
3668
3669
        fn timestamp_constant_and_new_are_same1(t: Timestamp) -> bool {
3670
            let got = Timestamp::constant(t.as_second(), t.subsec_nanosecond());
3671
            t == got
3672
        }
3673
3674
        fn timestamp_constant_and_new_are_same2(
3675
            secs: i64,
3676
            nanos: i32
3677
        ) -> quickcheck::TestResult {
3678
            let Ok(ts) = Timestamp::new(secs, nanos) else {
3679
                return quickcheck::TestResult::discard();
3680
            };
3681
            let got = Timestamp::constant(secs, nanos);
3682
            quickcheck::TestResult::from_bool(ts == got)
3683
        }
3684
    }
3685
3686
    /// A `serde` deserializer compatibility test.
3687
    ///
3688
    /// Serde YAML used to be unable to deserialize `jiff` types,
3689
    /// as deserializing from bytes is not supported by the deserializer.
3690
    ///
3691
    /// - <https://github.com/BurntSushi/jiff/issues/138>
3692
    /// - <https://github.com/BurntSushi/jiff/discussions/148>
3693
    #[test]
3694
    fn timestamp_deserialize_yaml() {
3695
        let expected = datetime(2024, 10, 31, 16, 33, 53, 123456789)
3696
            .to_zoned(TimeZone::UTC)
3697
            .unwrap()
3698
            .timestamp();
3699
3700
        let deserialized: Timestamp =
3701
            serde_yaml::from_str("2024-10-31T16:33:53.123456789+00:00")
3702
                .unwrap();
3703
3704
        assert_eq!(deserialized, expected);
3705
3706
        let deserialized: Timestamp = serde_yaml::from_slice(
3707
            "2024-10-31T16:33:53.123456789+00:00".as_bytes(),
3708
        )
3709
        .unwrap();
3710
3711
        assert_eq!(deserialized, expected);
3712
3713
        let cursor = Cursor::new(b"2024-10-31T16:33:53.123456789+00:00");
3714
        let deserialized: Timestamp = serde_yaml::from_reader(cursor).unwrap();
3715
3716
        assert_eq!(deserialized, expected);
3717
    }
3718
3719
    #[test]
3720
    fn timestamp_precision_loss() {
3721
        let ts1: Timestamp =
3722
            "2025-01-25T19:32:21.783444592+01:00".parse().unwrap();
3723
        let span = 1.second();
3724
        let ts2 = ts1 + span;
3725
        assert_eq!(ts2.to_string(), "2025-01-25T18:32:22.783444592Z");
3726
        assert_eq!(ts1, ts2 - span, "should be reversible");
3727
    }
3728
}