diff --git a/firebase_admin/_messaging_encoder.py b/firebase_admin/_messaging_encoder.py index c4da53f0d..48a3dd3cd 100644 --- a/firebase_admin/_messaging_encoder.py +++ b/firebase_admin/_messaging_encoder.py @@ -324,7 +324,11 @@ def encode_android_notification(cls, notification): event_time = result.get('event_time') if event_time: - result['event_time'] = str(event_time.isoformat()) + 'Z' + # if the datetime instance is not naive (tzinfo is present), convert to UTC + # otherwise (tzinfo is None) assume the datetime instance is already in UTC + if event_time.tzinfo is not None: + event_time = event_time.astimezone(datetime.timezone.utc) + result['event_time'] = event_time.strftime('%Y-%m-%dT%H:%M:%S.%fZ') priority = result.get('notification_priority') if priority: diff --git a/firebase_admin/_messaging_utils.py b/firebase_admin/_messaging_utils.py index 3a1943c04..d25ba5520 100644 --- a/firebase_admin/_messaging_utils.py +++ b/firebase_admin/_messaging_utils.py @@ -98,7 +98,8 @@ class AndroidNotification: the user clicks it (optional). event_timestamp: For notifications that inform users about events with an absolute time reference, sets the time that the event in the notification occurred as a - ``datetime.datetime`` instance. Notifications in the panel are sorted by this time + ``datetime.datetime`` instance. If the ``datetime.datetime`` instance is naive, it + defaults to be in the UTC timezone. Notifications in the panel are sorted by this time (optional). local_only: Sets whether or not this notification is relevant only to the current device. Some notifications can be bridged to other devices for remote display, such as a Wear OS diff --git a/tests/test_messaging.py b/tests/test_messaging.py index f8be4cd67..f2ef47cf8 100644 --- a/tests/test_messaging.py +++ b/tests/test_messaging.py @@ -547,7 +547,10 @@ def test_android_notification(self): click_action='ca', title_loc_key='tlk', body_loc_key='blk', title_loc_args=['t1', 't2'], body_loc_args=['b1', 'b2'], channel_id='c', ticker='ticker', sticky=True, - event_timestamp=datetime.datetime(2019, 10, 20, 15, 12, 23, 123), + event_timestamp=datetime.datetime( + 2019, 10, 20, 15, 12, 23, 123, + tzinfo=datetime.timezone(datetime.timedelta(hours=-5)) + ), local_only=False, priority='high', vibrate_timings_millis=[100, 50, 250], default_vibrate_timings=False, default_sound=True, @@ -577,7 +580,7 @@ def test_android_notification(self): 'channel_id': 'c', 'ticker': 'ticker', 'sticky': True, - 'event_time': '2019-10-20T15:12:23.000123Z', + 'event_time': '2019-10-20T20:12:23.000123Z', 'local_only': False, 'notification_priority': 'PRIORITY_HIGH', 'vibrate_timings': ['0.100000000s', '0.050000000s', '0.250000000s'], @@ -601,6 +604,28 @@ def test_android_notification(self): } check_encoding(msg, expected) + def test_android_notification_naive_event_timestamp(self): + event_time = datetime.datetime.now() + msg = messaging.Message( + topic='topic', + android=messaging.AndroidConfig( + notification=messaging.AndroidNotification( + title='t', + event_timestamp=event_time, + ) + ) + ) + expected = { + 'topic': 'topic', + 'android': { + 'notification': { + 'title': 't', + 'event_time': event_time.strftime('%Y-%m-%dT%H:%M:%S.%fZ') + }, + }, + } + check_encoding(msg, expected) + class TestLightSettingsEncoder: