diff --git a/swh/model/model.py b/swh/model/model.py --- a/swh/model/model.py +++ b/swh/model/model.py @@ -257,6 +257,21 @@ def from_datetime(cls, dt: datetime.datetime): return cls.from_dict(dt) + def to_datetime(self) -> datetime.datetime: + """Convert to a datetime (with a timezone set to the recorded fixed UTC offset) + + Beware that this conversion can be lossy: the negative_utc flag is not + taken into consideration (since it cannot be represented in a + datetime). Also note that it may fail due to type overflow. + + """ + timestamp = datetime.datetime.fromtimestamp( + self.timestamp.seconds, + datetime.timezone(datetime.timedelta(minutes=self.offset)), + ) + timestamp = timestamp.replace(microsecond=self.timestamp.microseconds) + return timestamp + @classmethod def from_iso8601(cls, s): """Builds a TimestampWithTimezone from an ISO8601-formatted string. 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 @@ -48,6 +48,8 @@ ) from swh.model.tests.swh_model_data import TEST_OBJECTS from swh.model.tests.test_identifiers import ( + TS_DATETIMES, + TS_TIMEZONES, content_example, directory_example, metadata_example, @@ -329,6 +331,17 @@ ) +@pytest.mark.parametrize("date", TS_DATETIMES) +@pytest.mark.parametrize("tz", TS_TIMEZONES) +@pytest.mark.parametrize("microsecond", [0, 1, 10, 100, 1000, 999999]) +def test_timestampwithtimezone_to_datetime(date, tz, microsecond): + date = date.replace(tzinfo=tz, microsecond=microsecond) + tstz = TimestampWithTimezone.from_datetime(date) + + assert tstz.to_datetime() == date + assert tstz.to_datetime().utcoffset() == date.utcoffset() + + def test_person_from_fullname(): """The author should have name, email and fullname filled.