freezegun
freezegun is a Python library (currently at version 1.5.5) that enables your tests to 'travel through time' by mocking the `datetime`, `date`, `time`, and `pendulum` modules. It simplifies testing time-sensitive code by allowing developers to freeze the current time or simulate its passage, ensuring deterministic and reliable test execution. The project maintains a regular release cadence, with frequent patch and minor updates.
Warnings
- gotcha Performance overhead in large projects: freezegun works by scanning and patching all imported modules that use date/time functions. In applications with many modules or complex dependency trees, this 'find-and-replace' mechanism can introduce significant overhead, making tests noticeably slower. For performance-critical scenarios, libraries like `time-machine` which mock at the C layer may be faster.
- breaking Asyncio compatibility issues: Prior to version 1.4.0, using `freezegun` with `asyncio` could cause `asyncio.sleep()` and other monotonic time-dependent functions to hang indefinitely, as `time.monotonic()` was also frozen. This was a common pitfall for asynchronous applications.
- gotcha Incomplete mocking scope: freezegun primarily patches module-level imports of `datetime` and `time` functions. It may not intercept calls to time functions that are 'hidden' inside arbitrary objects, set as default function arguments during module import, or invoked directly from C extensions (e.g., Cython-compiled code or certain low-level system calls made by third-party libraries).
- gotcha Timezone inconsistencies: Freezing time without explicitly managing timezones can lead to unexpected discrepancies, particularly when mixing `datetime.now()` (timezone-aware/local) and `datetime.utcnow()` (naive UTC) or `time.time()`. Issues can arise around Daylight Saving Time (DST) transitions if not handled carefully.
- gotcha External network call issues (SSL/Certificates): Freezing time to a date far in the past can cause `SSLCertVerificationError` when making external HTTP requests. This happens because the SSL certificates used by servers have validity periods, and if the frozen time falls outside this period (e.g., before the certificate's 'notBefore' date), the certificate validation will fail.
Install
-
pip install freezegun
Imports
- freeze_time
from freezegun import freeze_time
Quickstart
import datetime
from freezegun import freeze_time
@freeze_time("2023-10-26 14:30:00")
def test_fixed_time_decorator():
assert datetime.datetime.now() == datetime.datetime(2023, 10, 26, 14, 30, 0)
assert datetime.date.today() == datetime.date(2023, 10, 26)
def test_fixed_time_context_manager():
with freeze_time("2024-01-01 00:00:00"):
assert datetime.datetime.now() == datetime.datetime(2024, 1, 1, 0, 0, 0)
assert datetime.datetime.utcnow() == datetime.datetime(2024, 1, 1, 0, 0, 0)
def test_advancing_time():
with freeze_time("2023-01-01 10:00:00", tick=True) as frozen_datetime:
start_time = datetime.datetime.now()
print(f"Start: {start_time}")
# Simulate some operations that take time, like an external API call
# In real tests, you might have code here that calls `datetime.now()` multiple times
frozen_datetime.tick(delta=datetime.timedelta(seconds=5))
after_tick = datetime.datetime.now()
print(f"After tick: {after_tick}")
assert after_tick - start_time == datetime.timedelta(seconds=5)
test_fixed_time_decorator()
test_fixed_time_context_manager()
test_advancing_time()