Skip to content

Commit f4d25d8

Browse files
authored
Merge pull request #372 from clamsproject/368-tz-in-timestamps
timestamps in view metadata now in UTC instead of local time
2 parents 978e389 + 3ae9eca commit f4d25d8

3 files changed

Lines changed: 25 additions & 3 deletions

File tree

mmif/serialize/mmif.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
import math
1515
import warnings
1616
from collections import defaultdict
17-
from datetime import datetime
17+
from datetime import datetime, timezone
1818
from typing import Any, List, Union, Optional, Dict, cast, Iterator
1919

2020
import jsonschema.validators
@@ -433,7 +433,7 @@ def new_view(self) -> View:
433433
"""
434434
new_view = View()
435435
new_view.id = self.new_view_id()
436-
new_view.metadata.timestamp = datetime.now()
436+
new_view.metadata.timestamp = datetime.now(timezone.utc)
437437
self.add_view(new_view)
438438
return new_view
439439

mmif/serialize/model.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -402,7 +402,10 @@ def default(self, obj: 'MmifObject'):
402402
if hasattr(obj, '_serialize'):
403403
return obj._serialize()
404404
elif hasattr(obj, 'isoformat'): # for datetime objects
405-
return obj.isoformat()
405+
s = obj.isoformat()
406+
if s.endswith('+00:00'):
407+
s = s[:-6] + 'Z'
408+
return s
406409
elif hasattr(obj, '__str__'):
407410
return str(obj)
408411
else:

tests/test_serialize.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -608,6 +608,25 @@ def test_get_label(self):
608608
a = v.new_annotation(AnnotationTypes.BoundingBox)
609609
_ = a._get_label()
610610

611+
def test_timestamp_uses_utc_with_z_suffix(self):
612+
"""Test that timestamps are in UTC with 'Z' suffix to avoid ambiguity"""
613+
from datetime import timezone
614+
mmif_obj = Mmif(validate=False)
615+
616+
new_view = mmif_obj.new_view()
617+
new_view.metadata.app = "http://test.app"
618+
619+
# Verify the timestamp is timezone-aware and uses UTC
620+
self.assertIsNotNone(new_view.metadata.timestamp)
621+
self.assertIsNotNone(new_view.metadata.timestamp.tzinfo)
622+
self.assertEqual(new_view.metadata.timestamp.tzinfo, timezone.utc)
623+
624+
# Verify serialization uses 'Z' suffix instead of '+00:00'
625+
serialized = json.loads(mmif_obj.serialize())
626+
ts = serialized['views'][0]['metadata']['timestamp']
627+
self.assertTrue(ts.endswith('Z'))
628+
self.assertNotIn('+00:00', ts)
629+
611630
def test_get_anchor_point(self):
612631
mmif = Mmif(validate=False)
613632
v1 = mmif.new_view()

0 commit comments

Comments
 (0)