common: Introduce SecondsSinceUnixEpoch, MilliSecondsSinceUnixEpoch

This commit is contained in:
Jonas Platte 2021-05-13 01:06:04 +02:00
parent 3bdead1cf2
commit c34d570fff
No known key found for this signature in database
GPG Key ID: 7D261D771D915378
2 changed files with 97 additions and 0 deletions

View File

@ -13,3 +13,6 @@ pub mod presence;
pub mod push; pub mod push;
pub mod receipt; pub mod receipt;
pub mod thirdparty; pub mod thirdparty;
mod time;
pub use time::{MilliSecondsSinceUnixEpoch, SecondsSinceUnixEpoch};

View File

@ -0,0 +1,94 @@
use js_int::UInt;
use serde::{Deserialize, Serialize};
use std::{
convert::TryInto,
time::{Duration, SystemTime, UNIX_EPOCH},
};
/// A timestamp represented as the number of milliseconds since the unix epoch.
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize)]
#[serde(transparent)]
pub struct MilliSecondsSinceUnixEpoch(pub UInt);
impl MilliSecondsSinceUnixEpoch {
/// Creates a `MilliSecondsSinceUnixEpoch` from the given `SystemTime`, if it is not before the
/// unix epoch, or too large to be represented.
pub fn from_system_time(time: SystemTime) -> Option<Self> {
let duration = time.duration_since(UNIX_EPOCH).ok()?;
let millis = duration.as_millis().try_into().ok()?;
Some(Self(millis))
}
/// The current milliseconds since the unix epoch.
pub fn now() -> Self {
Self::from_system_time(SystemTime::now()).unwrap()
}
/// Creates a `SystemTime` from `self`, if it can be represented.
pub fn to_system_time(self) -> Option<SystemTime> {
UNIX_EPOCH.checked_add(Duration::from_millis(self.0.into()))
}
}
/// A timestamp represented as the number of seconds since the unix epoch.
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize)]
#[serde(transparent)]
pub struct SecondsSinceUnixEpoch(pub UInt);
impl SecondsSinceUnixEpoch {
/// Creates a `MilliSecondsSinceUnixEpoch` from the given `SystemTime`, if it is not before the
/// unix epoch, or too large to be represented.
pub fn from_system_time(time: SystemTime) -> Option<Self> {
let duration = time.duration_since(UNIX_EPOCH).ok()?;
let millis = duration.as_secs().try_into().ok()?;
Some(Self(millis))
}
/// Creates a `SystemTime` from `self`, if it can be represented.
pub fn to_system_time(self) -> Option<SystemTime> {
UNIX_EPOCH.checked_add(Duration::from_secs(self.0.into()))
}
}
#[cfg(test)]
mod tests {
use std::time::{Duration, UNIX_EPOCH};
use js_int::uint;
use matches::assert_matches;
use serde::{Deserialize, Serialize};
use serde_json::json;
use super::{MilliSecondsSinceUnixEpoch, SecondsSinceUnixEpoch};
#[derive(Clone, Debug, Deserialize, Serialize)]
struct SystemTimeTest {
millis: MilliSecondsSinceUnixEpoch,
secs: SecondsSinceUnixEpoch,
}
#[test]
fn deserialize() {
let json = json!({ "millis": 3000, "secs": 60 });
assert_matches!(
serde_json::from_value::<SystemTimeTest>(json),
Ok(SystemTimeTest { millis, secs })
if millis.to_system_time() == Some(UNIX_EPOCH + Duration::from_millis(3000))
&& secs.to_system_time() == Some(UNIX_EPOCH + Duration::from_secs(60))
);
}
#[test]
fn serialize() {
let request = SystemTimeTest {
millis: MilliSecondsSinceUnixEpoch::from_system_time(UNIX_EPOCH + Duration::new(2, 0))
.unwrap(),
secs: SecondsSinceUnixEpoch(uint!(0)),
};
assert_matches!(
serde_json::to_value(&request),
Ok(value) if value == json!({ "millis": 2000, "secs": 0 })
);
}
}