| use chrono::{DateTime, Local, Utc}; |
| use core::fmt; |
| use serde::{ |
| de::{self, Visitor}, |
| Deserialize, Deserializer, Serialize, Serializer, |
| }; |
| use std::{ |
| ops::Add, |
| time::{Duration, SystemTime, UNIX_EPOCH}, |
| }; |
| |
| /// A struct that represents a timestamp. |
| /// |
| /// This struct uses `SystemTime` from `std::time` crate. |
| /// |
| /// # Example |
| /// |
| /// ``` |
| /// use iggy::utils::timestamp::IggyTimestamp; |
| /// |
| /// let timestamp = IggyTimestamp::from(1694968446131680); |
| /// assert_eq!(timestamp.to_utc_string("%Y-%m-%d %H:%M:%S"), "2023-09-17 16:34:06"); |
| /// assert_eq!(timestamp.to_micros(), 1694968446131680); |
| /// ``` |
| #[derive(Debug, Clone, Copy)] |
| pub struct IggyTimestamp(SystemTime); |
| |
| pub const UTC_TIME_FORMAT: &str = "%Y-%m-%d %H:%M:%S"; |
| |
| impl IggyTimestamp { |
| pub fn now() -> Self { |
| IggyTimestamp::default() |
| } |
| |
| pub fn to_secs(&self) -> u64 { |
| self.0.duration_since(UNIX_EPOCH).unwrap().as_secs() |
| } |
| |
| pub fn to_micros(&self) -> u64 { |
| self.0.duration_since(UNIX_EPOCH).unwrap().as_micros() as u64 |
| } |
| |
| pub fn to_utc_string(&self, format: &str) -> String { |
| DateTime::<Utc>::from(self.0).format(format).to_string() |
| } |
| |
| pub fn to_local_string(&self, format: &str) -> String { |
| DateTime::<Local>::from(self.0).format(format).to_string() |
| } |
| } |
| |
| impl From<u64> for IggyTimestamp { |
| fn from(timestamp: u64) -> Self { |
| IggyTimestamp(UNIX_EPOCH + Duration::from_micros(timestamp)) |
| } |
| } |
| |
| impl From<IggyTimestamp> for u64 { |
| fn from(timestamp: IggyTimestamp) -> u64 { |
| timestamp.to_secs() |
| } |
| } |
| |
| impl Add<SystemTime> for IggyTimestamp { |
| type Output = IggyTimestamp; |
| |
| fn add(self, other: SystemTime) -> IggyTimestamp { |
| IggyTimestamp(self.0 + other.duration_since(UNIX_EPOCH).unwrap()) |
| } |
| } |
| |
| impl Default for IggyTimestamp { |
| fn default() -> Self { |
| Self(SystemTime::now()) |
| } |
| } |
| |
| impl fmt::Display for IggyTimestamp { |
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| write!(f, "{}", self.to_utc_string(UTC_TIME_FORMAT)) |
| } |
| } |
| |
| impl Serialize for IggyTimestamp { |
| fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> |
| where |
| S: Serializer, |
| { |
| let timestamp = self.to_micros(); |
| serializer.serialize_u64(timestamp) |
| } |
| } |
| |
| impl<'de> Deserialize<'de> for IggyTimestamp { |
| fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> |
| where |
| D: Deserializer<'de>, |
| { |
| deserializer.deserialize_u64(IggyTimestampVisitor) |
| } |
| } |
| struct IggyTimestampVisitor; |
| |
| impl<'de> Visitor<'de> for IggyTimestampVisitor { |
| type Value = IggyTimestamp; |
| |
| fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { |
| formatter.write_str("a microsecond timestamp as a u64") |
| } |
| |
| fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E> |
| where |
| E: de::Error, |
| { |
| Ok(IggyTimestamp::from(value)) |
| } |
| } |
| |
| #[cfg(test)] |
| mod tests { |
| use super::*; |
| |
| #[test] |
| fn test_timestamp_get() { |
| let timestamp = IggyTimestamp::now(); |
| assert!(timestamp.to_micros() > 0); |
| } |
| |
| #[test] |
| fn test_timestamp_to_micros() { |
| let timestamp = IggyTimestamp::from(1663472051111); |
| assert_eq!(timestamp.to_micros(), 1663472051111); |
| } |
| |
| #[test] |
| fn test_timestamp_to_string() { |
| let timestamp = IggyTimestamp::from(1694968446131680); |
| assert_eq!( |
| timestamp.to_utc_string("%Y-%m-%d %H:%M:%S"), |
| "2023-09-17 16:34:06" |
| ); |
| } |
| |
| #[test] |
| fn test_timestamp_from_u64() { |
| let timestamp = IggyTimestamp::from(1663472051111); |
| assert_eq!(timestamp.to_micros(), 1663472051111); |
| } |
| } |