Skip to content

Commit f8ecd81

Browse files
JohnDowsonjhpratt
authored andcommitted
feat: timestamp::milliseconds_i64 serializer
1 parent ce03bca commit f8ecd81

File tree

2 files changed

+67
-0
lines changed

2 files changed

+67
-0
lines changed
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
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+
}

time/src/serde/timestamp/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
1010
pub mod microseconds;
1111
pub mod milliseconds;
12+
pub mod milliseconds_i64;
1213
pub mod nanoseconds;
1314

1415
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};

0 commit comments

Comments
 (0)