0
# Date Utilities
1
2
General convenience functions for common date and time operations including current day calculation, timezone defaulting, and date comparison within tolerance.
3
4
## Capabilities
5
6
### Today Function
7
8
```python { .api }
9
def today(tzinfo=None):
10
"""
11
Return current date at midnight with optional timezone.
12
13
Parameters:
14
- tzinfo (tzinfo, optional): Timezone to attach and use for current day determination
15
16
Returns:
17
datetime: Current date at midnight (00:00:00) in specified timezone
18
"""
19
```
20
21
**Usage Examples:**
22
23
```python
24
from dateutil.utils import today
25
from dateutil.tz import gettz
26
from datetime import datetime
27
28
# Current day at midnight in local timezone
29
today_local = today()
30
print(f"Today (local): {today_local}")
31
32
# Current day at midnight in specific timezone
33
utc_tz = gettz('UTC')
34
today_utc = today(utc_tz)
35
print(f"Today (UTC): {today_utc}")
36
37
# Compare with datetime.now()
38
now = datetime.now(utc_tz)
39
today_utc_alt = today(utc_tz)
40
print(f"Now: {now}")
41
print(f"Today: {today_utc_alt}") # Same date, but time is 00:00:00
42
```
43
44
### Timezone Defaulting
45
46
```python { .api }
47
def default_tzinfo(dt, tzinfo):
48
"""
49
Set timezone on naive datetimes only, leaving aware datetimes unchanged.
50
51
Useful when dealing with datetimes that may have implicit or explicit timezones,
52
such as when parsing timezone strings or working with mixed timezone data.
53
54
Parameters:
55
- dt (datetime): Datetime object to potentially modify
56
- tzinfo (tzinfo): Timezone to assign if dt is naive
57
58
Returns:
59
datetime: Aware datetime (either original if already aware, or with tzinfo applied)
60
"""
61
```
62
63
**Usage Examples:**
64
65
```python
66
from dateutil.utils import default_tzinfo
67
from dateutil.tz import gettz
68
from dateutil.parser import parse
69
from datetime import datetime
70
71
eastern_tz = gettz('America/New_York')
72
73
# Apply timezone to naive datetime
74
naive_dt = datetime(2023, 12, 25, 14, 30)
75
aware_dt = default_tzinfo(naive_dt, eastern_tz)
76
print(f"Naive -> Aware: {aware_dt}")
77
78
# Aware datetime remains unchanged
79
already_aware = datetime(2023, 12, 25, 14, 30, tzinfo=gettz('UTC'))
80
still_aware = default_tzinfo(already_aware, eastern_tz)
81
print(f"Still UTC: {still_aware}") # Keeps original UTC timezone
82
83
# Practical example with parsing
84
def parse_with_default_tz(date_str, default_tz):
85
"""Parse date string and apply default timezone if none specified."""
86
parsed_dt = parse(date_str)
87
return default_tzinfo(parsed_dt, default_tz)
88
89
# Apply default timezone only when needed
90
dt1 = parse_with_default_tz("2023-12-25 14:30", eastern_tz) # Gets Eastern
91
dt2 = parse_with_default_tz("2023-12-25 14:30 UTC", eastern_tz) # Stays UTC
92
```
93
94
### Date Comparison with Tolerance
95
96
```python { .api }
97
def within_delta(dt1, dt2, delta):
98
"""
99
Check if two datetimes are within a specified tolerance of each other.
100
101
Useful for comparing datetimes that may have negligible differences
102
due to precision, network delays, or processing time.
103
104
Parameters:
105
- dt1 (datetime): First datetime
106
- dt2 (datetime): Second datetime
107
- delta (timedelta): Maximum allowed difference (tolerance)
108
109
Returns:
110
bool: True if absolute difference between dt1 and dt2 is <= delta
111
"""
112
```
113
114
**Usage Examples:**
115
116
```python
117
from dateutil.utils import within_delta
118
from datetime import datetime, timedelta
119
120
# Basic tolerance checking
121
dt1 = datetime(2023, 12, 25, 14, 30, 0, 0) # Exactly 14:30:00.000
122
dt2 = datetime(2023, 12, 25, 14, 30, 0, 500000) # 14:30:00.500 (500ms later)
123
124
tolerance = timedelta(seconds=1)
125
are_close = within_delta(dt1, dt2, tolerance)
126
print(f"Within 1 second: {are_close}") # True
127
128
# More strict tolerance
129
strict_tolerance = timedelta(milliseconds=100)
130
are_very_close = within_delta(dt1, dt2, strict_tolerance)
131
print(f"Within 100ms: {are_very_close}") # False
132
133
# Practical application: Event synchronization
134
def events_are_simultaneous(event1_time, event2_time, tolerance_seconds=5):
135
"""Check if two events occurred within tolerance of each other."""
136
tolerance = timedelta(seconds=tolerance_seconds)
137
return within_delta(event1_time, event2_time, tolerance)
138
139
# Example usage
140
event_a = datetime(2023, 12, 25, 14, 30, 15)
141
event_b = datetime(2023, 12, 25, 14, 30, 18)
142
143
simultaneous = events_are_simultaneous(event_a, event_b)
144
print(f"Events are simultaneous: {simultaneous}") # True (within 5 seconds)
145
```
146
147
## Advanced Usage Patterns
148
149
### Timezone-Aware Today Calculation
150
151
```python
152
from dateutil.utils import today
153
from dateutil.tz import gettz
154
from datetime import datetime
155
156
def business_day_start(timezone_name):
157
"""Get start of business day in specified timezone."""
158
tz = gettz(timezone_name)
159
return today(tz).replace(hour=9) # 9 AM start
160
161
def is_same_business_day(dt1, dt2, timezone_name):
162
"""Check if two datetimes fall on same business day."""
163
tz = gettz(timezone_name)
164
165
# Convert both to same timezone and compare dates
166
dt1_local = dt1.astimezone(tz) if dt1.tzinfo else dt1.replace(tzinfo=tz)
167
dt2_local = dt2.astimezone(tz) if dt2.tzinfo else dt2.replace(tzinfo=tz)
168
169
return dt1_local.date() == dt2_local.date()
170
171
# Example usage
172
ny_start = business_day_start('America/New_York')
173
london_start = business_day_start('Europe/London')
174
print(f"NY business day starts: {ny_start}")
175
print(f"London business day starts: {london_start}")
176
```
177
178
### Robust DateTime Processing Pipeline
179
180
```python
181
from dateutil.utils import default_tzinfo, within_delta
182
from dateutil.tz import gettz
183
from dateutil.parser import parse
184
from datetime import datetime, timedelta
185
186
class DateTimeProcessor:
187
"""Robust datetime processing with defaults and validation."""
188
189
def __init__(self, default_timezone='UTC', tolerance_seconds=1):
190
self.default_tz = gettz(default_timezone)
191
self.tolerance = timedelta(seconds=tolerance_seconds)
192
193
def normalize_datetime(self, dt_input):
194
"""Convert various datetime inputs to standardized format."""
195
if isinstance(dt_input, str):
196
dt = parse(dt_input)
197
else:
198
dt = dt_input
199
200
# Apply default timezone if naive
201
return default_tzinfo(dt, self.default_tz)
202
203
def are_equivalent(self, dt1, dt2):
204
"""Check if two datetime inputs represent equivalent times."""
205
norm_dt1 = self.normalize_datetime(dt1)
206
norm_dt2 = self.normalize_datetime(dt2)
207
208
return within_delta(norm_dt1, norm_dt2, self.tolerance)
209
210
# Usage example
211
processor = DateTimeProcessor('America/New_York', tolerance_seconds=5)
212
213
# Various input formats
214
inputs = [
215
"2023-12-25 14:30:00",
216
datetime(2023, 12, 25, 19, 30, 3, tzinfo=gettz('UTC')), # Same time in UTC
217
"Dec 25, 2023 2:30:02 PM EST"
218
]
219
220
# Normalize all inputs
221
normalized = [processor.normalize_datetime(inp) for inp in inputs]
222
for i, norm_dt in enumerate(normalized):
223
print(f"Input {i+1}: {norm_dt}")
224
225
# Check equivalence
226
print(f"All equivalent: {all(processor.are_equivalent(normalized[0], dt) for dt in normalized[1:])}")
227
```
228
229
### Data Quality Validation
230
231
```python
232
from dateutil.utils import within_delta
233
from datetime import datetime, timedelta
234
235
def validate_timestamp_sequence(timestamps, max_gap_minutes=60):
236
"""
237
Validate that timestamps form a reasonable sequence.
238
239
Parameters:
240
- timestamps: List of datetime objects
241
- max_gap_minutes: Maximum allowed gap between consecutive timestamps
242
243
Returns:
244
dict: Validation results with issues found
245
"""
246
issues = {
247
'out_of_order': [],
248
'large_gaps': [],
249
'duplicates': []
250
}
251
252
max_gap = timedelta(minutes=max_gap_minutes)
253
duplicate_tolerance = timedelta(seconds=1)
254
255
for i in range(len(timestamps) - 1):
256
current = timestamps[i]
257
next_ts = timestamps[i + 1]
258
259
# Check ordering
260
if current > next_ts:
261
issues['out_of_order'].append((i, i+1))
262
263
# Check for large gaps
264
gap = next_ts - current
265
if gap > max_gap:
266
issues['large_gaps'].append((i, i+1, gap))
267
268
# Check for duplicates (within tolerance)
269
if within_delta(current, next_ts, duplicate_tolerance):
270
issues['duplicates'].append((i, i+1))
271
272
return issues
273
274
# Example usage
275
test_timestamps = [
276
datetime(2023, 12, 25, 10, 0),
277
datetime(2023, 12, 25, 10, 15),
278
datetime(2023, 12, 25, 10, 15, 1), # Near duplicate
279
datetime(2023, 12, 25, 12, 0), # Large gap
280
datetime(2023, 12, 25, 11, 30), # Out of order
281
]
282
283
validation_results = validate_timestamp_sequence(test_timestamps)
284
print("Validation results:", validation_results)
285
```
286
287
## Types
288
289
```python { .api }
290
from datetime import datetime, timedelta, tzinfo
291
292
# Function signatures
293
def today(tzinfo: tzinfo | None = None) -> datetime: ...
294
def default_tzinfo(dt: datetime, tzinfo: tzinfo) -> datetime: ...
295
def within_delta(dt1: datetime, dt2: datetime, delta: timedelta) -> bool: ...
296
297
# Parameter types
298
DateTimeInput = datetime | str # For functions that accept multiple datetime formats
299
TimezoneInput = tzinfo | str | None # Timezone specifications
300
ToleranceInput = timedelta # Time tolerance specifications
301
```