Skip to content

Commit

Permalink
Work with Windows’ different epoch (#98)
Browse files Browse the repository at this point in the history
Fixes #89.
  • Loading branch information
adamchainz authored Jan 17, 2021
1 parent 71cf08a commit 16a76e4
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 3 deletions.
1 change: 1 addition & 0 deletions HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ History
* Remove ``tz_offset`` argument. This was incorrectly copied from
``freezegun``. Use the new timezone mocking with ``ZoneInfo`` instead.
* Add pytest plugin and fixture ``time_machine``.
* Work with Windows’ different epoch.

1.3.0 (2020-12-12)
------------------
Expand Down
22 changes: 20 additions & 2 deletions src/time_machine.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import os
import sys
import uuid
from time import gmtime as orig_gmtime
from time import tzset
from types import GeneratorType
from typing import Optional
Expand Down Expand Up @@ -33,6 +34,22 @@

NANOSECONDS_PER_SECOND = 1_000_000_000

# Windows' time epoch is not unix epoch but in 1601. This constant helps us
# translate to it.
_system_epoch = orig_gmtime(0)
SYSTEM_EPOCH_TIMESTAMP_NS = int(
dt.datetime(
_system_epoch.tm_year,
_system_epoch.tm_mon,
_system_epoch.tm_mday,
_system_epoch.tm_hour,
_system_epoch.tm_min,
_system_epoch.tm_sec,
tzinfo=dt.timezone.utc,
).timestamp()
* NANOSECONDS_PER_SECOND
)


def extract_timestamp_tzname(destination):
if callable(destination):
Expand Down Expand Up @@ -82,14 +99,15 @@ def time_ns(self):
if not self._tick:
return self._destination_timestamp_ns

base = SYSTEM_EPOCH_TIMESTAMP_NS + self._destination_timestamp_ns
now_ns = self._time_ns()

if not self._requested:
self._requested = True
self._real_start_timestamp_ns = now_ns
return self._destination_timestamp_ns
return base

return self._destination_timestamp_ns + (now_ns - self._real_start_timestamp_ns)
return base + (now_ns - self._real_start_timestamp_ns)

if sys.version_info >= (3, 7):

Expand Down
21 changes: 20 additions & 1 deletion tests/test_time_machine.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import time
import uuid
from importlib.util import module_from_spec, spec_from_file_location
from unittest import SkipTest, TestCase
from unittest import SkipTest, TestCase, mock

import pytest
from dateutil import tz
Expand Down Expand Up @@ -249,6 +249,25 @@ def test_time_time():
assert now >= LIBRARY_EPOCH


windows_epoch_in_posix = -11_644_445_222


@mock.patch.object(
time_machine,
"SYSTEM_EPOCH_TIMESTAMP_NS",
(windows_epoch_in_posix * NANOSECONDS_PER_SECOND),
)
def test_time_time_windows():
with time_machine.travel(EPOCH):
first = time.time()
assert isinstance(first, float)
assert first == windows_epoch_in_posix

second = time.time()
assert isinstance(second, float)
assert windows_epoch_in_posix < second < windows_epoch_in_posix + 1.0


def test_time_time_no_tick():
with time_machine.travel(EPOCH, tick=False):
assert time.time() == EPOCH
Expand Down

0 comments on commit 16a76e4

Please sign in to comment.