Skip to content

Commit

Permalink
Add conversion between chrono::DateTime<chrono::Utc> and Timestamp
Browse files Browse the repository at this point in the history
  • Loading branch information
bouzuya committed Mar 8, 2024
1 parent cdd595f commit 0f04a6d
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 0 deletions.
37 changes: 37 additions & 0 deletions src/typ/timestamp.rs
Expand Up @@ -52,3 +52,40 @@ impl From<prost_types::Timestamp> for Timestamp {
Self { seconds, nanos }
}
}

#[cfg(feature = "chrono")]
impl std::convert::TryFrom<Timestamp> for chrono::DateTime<chrono::Utc> {
type Error = crate::Error;

fn try_from(Timestamp { seconds, nanos }: Timestamp) -> Result<Self, Self::Error> {
let nanos = u32::try_from(nanos).map_err(|_| {
crate::Error::from(crate::error::ErrorCode::Custom(format!(
"chrono::DateTime::<chrono::Utc>::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::<chrono::Utc>::try_from(Timestamp) / chrono::DateTime::<chrono::Utc>::from_timestamp({}, {})",
seconds, nanos
)))
})
}
}

#[cfg(feature = "chrono")]
impl std::convert::TryFrom<chrono::DateTime<chrono::Utc>> for Timestamp {
type Error = crate::Error;

fn try_from(date_time: chrono::DateTime<chrono::Utc>) -> Result<Self, Self::Error> {
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::<chrono::Utc>) / i32::try_from({})",
nanos
)))
})?;
Ok(Self { seconds, nanos })
}
}
35 changes: 35 additions & 0 deletions 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::<chrono::Utc>::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::<chrono::FixedOffset>::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(())
}

0 comments on commit 0f04a6d

Please sign in to comment.