1use jiff::{SignedDuration, Timestamp as JiffTimestamp};
4
5use crate::errors::narrow;
6use crate::{OutOfRangeError, Timedelta, Timestamp};
7
8impl From<Timestamp> for JiffTimestamp {
10 #[inline]
11 fn from(instant: Timestamp) -> Self {
12 let saturated = if instant.0 < 0 { Self::MIN } else { Self::MAX };
15 Self::from_nanosecond(i128::from(instant.0)).unwrap_or(saturated)
16 }
17}
18
19impl TryFrom<JiffTimestamp> for Timestamp {
21 type Error = OutOfRangeError;
22
23 #[inline]
24 fn try_from(instant: JiffTimestamp) -> Result<Self, Self::Error> {
25 narrow(instant.as_nanosecond()).map(Self)
26 }
27}
28
29impl From<Timedelta> for SignedDuration {
31 #[inline]
32 fn from(span: Timedelta) -> Self {
33 Self::from_nanos(span.0)
34 }
35}
36
37impl TryFrom<SignedDuration> for Timedelta {
39 type Error = OutOfRangeError;
40
41 #[inline]
42 fn try_from(duration: SignedDuration) -> Result<Self, Self::Error> {
43 narrow(duration.as_nanos()).map(Self)
44 }
45}
46
47#[cfg(test)]
48mod tests {
49 use jiff::{SignedDuration, Timestamp as JiffTimestamp};
50 use rstest::rstest;
51
52 use crate::{OutOfRangeError, Timedelta, Timestamp};
53
54 #[rstest]
55 #[case::the_earliest(Timestamp::MIN)]
56 #[case::before_the_epoch(Timestamp::from_nanos(-1))]
57 #[case::a_capture(Timestamp::from_nanos(1_789_544_735_123_456_789))]
58 #[case::the_latest(Timestamp::MAX)]
59 fn an_instant_crosses_both_ways(#[case] instant: Timestamp) {
60 let theirs = JiffTimestamp::from(instant);
61 assert_eq!(theirs.as_nanosecond(), i128::from(instant.as_nanos()), "the same instant");
62 assert_eq!(Timestamp::try_from(theirs), Ok(instant), "and back");
63 }
64
65 #[test]
66 fn an_instant_past_the_range_is_refused() {
67 assert_eq!(Timestamp::try_from(JiffTimestamp::MAX), Err(OutOfRangeError), "after 2262");
68 assert_eq!(Timestamp::try_from(JiffTimestamp::MIN), Err(OutOfRangeError), "before 1677");
69 }
70
71 #[rstest]
72 #[case::the_longest_backwards(Timedelta::MIN)]
73 #[case::a_budget(Timedelta::from_millis(-250))]
74 #[case::the_longest(Timedelta::MAX)]
75 fn a_span_crosses_both_ways(#[case] span: Timedelta) {
76 let theirs = SignedDuration::from(span);
77 assert_eq!(theirs.as_nanos(), i128::from(span.as_nanos()), "the same span");
78 assert_eq!(Timedelta::try_from(theirs), Ok(span), "and back");
79 }
80
81 #[test]
82 fn a_span_past_the_range_is_refused() {
83 assert_eq!(Timedelta::try_from(SignedDuration::MAX), Err(OutOfRangeError), "forwards");
84 assert_eq!(Timedelta::try_from(SignedDuration::MIN), Err(OutOfRangeError), "and backwards");
85 }
86}