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}