0
# Escape Hatch
1
2
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.
3
4
## Capabilities
5
6
### Escape Hatch Object
7
8
The global `escape_hatch` object provides access to real time functions and travel status checking.
9
10
```python { .api }
11
class _EscapeHatch:
12
def is_travelling(self) -> bool:
13
"""
14
Check if time travel is currently active.
15
16
Returns:
17
True if time travel is active, False otherwise
18
"""
19
20
time: _EscapeHatchTime
21
datetime: _EscapeHatchDatetime
22
```
23
24
```python { .api }
25
escape_hatch: _EscapeHatch
26
```
27
28
Usage examples:
29
30
```python
31
import time_machine
32
from datetime import datetime
33
34
# Check travel status
35
print(time_machine.escape_hatch.is_travelling()) # False
36
37
with time_machine.travel("2023-01-01"):
38
print(time_machine.escape_hatch.is_travelling()) # True
39
40
# Access real time during travel
41
real_time = time_machine.escape_hatch.time.time()
42
fake_time = time.time()
43
44
print(f"Real time: {real_time}")
45
print(f"Fake time: {fake_time}")
46
47
print(time_machine.escape_hatch.is_travelling()) # False
48
```
49
50
### Real Time Functions
51
52
Access to real time module functions that bypass time travel patching.
53
54
```python { .api }
55
class _EscapeHatchTime:
56
def clock_gettime(self, clk_id: int) -> float:
57
"""
58
Get real clock time for specified clock ID.
59
60
Parameters:
61
- clk_id: Clock identifier (e.g., time.CLOCK_REALTIME)
62
63
Returns:
64
Real clock time as float seconds
65
"""
66
67
def clock_gettime_ns(self, clk_id: int) -> int:
68
"""
69
Get real clock time in nanoseconds for specified clock ID.
70
71
Parameters:
72
- clk_id: Clock identifier
73
74
Returns:
75
Real clock time as int nanoseconds
76
"""
77
78
def gmtime(self, secs: float | None = None) -> struct_time:
79
"""
80
Get real GMT time struct.
81
82
Parameters:
83
- secs: Optional timestamp, uses real current time if None
84
85
Returns:
86
Real GMT time as struct_time
87
"""
88
89
def localtime(self, secs: float | None = None) -> struct_time:
90
"""
91
Get real local time struct.
92
93
Parameters:
94
- secs: Optional timestamp, uses real current time if None
95
96
Returns:
97
Real local time as struct_time
98
"""
99
100
def monotonic(self) -> float:
101
"""
102
Get real monotonic time (unaffected by system clock adjustments).
103
104
Returns:
105
Real monotonic time as float seconds
106
"""
107
108
def monotonic_ns(self) -> int:
109
"""
110
Get real monotonic time in nanoseconds.
111
112
Returns:
113
Real monotonic time as int nanoseconds
114
"""
115
116
def strftime(self, format: str, t: tuple | struct_time | None = None) -> str:
117
"""
118
Format real time using strftime.
119
120
Parameters:
121
- format: Format string
122
- t: Optional time tuple, uses real current time if None
123
124
Returns:
125
Formatted time string
126
"""
127
128
def time(self) -> float:
129
"""
130
Get real current time as Unix timestamp.
131
132
Returns:
133
Real current time as float seconds since Unix epoch
134
"""
135
136
def time_ns(self) -> int:
137
"""
138
Get real current time as nanosecond timestamp.
139
140
Returns:
141
Real current time as int nanoseconds since Unix epoch
142
"""
143
```
144
145
Usage examples:
146
147
```python
148
import time
149
import time_machine
150
151
with time_machine.travel("2023-01-01"):
152
# Fake time (2023)
153
fake_time = time.time()
154
155
# Real time (actual current time)
156
real_time = time_machine.escape_hatch.time.time()
157
158
print(f"Travel time: {fake_time}") # ~1672531200 (2023-01-01)
159
print(f"Real time: {real_time}") # Actual current timestamp
160
161
# Performance measurement using real monotonic time
162
start = time_machine.escape_hatch.time.monotonic()
163
# ... some operation ...
164
elapsed = time_machine.escape_hatch.time.monotonic() - start
165
print(f"Real elapsed time: {elapsed}")
166
```
167
168
### Real DateTime Functions
169
170
Access to real datetime module functions that bypass time travel patching.
171
172
```python { .api }
173
class _EscapeHatchDatetime:
174
datetime: _EscapeHatchDatetimeDatetime
175
176
class _EscapeHatchDatetimeDatetime:
177
def now(self, tz: dt.tzinfo | None = None) -> dt.datetime:
178
"""
179
Get real current datetime.
180
181
Parameters:
182
- tz: Optional timezone info
183
184
Returns:
185
Real current datetime object
186
"""
187
188
def utcnow(self) -> dt.datetime:
189
"""
190
Get real current UTC datetime (naive).
191
192
Returns:
193
Real current UTC datetime without timezone info
194
"""
195
```
196
197
Usage examples:
198
199
```python
200
import time_machine
201
from datetime import datetime, timezone
202
203
with time_machine.travel("2023-01-01"):
204
# Fake datetime (2023)
205
fake_now = datetime.now()
206
207
# Real datetime (actual current time)
208
real_now = time_machine.escape_hatch.datetime.datetime.now()
209
210
print(f"Travel time: {fake_now}") # 2023-01-01 00:00:00
211
print(f"Real time: {real_now}") # Actual current datetime
212
213
# Real UTC time
214
real_utc = time_machine.escape_hatch.datetime.datetime.utcnow()
215
print(f"Real UTC: {real_utc}")
216
217
# Real time with timezone
218
real_tz = time_machine.escape_hatch.datetime.datetime.now(timezone.utc)
219
print(f"Real UTC+TZ: {real_tz}")
220
```
221
222
### Common Use Cases
223
224
#### Performance Measurement
225
226
```python
227
import time_machine
228
229
def test_performance():
230
with time_machine.travel("2023-01-01"):
231
# Use real monotonic time for accurate performance measurement
232
start = time_machine.escape_hatch.time.monotonic()
233
234
# Operation being timed
235
slow_operation()
236
237
elapsed = time_machine.escape_hatch.time.monotonic() - start
238
assert elapsed < 1.0 # Should complete within 1 second
239
```
240
241
#### External API Testing
242
243
```python
244
import time_machine
245
import requests
246
247
def test_api_with_real_timestamps():
248
with time_machine.travel("2023-01-01"):
249
# API expects real timestamps in headers
250
real_timestamp = time_machine.escape_hatch.time.time()
251
252
response = requests.post("https://api.example.com/data",
253
headers={"X-Timestamp": str(real_timestamp)},
254
json={"created_at": time.time()}) # Uses fake time
255
256
assert response.status_code == 200
257
```
258
259
#### Logging with Real Timestamps
260
261
```python
262
import time_machine
263
import logging
264
265
def test_with_real_log_timestamps():
266
# Custom formatter using real time
267
class RealTimeFormatter(logging.Formatter):
268
def formatTime(self, record, datefmt=None):
269
real_time = time_machine.escape_hatch.time.time()
270
return super().formatTime(
271
type('Record', (), {'created': real_time})(), datefmt
272
)
273
274
with time_machine.travel("2023-01-01"):
275
logger = logging.getLogger("test")
276
handler = logging.StreamHandler()
277
handler.setFormatter(RealTimeFormatter())
278
logger.addHandler(handler)
279
280
logger.info("This log has real timestamp despite time travel")
281
```
282
283
#### Conditional Logic Based on Travel Status
284
285
```python
286
import time_machine
287
288
def get_current_time():
289
"""Get current time, using real time in production, fake time in tests."""
290
if time_machine.escape_hatch.is_travelling():
291
# In tests - use travel time
292
return datetime.now()
293
else:
294
# In production - use real time
295
return time_machine.escape_hatch.datetime.datetime.now()
296
297
def test_conditional_time():
298
# Outside travel - uses real time
299
real_time = get_current_time()
300
301
with time_machine.travel("2023-01-01"):
302
# Inside travel - uses fake time
303
fake_time = get_current_time()
304
assert fake_time.year == 2023
305
```
306
307
## Type Definitions
308
309
```python { .api }
310
from time import struct_time
311
from datetime import datetime as dt
312
313
_TimeTuple = tuple[int, int, int, int, int, int, int, int, int]
314
```