Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ Usage

If you’re coming from freezegun or libfaketime, see also the below section on migrating.

``travel(destination, *, tick=True)``
``travel(destination, *, tick=True, tick_delta=None)``
-------------------------------------

``travel()`` is a class that allows time travel, to the datetime specified by ``destination``.
Expand Down Expand Up @@ -98,6 +98,18 @@ If ``True``, the default, successive calls to mocked functions return values inc
So after starting travel to ``0.0`` (the UNIX epoch), the first call to any datetime function will return its representation of ``1970-01-01 00:00:00.000000`` exactly.
The following calls "tick," so if a call was made exactly half a second later, it would return ``1970-01-01 00:00:00.500000``.

If ``tick`` is ``True``, setting ``tick_delta`` makes the tick deterministic, for example:

.. code-block:: python

with time_machine.travel(
dt.datetime(2023, 1, 1), tick_delta=dt.timedelta(microseconds=1)
):
assert dt.datetime.now() == dt.datetime(2023, 1, 1, 0, 0, microsecond=0)
assert dt.datetime.now() == dt.datetime(2023, 1, 1, 0, 0, microsecond=1)
assert dt.datetime.now() == dt.datetime(2023, 1, 1, 0, 0, microsecond=2)
...

Mocked Functions
^^^^^^^^^^^^^^^^

Expand Down
19 changes: 18 additions & 1 deletion src/time_machine/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,12 +125,14 @@ def __init__(
destination_timestamp: float,
destination_tzname: str | None,
tick: bool,
tick_delta: dt.timedelta | None = None,
) -> None:
self._destination_timestamp_ns = int(
destination_timestamp * NANOSECONDS_PER_SECOND
)
self._destination_tzname = destination_tzname
self._tick = tick
self._tick_delta = tick_delta
self._requested = False

def time(self) -> float:
Expand All @@ -140,6 +142,13 @@ def time_ns(self) -> int:
if not self._tick:
return self._destination_timestamp_ns

if self._tick_delta is not None:
destination_timestamp_ns_before = self._destination_timestamp_ns
self._destination_timestamp_ns += int(
self._tick_delta.total_seconds() * NANOSECONDS_PER_SECOND
)
return destination_timestamp_ns_before

base = SYSTEM_EPOCH_TIMESTAMP_NS + self._destination_timestamp_ns
now_ns: int = _time_machine.original_time_ns()

Expand Down Expand Up @@ -200,11 +209,18 @@ def _stop(self) -> None:


class travel:
def __init__(self, destination: DestinationType, *, tick: bool = True) -> None:
def __init__(
self,
destination: DestinationType,
*,
tick: bool = True,
tick_delta: dt.timedelta | None = None,
) -> None:
self.destination_timestamp, self.destination_tzname = extract_timestamp_tzname(
destination
)
self.tick = tick
self.tick_delta = tick_delta

def start(self) -> Coordinates:
_time_machine.patch_if_needed()
Expand All @@ -217,6 +233,7 @@ def start(self) -> Coordinates:
destination_timestamp=self.destination_timestamp,
destination_tzname=self.destination_tzname,
tick=self.tick,
tick_delta=self.tick_delta,
)
coordinates_stack.append(coordinates)
coordinates._start()
Expand Down
16 changes: 16 additions & 0 deletions tests/test_time_machine.py
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,22 @@ def test_time_time_ns_no_tick():
assert time.time_ns() == int(EPOCH * NANOSECONDS_PER_SECOND)


def test_tick_delta() -> None:
ts = list[dt.datetime]()
with time_machine.travel(
dt.datetime(2023, 1, 1), tick_delta=dt.timedelta(microseconds=1)
):
for _ in range(5):
ts.append(dt.datetime.now())
assert ts == [
dt.datetime(2023, 1, 1, 0, 0, microsecond=0),
dt.datetime(2023, 1, 1, 0, 0, microsecond=1),
dt.datetime(2023, 1, 1, 0, 0, microsecond=2),
dt.datetime(2023, 1, 1, 0, 0, microsecond=3),
dt.datetime(2023, 1, 1, 0, 0, microsecond=4),
]


# all supported forms


Expand Down