Skip to main content

time/serde/timestamp/
milliseconds.rs

1//! Treat an [`OffsetDateTime`] as a [Unix timestamp] with milliseconds for
2//! the purposes of serde.
3//!
4//! Use this module in combination with serde's [`#[with]`][with] attribute.
5//!
6//! When deserializing, the offset is assumed to be UTC.
7//!
8//! [Unix timestamp]: https://en.wikipedia.org/wiki/Unix_time
9//! [with]: https://serde.rs/field-attrs.html#with
10
11use serde_core::{Deserialize, Deserializer, Serialize, Serializer};
12
13use crate::OffsetDateTime;
14use crate::error::ComponentRange;
15
16/// Serialize an `OffsetDateTime` as its Unix timestamp with milliseconds
17#[inline]
18pub fn serialize<S>(datetime: &OffsetDateTime, serializer: S) -> Result<S::Ok, S::Error>
19where
20    S: Serializer,
21{
22    let timestamp = datetime.unix_timestamp_nanos() / 1_000_000;
23    timestamp.serialize(serializer)
24}
25
26/// Deserialize an `OffsetDateTime` from its Unix timestamp with milliseconds
27#[inline]
28pub fn deserialize<'a, D>(deserializer: D) -> Result<OffsetDateTime, D::Error>
29where
30    D: Deserializer<'a>,
31{
32    let value: i128 = <_>::deserialize(deserializer)?;
33    value
34        .checked_mul(1_000_000)
35        .map(OffsetDateTime::from_unix_timestamp_nanos)
36        .unwrap_or_else(|| Err(ComponentRange::unconditional("timestamp")))
37        .map_err(ComponentRange::into_de_error)
38}
39
40/// Treat an `Option<OffsetDateTime>` as a [Unix timestamp] with milliseconds
41/// for the purposes of serde.
42///
43/// Use this module in combination with serde's [`#[with]`][with] attribute.
44///
45/// Note: Due to [serde-rs/serde#2878], you will need to apply `#[serde(default)]` if you want a
46/// missing field to deserialize as `None`.
47///
48/// When deserializing, the offset is assumed to be UTC.
49///
50/// [Unix timestamp]: https://en.wikipedia.org/wiki/Unix_time
51/// [with]: https://serde.rs/field-attrs.html#with
52/// [serde-rs/serde#2878]: https://github.com/serde-rs/serde/issues/2878
53pub mod option {
54    use super::*;
55
56    /// Serialize an `Option<OffsetDateTime>` as its Unix timestamp with milliseconds
57    #[inline]
58    pub fn serialize<S>(option: &Option<OffsetDateTime>, serializer: S) -> Result<S::Ok, S::Error>
59    where
60        S: Serializer,
61    {
62        option
63            .map(|timestamp| timestamp.unix_timestamp_nanos() / 1_000_000)
64            .serialize(serializer)
65    }
66
67    /// Deserialize an `Option<OffsetDateTime>` from its Unix timestamp with milliseconds
68    #[inline]
69    pub fn deserialize<'a, D>(deserializer: D) -> Result<Option<OffsetDateTime>, D::Error>
70    where
71        D: Deserializer<'a>,
72    {
73        Option::deserialize(deserializer)?
74            .map(|value: i128| {
75                value
76                    .checked_mul(1_000_000)
77                    .map(OffsetDateTime::from_unix_timestamp_nanos)
78                    .unwrap_or_else(|| Err(ComponentRange::unconditional("timestamp")))
79            })
80            .transpose()
81            .map_err(ComponentRange::into_de_error)
82    }
83}