Skip to main content

bullet_exchange_interface/
time.rs

1use crate::define_simple_type;
2use crate::error::{ArithmeticError, ArithmeticOperation};
3
4// Stores microseconds since Unix Epoch.
5define_simple_type!(UnixTimestampMicros(i64));
6
7pub const MICROSECONDS_PER_HOUR: i64 = 3_600_000_000;
8pub const ONE_HOUR: UnixTimestampMicros = UnixTimestampMicros(MICROSECONDS_PER_HOUR);
9
10impl UnixTimestampMicros {
11    pub const ZERO: Self = Self(0);
12    pub fn from_secs(secs: i64) -> Result<Self, ArithmeticError> {
13        let micros = secs
14            .checked_mul(1_000_000)
15            .ok_or(ArithmeticError::IntegerFailed {
16                operation: ArithmeticOperation::Multiplication,
17                left: secs as i128,
18                right: 1_000_000,
19            })?;
20        Ok(Self(micros))
21    }
22
23    pub fn from_secs_u32(secs: u32) -> Self {
24        #[allow(clippy::arithmetic_side_effects)]
25        Self((secs as i64) * 1_000_000)
26    }
27
28    pub fn from_micros(micros: i64) -> Self {
29        Self(micros)
30    }
31
32    pub fn from_millis(millis: i64) -> Result<Self, ArithmeticError> {
33        millis
34            .checked_mul(1000)
35            .map(Self)
36            .ok_or(ArithmeticError::IntegerFailed {
37                operation: ArithmeticOperation::Multiplication,
38                left: millis as i128,
39                right: 1000,
40            })
41    }
42    pub fn from_nanos(nanos: u128) -> Result<Self, ArithmeticError> {
43        (nanos / 1000)
44            .try_into()
45            .map(Self)
46            .map_err(|_| ArithmeticError::IntegerFailed {
47                operation: ArithmeticOperation::Division,
48                left: nanos as i128,
49                right: 1000,
50            })
51    }
52
53    pub fn as_secs(&self) -> i64 {
54        self.0 / 1_000_000
55    }
56
57    pub fn as_micros(&self) -> i64 {
58        self.0
59    }
60
61    pub fn as_hour(&self) -> i64 {
62        self.0 / MICROSECONDS_PER_HOUR
63    }
64
65    pub fn checked_add_secs(&self, other: i64) -> Result<Self, ArithmeticError> {
66        self.checked_add(Self::from_secs(other)?)
67    }
68    pub fn checked_add(&self, other: UnixTimestampMicros) -> Result<Self, ArithmeticError> {
69        self.0
70            .checked_add(other.0)
71            .map(Self)
72            .ok_or(ArithmeticError::IntegerFailed {
73                operation: ArithmeticOperation::Addition,
74                left: self.0 as i128,
75                right: other.0 as i128,
76            })
77    }
78
79    /// Returns the microseconds elapsed. Or zero on errors.
80    pub fn elapsed_micros(self, other: UnixTimestampMicros) -> i64 {
81        self.0.checked_sub(other.0).unwrap_or(0).max(0)
82    }
83
84    /// Returns the seconds elapsed. Or zero on errors.
85    pub fn elapsed_secs(self, other: UnixTimestampMicros) -> u64 {
86        let delta = self
87            .as_secs()
88            .checked_sub(other.as_secs())
89            .unwrap_or(0)
90            .max(0);
91        // Safe to cast to u64 as it will be 0 or larger
92        delta as u64
93    }
94}