diff --git a/swh/model/model.py b/swh/model/model.py --- a/swh/model/model.py +++ b/swh/model/model.py @@ -19,6 +19,7 @@ import datetime from enum import Enum import hashlib +import math from typing import Any, Dict, Iterable, Optional, Tuple, TypeVar, Union import attr @@ -477,7 +478,7 @@ microseconds = time_representation.microsecond if microseconds: time_representation = time_representation.replace(microsecond=0) - seconds = int(time_representation.timestamp()) + seconds = math.floor(time_representation.timestamp()) utcoffset = time_representation.utcoffset() if utcoffset is None: raise ValueError( diff --git a/swh/model/tests/test_model.py b/swh/model/tests/test_model.py --- a/swh/model/tests/test_model.py +++ b/swh/model/tests/test_model.py @@ -500,17 +500,45 @@ def test_timestampwithtimezone_from_datetime(): + # Typical case tz = datetime.timezone(datetime.timedelta(minutes=+60)) date = datetime.datetime(2020, 2, 27, 14, 39, 19, tzinfo=tz) - tstz = TimestampWithTimezone.from_datetime(date) - assert tstz == TimestampWithTimezone( timestamp=Timestamp(seconds=1582810759, microseconds=0,), offset=60, negative_utc=False, ) + # Typical case (close to epoch) + tz = datetime.timezone(datetime.timedelta(minutes=+60)) + date = datetime.datetime(1970, 1, 1, 1, 0, 5, tzinfo=tz) + tstz = TimestampWithTimezone.from_datetime(date) + assert tstz == TimestampWithTimezone( + timestamp=Timestamp(seconds=5, microseconds=0,), offset=60, negative_utc=False, + ) + + # non-integer number of seconds before UNIX epoch + date = datetime.datetime( + 1969, 12, 31, 23, 59, 59, 100000, tzinfo=datetime.timezone.utc + ) + tstz = TimestampWithTimezone.from_datetime(date) + assert tstz == TimestampWithTimezone( + timestamp=Timestamp(seconds=-1, microseconds=100000,), + offset=0, + negative_utc=False, + ) + + # timezone offset with non-integer number of seconds, for dates before epoch + # we round down to the previous second, so it should be the same as + # 1969-01-01T23:59:59Z + tz = datetime.timezone(datetime.timedelta(microseconds=100000)) + date = datetime.datetime(1970, 1, 1, 0, 0, 0, tzinfo=tz) + tstz = TimestampWithTimezone.from_datetime(date) + assert tstz == TimestampWithTimezone( + timestamp=Timestamp(seconds=-1, microseconds=0,), offset=0, negative_utc=False, + ) + def test_timestampwithtimezone_from_naive_datetime(): date = datetime.datetime(2020, 2, 27, 14, 39, 19)