{"id":634,"library":"freezegun","title":"freezegun","description":"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.","status":"active","version":"1.5.5","language":"python","source_language":"en","source_url":"https://github.com/spulec/freezegun","tags":["testing","datetime","time","mocking","fixtures"],"install":[{"cmd":"pip install freezegun","lang":"bash","label":"Install stable version"}],"dependencies":[{"reason":"Requires Python 3.8 or newer.","package":"python","optional":false},{"reason":"Used internally for parsing flexible date/time strings.","package":"python-dateutil","optional":false},{"reason":"Fallback for timezone handling on Python versions older than 3.9, which lack `zoneinfo`.","package":"pytz","optional":true}],"imports":[{"symbol":"freeze_time","correct":"from freezegun import freeze_time"}],"quickstart":{"code":"import datetime\nfrom freezegun import freeze_time\n\n@freeze_time(\"2023-10-26 14:30:00\")\ndef test_fixed_time_decorator():\n    assert datetime.datetime.now() == datetime.datetime(2023, 10, 26, 14, 30, 0)\n    assert datetime.date.today() == datetime.date(2023, 10, 26)\n\ndef test_fixed_time_context_manager():\n    with freeze_time(\"2024-01-01 00:00:00\"):\n        assert datetime.datetime.now() == datetime.datetime(2024, 1, 1, 0, 0, 0)\n        assert datetime.datetime.utcnow() == datetime.datetime(2024, 1, 1, 0, 0, 0)\n\ndef test_advancing_time():\n    with freeze_time(\"2023-01-01 10:00:00\", tick=True) as frozen_datetime:\n        start_time = datetime.datetime.now()\n        print(f\"Start: {start_time}\")\n        # Simulate some operations that take time, like an external API call\n        # In real tests, you might have code here that calls `datetime.now()` multiple times\n        frozen_datetime.tick(delta=datetime.timedelta(seconds=5))\n        after_tick = datetime.datetime.now()\n        print(f\"After tick: {after_tick}\")\n        assert after_tick - start_time == datetime.timedelta(seconds=5)\n\ntest_fixed_time_decorator()\ntest_fixed_time_context_manager()\ntest_advancing_time()","lang":"python","description":"The most common way to use freezegun is via the `@freeze_time` decorator for test functions or the `with freeze_time(...)` context manager for specific blocks of code. You can pass a string representing the desired date and time. The `tick=True` parameter allows time to advance naturally (or manually with `frozen_datetime.tick()`) after the initial freeze, useful for testing time-sensitive sequences or durations. It effectively mocks `datetime.datetime.now()`, `datetime.date.today()`, `time.time()`, and related functions."},"warnings":[{"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.","message":"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.","severity":"gotcha","affected_versions":"All versions"},{"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.","message":"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.","severity":"breaking","affected_versions":"<1.4.0"},{"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`).","message":"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).","severity":"gotcha","affected_versions":"All versions"},{"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.","message":"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.","severity":"gotcha","affected_versions":"All versions"},{"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).","message":"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.","severity":"gotcha","affected_versions":"All versions"},{"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.","message":"`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.","severity":"gotcha","affected_versions":"All versions"},{"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.","message":"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.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"last_verified":"2026-05-12T17:02:15.993Z","next_check":"2026-06-26T00:00:00.000Z","problems":[{"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.","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.","error":"datetime.datetime.now() not frozen freezegun"},{"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.","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.","error":"AttributeError: type object 'datetime.datetime' has no attribute 'datetime'"},{"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.","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.","error":"RuntimeError: 'datetime' module was frozen, but the 'datetime' module itself was replaced"},{"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.","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.","error":"freezegun time.time() not frozen in thread"}],"ecosystem":"pypi","meta_description":null,"install_score":100,"install_tag":"verified","quickstart_score":0,"quickstart_tag":"stale","pypi_latest":"1.5.5","install_checks":{"last_tested":"2026-05-12","tag":"verified","tag_description":"installs cleanly on critical runtimes, fast import, recently tested","results":[{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":null,"import_time_s":0.22,"mem_mb":7.5,"disk_size":"18.8M"},{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.24,"mem_mb":7.5,"disk_size":"18.8M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":1.6,"import_time_s":0.15,"mem_mb":7.5,"disk_size":"19M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.15,"mem_mb":7.5,"disk_size":"19M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":null,"import_time_s":0.32,"mem_mb":8.4,"disk_size":"20.8M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.36,"mem_mb":8.4,"disk_size":"20.8M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":1.7,"import_time_s":0.32,"mem_mb":8.4,"disk_size":"21M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.27,"mem_mb":8.4,"disk_size":"21M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":null,"import_time_s":0.53,"mem_mb":8.4,"disk_size":"12.6M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.57,"mem_mb":8.4,"disk_size":"12.6M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":1.6,"import_time_s":0.51,"mem_mb":8.4,"disk_size":"13M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.49,"mem_mb":8.4,"disk_size":"13M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":null,"import_time_s":0.54,"mem_mb":8.8,"disk_size":"12.3M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.57,"mem_mb":8.8,"disk_size":"12.2M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":1.6,"import_time_s":0.52,"mem_mb":8.8,"disk_size":"13M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.51,"mem_mb":8.8,"disk_size":"13M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":null,"import_time_s":0.23,"mem_mb":7.2,"disk_size":"18.2M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.25,"mem_mb":7.2,"disk_size":"18.2M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":1.9,"import_time_s":0.19,"mem_mb":7.2,"disk_size":"19M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.18,"mem_mb":7.2,"disk_size":"19M"}]},"quickstart_checks":{"last_tested":"2026-04-24","tag":"stale","tag_description":"widespread failures or data too old to trust","results":[{"runtime":"python:3.10-alpine","exit_code":1},{"runtime":"python:3.10-slim","exit_code":1},{"runtime":"python:3.11-alpine","exit_code":1},{"runtime":"python:3.11-slim","exit_code":1},{"runtime":"python:3.12-alpine","exit_code":1},{"runtime":"python:3.12-slim","exit_code":1},{"runtime":"python:3.13-alpine","exit_code":1},{"runtime":"python:3.13-slim","exit_code":1},{"runtime":"python:3.9-alpine","exit_code":1},{"runtime":"python:3.9-slim","exit_code":1}]}}