From 0f04a6d8246c77379f41372b28a858f188956654 Mon Sep 17 00:00:00 2001 From: bouzuya Date: Fri, 8 Mar 2024 11:56:43 +0900 Subject: [PATCH] Add conversion between chrono::DateTime and Timestamp --- src/typ/timestamp.rs | 37 +++++++++++++++++++++++++++++++++++++ tests/v0_7_0.rs | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) create mode 100644 tests/v0_7_0.rs diff --git a/src/typ/timestamp.rs b/src/typ/timestamp.rs index 1093d83..8338b24 100644 --- a/src/typ/timestamp.rs +++ b/src/typ/timestamp.rs @@ -52,3 +52,40 @@ impl From for Timestamp { Self { seconds, nanos } } } + +#[cfg(feature = "chrono")] +impl std::convert::TryFrom for chrono::DateTime { + type Error = crate::Error; + + fn try_from(Timestamp { seconds, nanos }: Timestamp) -> Result { + let nanos = u32::try_from(nanos).map_err(|_| { + crate::Error::from(crate::error::ErrorCode::Custom(format!( + "chrono::DateTime::::try_from(Timestamp) / u32::try_from({})", + nanos + ))) + })?; + Self::from_timestamp(seconds, nanos).ok_or_else(|| { + crate::Error::from(crate::error::ErrorCode::Custom(format!( + "chrono::DateTime::::try_from(Timestamp) / chrono::DateTime::::from_timestamp({}, {})", + seconds, nanos + ))) + }) + } +} + +#[cfg(feature = "chrono")] +impl std::convert::TryFrom> for Timestamp { + type Error = crate::Error; + + fn try_from(date_time: chrono::DateTime) -> Result { + let seconds = date_time.timestamp(); + let nanos = date_time.timestamp_subsec_nanos(); + let nanos = i32::try_from(nanos).map_err(|_| { + crate::Error::from(crate::error::ErrorCode::Custom(format!( + "Timestamp::try_from(chrono::DateTime::) / i32::try_from({})", + nanos + ))) + })?; + Ok(Self { seconds, nanos }) + } +} diff --git a/tests/v0_7_0.rs b/tests/v0_7_0.rs new file mode 100644 index 0000000..05609e0 --- /dev/null +++ b/tests/v0_7_0.rs @@ -0,0 +1,35 @@ +#[cfg(feature = "chrono")] +#[test] +fn test_try_from_timestamp_for_chrono_date_time() -> serde_firestore_value::Result<()> { + use serde_firestore_value::Timestamp; + let timestamp = Timestamp { + seconds: 1_i64, + nanos: 2_i32, + }; + let date_time = chrono::DateTime::::try_from(timestamp)?; + assert_eq!( + date_time.to_rfc3339(), + "1970-01-01T00:00:01.000000002+00:00" + ); + Ok(()) +} + +#[cfg(feature = "chrono")] +#[test] +fn test_try_from_chrono_date_time_for_timestamp() -> anyhow::Result<()> { + use serde_firestore_value::Timestamp; + let date_time = chrono::DateTime::::parse_from_rfc3339( + "1970-01-01T00:00:01.000000002+00:00", + )? + .naive_utc() + .and_utc(); + let timestamp = Timestamp::try_from(date_time)?; + assert_eq!( + timestamp, + Timestamp { + seconds: 1_i64, + nanos: 2_i32, + } + ); + Ok(()) +}