Skip to main content

bibeam_core/
time.rs

1#![forbid(unsafe_code)]
2//! UTC timestamp wrapper around [`time::OffsetDateTime`].
3//!
4//! All `BiBeam` core types that need a "when did this happen" field hold a
5//! [`Timestamp`] rather than reaching for [`time::OffsetDateTime`] directly.
6//! That keeps wire/serde encoding uniform (RFC 3339) and gives us a single
7//! choke point if we ever need to swap the underlying representation.
8
9use serde::{Deserialize, Deserializer, Serialize, Serializer};
10use time::OffsetDateTime;
11use time::serde::rfc3339;
12
13/// A UTC timestamp serialised as RFC 3339.
14///
15/// Wraps a [`time::OffsetDateTime`] and forces serde to round-trip through
16/// the RFC 3339 string form, so every encoded `Timestamp` on the wire and on
17/// disk looks the same regardless of which subsystem produced it.
18#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
19pub struct Timestamp(OffsetDateTime);
20
21impl Timestamp {
22    /// Capture the current UTC time.
23    #[must_use]
24    pub fn now() -> Self {
25        Self(OffsetDateTime::now_utc())
26    }
27
28    /// Build a [`Timestamp`] from an existing [`OffsetDateTime`].
29    ///
30    /// The wrapped value is preserved verbatim; no timezone conversion is
31    /// applied. Callers who want UTC normalisation should convert before
32    /// passing the value in.
33    #[must_use]
34    pub const fn from_offset_date_time(value: OffsetDateTime) -> Self {
35        Self(value)
36    }
37
38    /// Consume the wrapper and return the underlying [`OffsetDateTime`].
39    #[must_use]
40    pub const fn into_inner(self) -> OffsetDateTime {
41        self.0
42    }
43
44    /// Borrow the underlying [`OffsetDateTime`].
45    #[must_use]
46    pub const fn as_offset_date_time(&self) -> &OffsetDateTime {
47        &self.0
48    }
49}
50
51impl Serialize for Timestamp {
52    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
53    where
54        S: Serializer,
55    {
56        rfc3339::serialize(&self.0, serializer)
57    }
58}
59
60impl<'de> Deserialize<'de> for Timestamp {
61    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
62    where
63        D: Deserializer<'de>,
64    {
65        rfc3339::deserialize(deserializer).map(Self)
66    }
67}