Skip to main content

wavs_types/
time.rs

1use std::{num::ParseIntError, str::FromStr};
2
3use anyhow::Result;
4
5cfg_if::cfg_if! {
6    if #[cfg(feature = "clock")] {
7        use chrono::{DateTime, TimeZone, Utc};
8        use anyhow::anyhow;
9    }
10}
11use serde::{Deserialize, Serialize};
12#[cfg(feature = "ts-bindings")]
13use ts_rs::TS;
14use utoipa::ToSchema;
15
16#[derive(
17    Serialize,
18    Deserialize,
19    Clone,
20    Copy,
21    Debug,
22    PartialEq,
23    Eq,
24    Hash,
25    bincode::Encode,
26    bincode::Decode,
27    ToSchema,
28)]
29pub struct Duration {
30    pub secs: u64,
31}
32
33impl From<Duration> for std::time::Duration {
34    fn from(d: Duration) -> Self {
35        std::time::Duration::from_secs(d.secs)
36    }
37}
38
39#[repr(transparent)]
40#[cfg_attr(feature = "ts-bindings", derive(TS))]
41#[derive(
42    Debug, Hash, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, ToSchema,
43)]
44pub struct Timestamp(u64);
45
46impl Timestamp {
47    // Create a new Timestamp directly from nanoseconds
48    pub fn from_nanos(nanos: u64) -> Self {
49        Timestamp(nanos)
50    }
51
52    // Create a new Timestamp from DateTime<Utc>
53    #[cfg(feature = "clock")]
54    pub fn from_datetime(dt: DateTime<Utc>) -> Result<Self> {
55        let nanos = dt
56            .timestamp_nanos_opt()
57            .ok_or_else(|| anyhow!("Invalid timestamp"))?;
58
59        if nanos < 0 {
60            return Err(anyhow!("Timestamp cannot represent dates before 1970"));
61        }
62
63        Ok(Timestamp(nanos as u64))
64    }
65
66    #[cfg(feature = "clock")]
67    pub fn into_datetime(self) -> DateTime<Utc> {
68        Utc.timestamp_nanos(self.0 as i64)
69    }
70
71    // Get the nanosecond value
72    pub fn as_nanos(&self) -> u64 {
73        self.0
74    }
75
76    // Create from current time
77    #[cfg(feature = "clock")]
78    pub fn now() -> Self {
79        // Current time is always after 1970, so this unwrap is safe
80        Self::from_datetime(Utc::now()).expect("Current time should always be valid")
81    }
82}
83
84// Define FromStr for to enable parsing from command line strings
85impl FromStr for Timestamp {
86    type Err = ParseIntError;
87
88    fn from_str(s: &str) -> Result<Self, Self::Err> {
89        let nanos: u64 = s.parse()?;
90        Ok(Timestamp::from_nanos(nanos))
91    }
92}