t: abi::timestamp,
}
-pub fn dur2intervals(dur: &Duration) -> abi::timestamp {
+fn checked_dur2intervals(dur: &Duration) -> Option<abi::timestamp> {
dur.as_secs()
.checked_mul(NSEC_PER_SEC)
.and_then(|nanos| nanos.checked_add(dur.subsec_nanos() as abi::timestamp))
+}
+
+pub fn dur2intervals(dur: &Duration) -> abi::timestamp {
+ checked_dur2intervals(dur)
.expect("overflow converting duration to nanoseconds")
}
}
pub fn add_duration(&self, other: &Duration) -> SystemTime {
- SystemTime {
- t: self.t
- .checked_add(dur2intervals(other))
- .expect("overflow when adding duration to instant"),
- }
+ self.checked_add_duration(other)
+ .expect("overflow when adding duration to instant")
+ }
+
+ pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
+ checked_dur2intervals(other)
+ .and_then(|d| self.t.checked_add(d))
+ .map(|t| SystemTime {t})
}
pub fn sub_duration(&self, other: &Duration) -> SystemTime {
}
fn add_duration(&self, other: &Duration) -> Timespec {
- let mut secs = other
+ self.checked_add_duration(other).expect("overflow when adding duration to time")
+ }
+
+ fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
+ let mut secs = match other
.as_secs()
.try_into() // <- target type would be `i64`
.ok()
.and_then(|secs| self.t.tv_sec.checked_add(secs))
- .expect("overflow when adding duration to time");
+ {
+ Some(ts) => ts,
+ None => return None,
+ };
// Nano calculations can't overflow because nanos are <1B which fit
// in a u32.
let mut nsec = other.subsec_nanos() + self.t.tv_nsec as u32;
if nsec >= NSEC_PER_SEC as u32 {
nsec -= NSEC_PER_SEC as u32;
- secs = secs.checked_add(1).expect("overflow when adding \
- duration to time");
+ secs = match secs.checked_add(1) {
+ Some(ts) => ts,
+ None => return None,
+ }
}
- Timespec {
+ Some(Timespec {
t: syscall::TimeSpec {
tv_sec: secs,
tv_nsec: nsec as i32,
},
- }
+ })
}
fn sub_duration(&self, other: &Duration) -> Timespec {
SystemTime { t: self.t.add_duration(other) }
}
+ pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
+ self.t.checked_add_duration(other).map(|t| SystemTime { t })
+ }
+
pub fn sub_duration(&self, other: &Duration) -> SystemTime {
SystemTime { t: self.t.sub_duration(other) }
}
}
fn add_duration(&self, other: &Duration) -> Timespec {
- let mut secs = other
+ self.checked_add_duration(other).expect("overflow when adding duration to time")
+ }
+
+ fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
+ let mut secs = match other
.as_secs()
.try_into() // <- target type would be `libc::time_t`
.ok()
.and_then(|secs| self.t.tv_sec.checked_add(secs))
- .expect("overflow when adding duration to time");
+ {
+ Some(ts) => ts,
+ None => return None,
+ };
// Nano calculations can't overflow because nanos are <1B which fit
// in a u32.
let mut nsec = other.subsec_nanos() + self.t.tv_nsec as u32;
if nsec >= NSEC_PER_SEC as u32 {
nsec -= NSEC_PER_SEC as u32;
- secs = secs.checked_add(1).expect("overflow when adding \
- duration to time");
+ secs = match secs.checked_add(1) {
+ Some(ts) => ts,
+ None => return None,
+ }
}
- Timespec {
+ Some(Timespec {
t: libc::timespec {
tv_sec: secs,
tv_nsec: nsec as _,
},
- }
+ })
}
fn sub_duration(&self, other: &Duration) -> Timespec {
SystemTime { t: self.t.add_duration(other) }
}
+ pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
+ self.t.checked_add_duration(other).map(|t| SystemTime { t })
+ }
+
pub fn sub_duration(&self, other: &Duration) -> SystemTime {
SystemTime { t: self.t.sub_duration(other) }
}
SystemTime { t: self.t.add_duration(other) }
}
+ pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
+ self.t.checked_add_duration(other).map(|t| SystemTime { t })
+ }
+
pub fn sub_duration(&self, other: &Duration) -> SystemTime {
SystemTime { t: self.t.sub_duration(other) }
}
SystemTime(self.0 + *other)
}
+ pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
+ self.0.checked_add(*other).map(|d| SystemTime(d))
+ }
+
pub fn sub_duration(&self, other: &Duration) -> SystemTime {
SystemTime(self.0 - *other)
}
}
pub fn add_duration(&self, other: &Duration) -> SystemTime {
- let intervals = self.intervals().checked_add(dur2intervals(other))
- .expect("overflow when adding duration to time");
- SystemTime::from_intervals(intervals)
+ self.checked_add_duration(other).expect("overflow when adding duration to time")
+ }
+
+ pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
+ checked_dur2intervals(other)
+ .and_then(|d| self.intervals().checked_add(d))
+ .map(|i| SystemTime::from_intervals(i))
}
pub fn sub_duration(&self, other: &Duration) -> SystemTime {
}
}
-fn dur2intervals(d: &Duration) -> i64 {
+fn checked_dur2intervals(d: &Duration) -> Option<i64> {
d.as_secs()
.checked_mul(INTERVALS_PER_SEC)
.and_then(|i| i.checked_add(d.subsec_nanos() as u64 / 100))
.and_then(|i| i.try_into().ok())
+}
+
+fn dur2intervals(d: &Duration) -> i64 {
+ checked_dur2intervals(d)
.expect("overflow when converting duration to intervals")
}
pub fn elapsed(&self) -> Result<Duration, SystemTimeError> {
SystemTime::now().duration_since(*self)
}
+
+ /// Returns `Some(t)` where `t` is the time `self + duration` if `t` can be represented as
+ /// `SystemTime` (which means it's inside the bounds of the underlying data structure), `None`
+ /// otherwise.
+ #[stable(feature = "time_checked_add", since = "1.32.0")]
+ pub fn checked_add_duration(&self, duration: &Duration) -> Option<SystemTime> {
+ self.0.checked_add_duration(duration).map(|t| SystemTime(t))
+ }
}
#[stable(feature = "time2", since = "1.8.0")]
let one_second_from_epoch2 = UNIX_EPOCH + Duration::new(0, 500_000_000)
+ Duration::new(0, 500_000_000);
assert_eq!(one_second_from_epoch, one_second_from_epoch2);
+
+ // checked_add_duration will not panic on overflow
+ let mut maybe_t = Some(SystemTime::UNIX_EPOCH);
+ let max_duration = Duration::from_secs(u64::max_value());
+ // in case `SystemTime` can store `>= UNIX_EPOCH + max_duration`.
+ for _ in 0..2 {
+ maybe_t = maybe_t.and_then(|t| t.checked_add_duration(&max_duration));
+ }
+ assert_eq!(maybe_t, None);
+
+ // checked_add_duration calculates the right time and will work for another year
+ let year = Duration::from_secs(60 * 60 * 24 * 365);
+ assert_eq!(a + year, a.checked_add_duration(&year).unwrap());
}
#[test]