Travel through time in your tests.
The escape hatch provides access to real time functions during time travel, enabling tests to access actual system time when needed. This is essential for performance measurements, external API calls, or any operations requiring real timestamps.
The global escape_hatch object provides access to real time functions and travel status checking.
class _EscapeHatch:
def is_travelling(self) -> bool:
"""
Check if time travel is currently active.
Returns:
True if time travel is active, False otherwise
"""
time: _EscapeHatchTime
datetime: _EscapeHatchDatetimeescape_hatch: _EscapeHatchUsage examples:
import time_machine
from datetime import datetime
# Check travel status
print(time_machine.escape_hatch.is_travelling()) # False
with time_machine.travel("2023-01-01"):
print(time_machine.escape_hatch.is_travelling()) # True
# Access real time during travel
real_time = time_machine.escape_hatch.time.time()
fake_time = time.time()
print(f"Real time: {real_time}")
print(f"Fake time: {fake_time}")
print(time_machine.escape_hatch.is_travelling()) # FalseAccess to real time module functions that bypass time travel patching.
class _EscapeHatchTime:
def clock_gettime(self, clk_id: int) -> float:
"""
Get real clock time for specified clock ID.
Parameters:
- clk_id: Clock identifier (e.g., time.CLOCK_REALTIME)
Returns:
Real clock time as float seconds
"""
def clock_gettime_ns(self, clk_id: int) -> int:
"""
Get real clock time in nanoseconds for specified clock ID.
Parameters:
- clk_id: Clock identifier
Returns:
Real clock time as int nanoseconds
"""
def gmtime(self, secs: float | None = None) -> struct_time:
"""
Get real GMT time struct.
Parameters:
- secs: Optional timestamp, uses real current time if None
Returns:
Real GMT time as struct_time
"""
def localtime(self, secs: float | None = None) -> struct_time:
"""
Get real local time struct.
Parameters:
- secs: Optional timestamp, uses real current time if None
Returns:
Real local time as struct_time
"""
def monotonic(self) -> float:
"""
Get real monotonic time (unaffected by system clock adjustments).
Returns:
Real monotonic time as float seconds
"""
def monotonic_ns(self) -> int:
"""
Get real monotonic time in nanoseconds.
Returns:
Real monotonic time as int nanoseconds
"""
def strftime(self, format: str, t: tuple | struct_time | None = None) -> str:
"""
Format real time using strftime.
Parameters:
- format: Format string
- t: Optional time tuple, uses real current time if None
Returns:
Formatted time string
"""
def time(self) -> float:
"""
Get real current time as Unix timestamp.
Returns:
Real current time as float seconds since Unix epoch
"""
def time_ns(self) -> int:
"""
Get real current time as nanosecond timestamp.
Returns:
Real current time as int nanoseconds since Unix epoch
"""Usage examples:
import time
import time_machine
with time_machine.travel("2023-01-01"):
# Fake time (2023)
fake_time = time.time()
# Real time (actual current time)
real_time = time_machine.escape_hatch.time.time()
print(f"Travel time: {fake_time}") # ~1672531200 (2023-01-01)
print(f"Real time: {real_time}") # Actual current timestamp
# Performance measurement using real monotonic time
start = time_machine.escape_hatch.time.monotonic()
# ... some operation ...
elapsed = time_machine.escape_hatch.time.monotonic() - start
print(f"Real elapsed time: {elapsed}")Access to real datetime module functions that bypass time travel patching.
class _EscapeHatchDatetime:
datetime: _EscapeHatchDatetimeDatetime
class _EscapeHatchDatetimeDatetime:
def now(self, tz: dt.tzinfo | None = None) -> dt.datetime:
"""
Get real current datetime.
Parameters:
- tz: Optional timezone info
Returns:
Real current datetime object
"""
def utcnow(self) -> dt.datetime:
"""
Get real current UTC datetime (naive).
Returns:
Real current UTC datetime without timezone info
"""Usage examples:
import time_machine
from datetime import datetime, timezone
with time_machine.travel("2023-01-01"):
# Fake datetime (2023)
fake_now = datetime.now()
# Real datetime (actual current time)
real_now = time_machine.escape_hatch.datetime.datetime.now()
print(f"Travel time: {fake_now}") # 2023-01-01 00:00:00
print(f"Real time: {real_now}") # Actual current datetime
# Real UTC time
real_utc = time_machine.escape_hatch.datetime.datetime.utcnow()
print(f"Real UTC: {real_utc}")
# Real time with timezone
real_tz = time_machine.escape_hatch.datetime.datetime.now(timezone.utc)
print(f"Real UTC+TZ: {real_tz}")import time_machine
def test_performance():
with time_machine.travel("2023-01-01"):
# Use real monotonic time for accurate performance measurement
start = time_machine.escape_hatch.time.monotonic()
# Operation being timed
slow_operation()
elapsed = time_machine.escape_hatch.time.monotonic() - start
assert elapsed < 1.0 # Should complete within 1 secondimport time_machine
import requests
def test_api_with_real_timestamps():
with time_machine.travel("2023-01-01"):
# API expects real timestamps in headers
real_timestamp = time_machine.escape_hatch.time.time()
response = requests.post("https://api.example.com/data",
headers={"X-Timestamp": str(real_timestamp)},
json={"created_at": time.time()}) # Uses fake time
assert response.status_code == 200import time_machine
import logging
def test_with_real_log_timestamps():
# Custom formatter using real time
class RealTimeFormatter(logging.Formatter):
def formatTime(self, record, datefmt=None):
real_time = time_machine.escape_hatch.time.time()
return super().formatTime(
type('Record', (), {'created': real_time})(), datefmt
)
with time_machine.travel("2023-01-01"):
logger = logging.getLogger("test")
handler = logging.StreamHandler()
handler.setFormatter(RealTimeFormatter())
logger.addHandler(handler)
logger.info("This log has real timestamp despite time travel")import time_machine
def get_current_time():
"""Get current time, using real time in production, fake time in tests."""
if time_machine.escape_hatch.is_travelling():
# In tests - use travel time
return datetime.now()
else:
# In production - use real time
return time_machine.escape_hatch.datetime.datetime.now()
def test_conditional_time():
# Outside travel - uses real time
real_time = get_current_time()
with time_machine.travel("2023-01-01"):
# Inside travel - uses fake time
fake_time = get_current_time()
assert fake_time.year == 2023from time import struct_time
from datetime import datetime as dt
_TimeTuple = tuple[int, int, int, int, int, int, int, int, int]Install with Tessl CLI
npx tessl i tessl/pypi-time-machine