|
| 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 | +
|
| 11 | +use num_conv::prelude::*; |
| 12 | +use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; |
| 13 | + |
| 14 | +use crate::OffsetDateTime; |
| 15 | + |
| 16 | +/// Serialize an `OffsetDateTime` as its Unix timestamp with milliseconds |
| 17 | +pub fn serialize<S: Serializer>( |
| 18 | + datetime: &OffsetDateTime, |
| 19 | + serializer: S, |
| 20 | +) -> Result<S::Ok, S::Error> { |
| 21 | + let timestamp = (datetime.unix_timestamp_nanos() / 1_000_000).truncate::<i64>(); |
| 22 | + timestamp.serialize(serializer) |
| 23 | +} |
| 24 | + |
| 25 | +/// Deserialize an `OffsetDateTime` from its Unix timestamp with milliseconds |
| 26 | +pub fn deserialize<'a, D: Deserializer<'a>>(deserializer: D) -> Result<OffsetDateTime, D::Error> { |
| 27 | + let value: i64 = <_>::deserialize(deserializer)?; |
| 28 | + OffsetDateTime::from_unix_timestamp_nanos(value.extend::<i128>() * 1_000_000) |
| 29 | + .map_err(|err| de::Error::invalid_value(de::Unexpected::Signed(err.value), &err)) |
| 30 | +} |
| 31 | + |
| 32 | +/// Treat an `Option<OffsetDateTime>` as a [Unix timestamp] with milliseconds |
| 33 | +/// for the purposes of serde. |
| 34 | +/// |
| 35 | +/// Use this module in combination with serde's [`#[with]`][with] attribute. |
| 36 | +/// |
| 37 | +/// When deserializing, the offset is assumed to be UTC. |
| 38 | +/// |
| 39 | +/// [Unix timestamp]: https://en.wikipedia.org/wiki/Unix_time |
| 40 | +/// [with]: https://serde.rs/field-attrs.html#with |
| 41 | +pub mod option { |
| 42 | + #[allow(clippy::wildcard_imports)] |
| 43 | + use super::*; |
| 44 | + |
| 45 | + /// Serialize an `Option<OffsetDateTime>` as its Unix timestamp with milliseconds |
| 46 | + pub fn serialize<S: Serializer>( |
| 47 | + option: &Option<OffsetDateTime>, |
| 48 | + serializer: S, |
| 49 | + ) -> Result<S::Ok, S::Error> { |
| 50 | + option |
| 51 | + .map(|timestamp| (timestamp.unix_timestamp_nanos() / 1_000_000).truncate::<i64>()) |
| 52 | + .serialize(serializer) |
| 53 | + } |
| 54 | + |
| 55 | + /// Deserialize an `Option<OffsetDateTime>` from its Unix timestamp with milliseconds |
| 56 | + pub fn deserialize<'a, D: Deserializer<'a>>( |
| 57 | + deserializer: D, |
| 58 | + ) -> Result<Option<OffsetDateTime>, D::Error> { |
| 59 | + Option::deserialize(deserializer)? |
| 60 | + .map(|value: i64| { |
| 61 | + OffsetDateTime::from_unix_timestamp_nanos(value.extend::<i128>() * 1_000_000) |
| 62 | + }) |
| 63 | + .transpose() |
| 64 | + .map_err(|err| de::Error::invalid_value(de::Unexpected::Signed(err.value), &err)) |
| 65 | + } |
| 66 | +} |
0 commit comments