use std::{
cmp::Ordering,
convert::TryFrom,
fmt,
ops::{Add, Sub},
time::{Duration, Instant},
};
use chrono::{DateTime, Utc};
use crate::ROSTime;
#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug)]
pub struct Time {
instant: Instant,
}
impl Time {
pub fn now() -> Time {
Self {
instant: Instant::now(),
}
}
pub fn now_with_ros_time() -> (Time, ROSTime) {
let (st, ct) = Self::now_with_utc();
let ros_time = ROSTime::try_from(ct)
.unwrap_or(ROSTime::ZERO);
(st, ros_time)
}
#[doc(hidden)]
pub fn now_with_utc() -> (Time, DateTime<Utc>) {
let m0 = Self::now();
let utc = Utc::now();
let m1 = Self::now();
let diff = m1 - m0;
(m0 + TimeDiff::from_nanos(diff.as_nanos() / 2), utc)
}
} impl fmt::Display for Time {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(self, fmt)
}
}
impl Sub for Time {
type Output = TimeDiff;
fn sub(self, other: Time) -> TimeDiff {
self
.instant
.checked_duration_since(other.instant)
.map(|duration| TimeDiff {
duration,
is_negative: false,
})
.unwrap_or_else(|| TimeDiff {
duration: other.instant.saturating_duration_since(self.instant),
is_negative: true,
})
}
}
impl Sub<TimeDiff> for Time {
type Output = Time;
fn sub(self, diff: TimeDiff) -> Time {
if diff.is_negative {
Time {
instant: self.instant - diff.duration,
}
} else {
Time {
instant: self.instant + diff.duration,
}
}
}
}
impl Add<TimeDiff> for Time {
type Output = Time;
fn add(self, diff: TimeDiff) -> Time {
if diff.is_negative {
Time {
instant: self.instant + diff.duration,
}
} else {
Time {
instant: self.instant - diff.duration,
}
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct TimeDiff {
duration: Duration,
is_negative: bool, }
#[derive(Debug, Clone, Copy)]
pub struct NegativetimeDiffError {}
impl TimeDiff {
pub const fn from_nanos(nanos: i64) -> TimeDiff {
if nanos >= 0 {
TimeDiff {
duration: Duration::from_nanos(nanos as u64),
is_negative: false,
}
} else {
TimeDiff {
duration: Duration::from_nanos(-nanos as u64),
is_negative: true,
}
}
}
pub const fn from_millis(millis: i64) -> TimeDiff {
Self::from_nanos(millis * 1_000_000)
}
pub const fn from_secs(secs: i64) -> TimeDiff {
Self::from_nanos(secs * 1_000_000_000)
}
pub const fn as_nanos(self) -> i64 {
let n = self.duration.as_nanos();
let n = if n > (i64::MAX as u128) {
i64::MAX
} else {
n as i64
};
if self.is_negative {
-n
} else {
n
}
}
pub const fn as_millis(self) -> i64 {
self.as_nanos() / 1_000_000
}
#[allow(dead_code)]
pub const fn as_seconds(self) -> i64 {
self.as_nanos() / 1_000_000_000
}
pub fn as_duration(self) -> Result<Duration, NegativetimeDiffError> {
if self.is_negative {
Err(NegativetimeDiffError {})
} else {
Ok(self.duration)
}
}
pub fn as_saturating_duration(self) -> Duration {
if self.is_negative {
Duration::ZERO
} else {
self.duration
}
}
}
impl Ord for TimeDiff {
fn cmp(&self, other: &Self) -> Ordering {
match (self.is_negative, other.is_negative) {
(false, false) => self.duration.cmp(&other.duration),
(true, true) => self.duration.cmp(&other.duration).reverse(),
(false, true) => Ordering::Greater,
(true, false) => Ordering::Less,
}
}
}
impl PartialOrd for TimeDiff {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl fmt::Display for TimeDiff {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(self, fmt)
}
}
impl Add for TimeDiff {
type Output = TimeDiff;
fn add(self, other: TimeDiff) -> TimeDiff {
Self::from_nanos(self.as_nanos() + other.as_nanos())
}
}
impl Sub for TimeDiff {
type Output = TimeDiff;
fn sub(self, other: TimeDiff) -> TimeDiff {
Self::from_nanos(self.as_nanos() - other.as_nanos())
}
}