From 1209850b187e8ede274276c966edbeda35a9c5d6 Mon Sep 17 00:00:00 2001 From: debaditya Date: Sun, 9 Aug 2026 10:51:35 +0530 Subject: [PATCH] fix(sns): preserve millisecond timestamp precision --- lambda-events/src/event/sns/mod.rs | 47 ++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/lambda-events/src/event/sns/mod.rs b/lambda-events/src/event/sns/mod.rs index 5879bc87..04c0416c 100644 --- a/lambda-events/src/event/sns/mod.rs +++ b/lambda-events/src/event/sns/mod.rs @@ -1,13 +1,20 @@ #[cfg(feature = "builders")] use bon::Builder; -use chrono::{DateTime, Utc}; -use serde::{de::DeserializeOwned, Deserialize, Serialize}; +use chrono::{DateTime, SecondsFormat, Utc}; +use serde::{de::DeserializeOwned, Deserialize, Serialize, Serializer}; #[cfg(feature = "catch-all-fields")] use serde_json::Value; use std::collections::HashMap; use crate::custom_serde::deserialize_nullish; +fn serialize_timestamp(timestamp: &DateTime, serializer: S) -> Result +where + S: Serializer, +{ + serializer.serialize_str(×tamp.to_rfc3339_opts(SecondsFormat::Millis, true)) +} + /// The `Event` notification event handled by Lambda /// /// [https://docs.aws.amazon.com/lambda/latest/dg/with-sns.html](https://docs.aws.amazon.com/lambda/latest/dg/with-sns.html) @@ -85,6 +92,7 @@ pub struct SnsMessage { pub subject: Option, /// The time (UTC) when the notification was published. + #[serde(serialize_with = "serialize_timestamp")] pub timestamp: DateTime, /// Version of the Amazon SNS signature used. @@ -166,6 +174,7 @@ pub struct SnsSubscriptionMessage { pub subject: Option, /// The time (UTC) when the message was sent. + #[serde(serialize_with = "serialize_timestamp")] pub timestamp: DateTime, /// Version of the Amazon SNS signature used. @@ -289,6 +298,7 @@ pub struct SnsMessageObj { pub subject: Option, /// The time (UTC) when the notification was published. + #[serde(serialize_with = "serialize_timestamp")] pub timestamp: DateTime, /// Version of the Amazon SNS signature used. @@ -595,4 +605,37 @@ mod test { let reparsed: SnsSubscriptionMessage = serde_json::from_slice(output.as_bytes()).unwrap(); assert_eq!(parsed, reparsed); } + + #[test] + #[cfg(feature = "sns")] + fn sns_timestamps_serialize_with_millisecond_precision() { + let mut data: serde_json::Value = + serde_json::from_slice(include_bytes!("../../fixtures/example-sns-event.json")).unwrap(); + data["Records"][0]["Sns"]["Timestamp"] = serde_json::json!("2019-01-02T12:45:07.000Z"); + let parsed: SnsEvent = serde_json::from_value(data).unwrap(); + let serialized = serde_json::to_value(parsed).unwrap(); + assert_eq!( + serialized["Records"][0]["Sns"]["Timestamp"].as_str(), + Some("2019-01-02T12:45:07.000Z") + ); + + #[derive(Debug, Serialize, Deserialize, Eq, PartialEq)] + struct Message { + foo: String, + bar: i32, + } + + let data = include_bytes!("../../fixtures/example-sns-event-obj.json"); + let parsed: SnsEventObj = serde_json::from_slice(data).unwrap(); + let serialized = serde_json::to_value(parsed).unwrap(); + assert_eq!( + serialized["Records"][0]["Sns"]["Timestamp"].as_str(), + Some("2015-08-18T18:02:32.111Z") + ); + + let data = include_bytes!("../../fixtures/example-sns-subscription-confirmation.json"); + let parsed: SnsSubscriptionMessage = serde_json::from_slice(data).unwrap(); + let serialized = serde_json::to_value(parsed).unwrap(); + assert_eq!(serialized["Timestamp"].as_str(), Some("2012-04-26T20:45:04.751Z")); + } }