diff --git a/freezegun/api.py b/freezegun/api.py index 6096896a..69fe3692 100644 --- a/freezegun/api.py +++ b/freezegun/api.py @@ -1,3 +1,4 @@ +import dateutil import datetime import functools import sys @@ -21,6 +22,8 @@ MayaDT = None _TIME_NS_PRESENT = hasattr(time, 'time_ns') +_EPOCH = datetime.datetime(1970, 1, 1) +_EPOCHTZ = datetime.datetime(1970, 1, 1, tzinfo=dateutil.tz.UTC) real_time = time.time real_localtime = time.localtime @@ -335,6 +338,19 @@ def astimezone(self, tz=None): tz = tzlocal() return datetime_to_fakedatetime(real_datetime.astimezone(self, tz)) + @classmethod + def fromtimestamp(cls, t, tz=None): + if tz is None: + return real_datetime.fromtimestamp( + t, tz=dateutil.tz.tzoffset("freezegun", cls._tz_offset()) + ).replace(tzinfo=None) + return datetime_to_fakedatetime(real_datetime.fromtimestamp(t, tz)) + + def timestamp(self): + if self.tzinfo is None: + return (self - _EPOCH - self._tz_offset()).total_seconds() + return (self - _EPOCHTZ).total_seconds() + @classmethod def now(cls, tz=None): now = cls._time_to_freeze() or real_datetime.now() diff --git a/tests/test_datetimes.py b/tests/test_datetimes.py index 9bafb493..dbdb3f94 100644 --- a/tests/test_datetimes.py +++ b/tests/test_datetimes.py @@ -5,6 +5,7 @@ import locale import sys from unittest import SkipTest +from dateutil.tz import UTC import pytest from tests import utils @@ -449,9 +450,7 @@ def test_nested_context_manager(): def _assert_datetime_date_and_time_are_all_equal(expected_datetime): assert datetime.datetime.now() == expected_datetime assert datetime.date.today() == expected_datetime.date() - datetime_from_time = datetime.datetime.fromtimestamp(time.time()) - timezone_adjusted_datetime = datetime_from_time + datetime.timedelta(seconds=time.timezone) - assert timezone_adjusted_datetime == expected_datetime + assert datetime.datetime.fromtimestamp(time.time()) == expected_datetime def test_nested_context_manager_with_tz_offsets(): @@ -689,7 +688,6 @@ def test_time_ns(): assert time.time_ns() != expected_timestamp * 1e9 -@pytest.mark.skip("timezone handling is currently incorrect") def test_compare_datetime_and_time_with_timezone(monkeypatch): """ Compare the result of datetime.datetime.now() and time.time() in a non-UTC timezone. These @@ -700,13 +698,28 @@ def test_compare_datetime_and_time_with_timezone(monkeypatch): m.setenv("TZ", "Europe/Berlin") time.tzset() - dt1 = datetime.datetime.now() - dt2 = datetime.datetime.fromtimestamp(time.time()) - assert dt1 == dt2 + now = datetime.datetime.now() + assert now == datetime.datetime.fromtimestamp(time.time()) + assert now == datetime.datetime.utcfromtimestamp(time.time()) + assert now == datetime.datetime.utcnow() + assert now.timestamp() == time.time() finally: time.tzset() # set the timezone back to what is was before +def test_timestamp_with_tzoffset(): + with freeze_time("2000-01-01", tz_offset=6): + utcnow = datetime.datetime(2000, 1, 1, 0) + nowtz = datetime.datetime(2000, 1, 1, 0, tzinfo=UTC) + now = datetime.datetime(2000, 1, 1, 6) + assert now == datetime.datetime.now() + assert now == datetime.datetime.fromtimestamp(time.time()) + assert now.timestamp() == time.time() + assert nowtz.timestamp() == time.time() + + assert utcnow == datetime.datetime.utcfromtimestamp(time.time()) + assert utcnow == datetime.datetime.utcnow() + @pytest.mark.skip("timezone handling is currently incorrect") def test_datetime_in_timezone(monkeypatch): """