freezegun
raw JSON → 1.5.5 verified Tue May 12 auth: no python install: verified quickstart: stale
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.
pip install freezegun Common errors
error datetime.datetime.now() not frozen freezegun ↓
cause The `datetime` module or its components (like `datetime.datetime` or `datetime.date`) were imported into the module under test at module load time, before `freezegun` had a chance to patch them.
fix
Ensure that
datetime imports in the code under test occur within the scope of the freezegun.freeze_time decorator or context manager, or that freezegun is initialized early enough to patch already loaded modules. error AttributeError: type object 'datetime.datetime' has no attribute 'datetime' ↓
cause This error typically occurs when `datetime` is imported using `from datetime import datetime` and then an attempt is made to access `datetime.datetime.now()`. When `datetime.datetime` is imported directly, `datetime` itself refers to the class, not the module, so `datetime.datetime` is invalid.
fix
Change the import statement to
import datetime and then call datetime.datetime.now(), or if you import from datetime import datetime, directly call datetime.now() without the module prefix. error RuntimeError: 'datetime' module was frozen, but the 'datetime' module itself was replaced ↓
cause This error indicates a conflict where `freezegun` has already frozen the `datetime` module, but another library or part of the test setup subsequently replaces the `datetime` module entirely, breaking `freezegun`'s patch.
fix
Investigate if another mocking library or a complex test fixture is also manipulating the
datetime module. Ensure freezegun is the last to apply its patches, or use freezegun.configure(default_ignore_list=[...]) or the ignore parameter on freeze_time to exclude conflicting modules. error freezegun time.time() not frozen in thread ↓
cause By default, `freezegun` adds `threading` to its ignore list to prevent deadlocks and unexpected behavior, meaning `time.time()` calls originating from within the `threading` module (or code that is considered part of `threading`'s stack) will not be frozen.
fix
If you explicitly need to freeze time within threads, you can remove
threading from the ignore list using freeze_time(..., ignore=['list', 'of', 'modules'] - {'threading'}) or freezegun.configure(default_ignore_list=list(set(freezegun.config.default_ignore_list) - {'threading'})). Exercise caution as this can lead to deadlocks if threading internals are also frozen. 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. ↓
fix For smaller projects, this overhead is usually negligible. For large projects with slow time-mocking tests, consider profiling to confirm `freezegun` as the bottleneck and evaluate alternatives like `time-machine`. Ensure `freezegun` is only active for the specific tests requiring time manipulation.
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. ↓
fix Upgrade to freezegun 1.4.0 or newer. Use the `real_asyncio=True` parameter with `freeze_time` (e.g., `with freeze_time('2023-01-01', real_asyncio=True):`) to allow asyncio event loops to use real monotonic time while other time functions remain frozen.
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). ↓
fix Be aware of how time-related functions are imported and used in the code under test. If you encounter unmocked time, inspect the import path and call stack. For C extensions or deeply embedded time calls, `freezegun` might not be sufficient, and you might need to use other mocking strategies or a library that intercepts at a lower level (like `time-machine`).
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. ↓
fix Always specify the desired timezone when freezing time if your application is timezone-aware (e.g., `freeze_time('2023-10-26 14:30:00', tz_offset=-5)` or ensuring `datetime.now()` is explicitly timezone-aware where needed). Test edge cases like DST transitions to ensure consistent behavior.
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. ↓
fix When testing code that makes external HTTP requests with SSL, ensure the frozen time is within the validity period of common SSL certificates. Alternatively, if appropriate for your test, consider mocking the external HTTP calls entirely or disabling SSL verification for that specific test (with caution).
gotcha `freezegun`'s `tick()` or `travel()` functions may introduce minor microsecond precision discrepancies when advancing time. If the initial `datetime.now()` or subsequent `datetime.now()` calls include non-zero microseconds, direct comparisons of `timedelta`s to exact second values can fail, leading to `AssertionError`s. This often happens because the patching mechanism might handle sub-second precision differently when freezing vs. advancing. ↓
fix When asserting time advancement with `freezegun`, consider using a small tolerance for `timedelta` comparisons (e.g., `assert abs((after_tick - start_time) - datetime.timedelta(seconds=5)) < datetime.timedelta(microseconds=100)`) or truncate `datetime` objects to milliseconds/seconds before comparison to avoid microsecond-level precision issues.
gotcha Freezegun may introduce minor microsecond discrepancies when advancing time, particularly when using `freezegun.move_time()` or performing arithmetic with high-precision `datetime` objects. This can lead to `AssertionError` if tests expect exact equality with `datetime.timedelta` comparisons, even for seemingly precise time advancements. The observed discrepancies are typically very small, on the order of a few microseconds. ↓
fix Instead of asserting for exact equality with `datetime.timedelta`, consider comparing with a small tolerance for microsecond differences (e.g., `assert abs(actual_timedelta - expected_timedelta) < datetime.timedelta(microseconds=10)`). Alternatively, round `datetime` objects to a desired precision (e.g., seconds or milliseconds) before comparison if microsecond accuracy is not critical for the test.
Install compatibility verified last tested: 2026-05-12
python os / libc status wheel install import disk
3.10 alpine (musl) wheel - 0.22s 18.8M
3.10 alpine (musl) - - 0.24s 18.8M
3.10 slim (glibc) wheel 1.6s 0.15s 19M
3.10 slim (glibc) - - 0.15s 19M
3.11 alpine (musl) wheel - 0.32s 20.8M
3.11 alpine (musl) - - 0.36s 20.8M
3.11 slim (glibc) wheel 1.7s 0.32s 21M
3.11 slim (glibc) - - 0.27s 21M
3.12 alpine (musl) wheel - 0.53s 12.6M
3.12 alpine (musl) - - 0.57s 12.6M
3.12 slim (glibc) wheel 1.6s 0.51s 13M
3.12 slim (glibc) - - 0.49s 13M
3.13 alpine (musl) wheel - 0.54s 12.3M
3.13 alpine (musl) - - 0.57s 12.2M
3.13 slim (glibc) wheel 1.6s 0.52s 13M
3.13 slim (glibc) - - 0.51s 13M
3.9 alpine (musl) wheel - 0.23s 18.2M
3.9 alpine (musl) - - 0.25s 18.2M
3.9 slim (glibc) wheel 1.9s 0.19s 19M
3.9 slim (glibc) - - 0.18s 19M
Imports
- freeze_time
from freezegun import freeze_time
Quickstart stale last tested: 2026-04-24
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()