6
6
from datetime import datetime
7
7
from datetime import timedelta
8
8
from typing import TYPE_CHECKING
9
+ from typing import Generic
9
10
from typing import Iterator
10
- from typing import Union
11
+ from typing import TypeVar
11
12
from typing import cast
12
13
from typing import overload
13
14
26
27
from pendulum .locales .locale import Locale
27
28
28
29
29
- class Interval (Duration ):
30
+ _T = TypeVar ("_T" , bound = date )
31
+
32
+
33
+ class Interval (Duration , Generic [_T ]):
30
34
"""
31
35
An interval of time between two datetimes.
32
36
"""
33
37
34
- @overload
35
- def __new__ (
36
- cls ,
37
- start : pendulum .DateTime | datetime ,
38
- end : pendulum .DateTime | datetime ,
39
- absolute : bool = False ,
40
- ) -> Self :
41
- ...
42
-
43
- @overload
44
- def __new__ (
45
- cls ,
46
- start : pendulum .Date | date ,
47
- end : pendulum .Date | date ,
48
- absolute : bool = False ,
49
- ) -> Self :
50
- ...
51
-
52
- def __new__ (
53
- cls ,
54
- start : pendulum .DateTime | pendulum .Date | datetime | date ,
55
- end : pendulum .DateTime | pendulum .Date | datetime | date ,
56
- absolute : bool = False ,
57
- ) -> Self :
38
+ def __new__ (cls , start : _T , end : _T , absolute : bool = False ) -> Self :
58
39
if (
59
40
isinstance (start , datetime )
60
41
and not isinstance (end , datetime )
@@ -83,34 +64,40 @@ def __new__(
83
64
_start = start
84
65
_end = end
85
66
if isinstance (start , pendulum .DateTime ):
86
- _start = datetime (
87
- start .year ,
88
- start .month ,
89
- start .day ,
90
- start .hour ,
91
- start .minute ,
92
- start .second ,
93
- start .microsecond ,
94
- tzinfo = start .tzinfo ,
95
- fold = start .fold ,
67
+ _start = cast (
68
+ _T ,
69
+ datetime (
70
+ start .year ,
71
+ start .month ,
72
+ start .day ,
73
+ start .hour ,
74
+ start .minute ,
75
+ start .second ,
76
+ start .microsecond ,
77
+ tzinfo = start .tzinfo ,
78
+ fold = start .fold ,
79
+ ),
96
80
)
97
81
elif isinstance (start , pendulum .Date ):
98
- _start = date (start .year , start .month , start .day )
82
+ _start = cast ( _T , date (start .year , start .month , start .day ) )
99
83
100
84
if isinstance (end , pendulum .DateTime ):
101
- _end = datetime (
102
- end .year ,
103
- end .month ,
104
- end .day ,
105
- end .hour ,
106
- end .minute ,
107
- end .second ,
108
- end .microsecond ,
109
- tzinfo = end .tzinfo ,
110
- fold = end .fold ,
85
+ _end = cast (
86
+ _T ,
87
+ datetime (
88
+ end .year ,
89
+ end .month ,
90
+ end .day ,
91
+ end .hour ,
92
+ end .minute ,
93
+ end .second ,
94
+ end .microsecond ,
95
+ tzinfo = end .tzinfo ,
96
+ fold = end .fold ,
97
+ ),
111
98
)
112
99
elif isinstance (end , pendulum .Date ):
113
- _end = date (end .year , end .month , end .day )
100
+ _end = cast ( _T , date (end .year , end .month , end .day ) )
114
101
115
102
# Fixing issues with datetime.__sub__()
116
103
# not handling offsets if the tzinfo is the same
@@ -121,69 +108,70 @@ def __new__(
121
108
):
122
109
if _start .tzinfo is not None :
123
110
offset = cast (timedelta , cast (datetime , start ).utcoffset ())
124
- _start = ( _start - offset ).replace (tzinfo = None )
111
+ _start = cast ( _T , ( _start - offset ).replace (tzinfo = None ) )
125
112
126
113
if isinstance (end , datetime ) and _end .tzinfo is not None :
127
114
offset = cast (timedelta , end .utcoffset ())
128
- _end = ( _end - offset ).replace (tzinfo = None )
115
+ _end = cast ( _T , ( _end - offset ).replace (tzinfo = None ) )
129
116
130
- delta : timedelta = _end - _start # type: ignore[operator]
117
+ delta : timedelta = _end - _start
131
118
132
119
return super ().__new__ (cls , seconds = delta .total_seconds ())
133
120
134
- def __init__ (
135
- self ,
136
- start : pendulum .DateTime | pendulum .Date | datetime | date ,
137
- end : pendulum .DateTime | pendulum .Date | datetime | date ,
138
- absolute : bool = False ,
139
- ) -> None :
121
+ def __init__ (self , start : _T , end : _T , absolute : bool = False ) -> None :
140
122
super ().__init__ ()
141
123
142
- _start : pendulum . DateTime | pendulum . Date | datetime | date
124
+ _start : _T
143
125
if not isinstance (start , pendulum .Date ):
144
126
if isinstance (start , datetime ):
145
- start = pendulum .instance (start )
127
+ start = cast ( _T , pendulum .instance (start ) )
146
128
else :
147
- start = pendulum .date (start .year , start .month , start .day )
129
+ start = cast ( _T , pendulum .date (start .year , start .month , start .day ) )
148
130
149
131
_start = start
150
132
else :
151
133
if isinstance (start , pendulum .DateTime ):
152
- _start = datetime (
153
- start .year ,
154
- start .month ,
155
- start .day ,
156
- start .hour ,
157
- start .minute ,
158
- start .second ,
159
- start .microsecond ,
160
- tzinfo = start .tzinfo ,
134
+ _start = cast (
135
+ _T ,
136
+ datetime (
137
+ start .year ,
138
+ start .month ,
139
+ start .day ,
140
+ start .hour ,
141
+ start .minute ,
142
+ start .second ,
143
+ start .microsecond ,
144
+ tzinfo = start .tzinfo ,
145
+ ),
161
146
)
162
147
else :
163
- _start = date (start .year , start .month , start .day )
148
+ _start = cast ( _T , date (start .year , start .month , start .day ) )
164
149
165
- _end : pendulum . DateTime | pendulum . Date | datetime | date
150
+ _end : _T
166
151
if not isinstance (end , pendulum .Date ):
167
152
if isinstance (end , datetime ):
168
- end = pendulum .instance (end )
153
+ end = cast ( _T , pendulum .instance (end ) )
169
154
else :
170
- end = pendulum .date (end .year , end .month , end .day )
155
+ end = cast ( _T , pendulum .date (end .year , end .month , end .day ) )
171
156
172
157
_end = end
173
158
else :
174
159
if isinstance (end , pendulum .DateTime ):
175
- _end = datetime (
176
- end .year ,
177
- end .month ,
178
- end .day ,
179
- end .hour ,
180
- end .minute ,
181
- end .second ,
182
- end .microsecond ,
183
- tzinfo = end .tzinfo ,
160
+ _end = cast (
161
+ _T ,
162
+ datetime (
163
+ end .year ,
164
+ end .month ,
165
+ end .day ,
166
+ end .hour ,
167
+ end .minute ,
168
+ end .second ,
169
+ end .microsecond ,
170
+ tzinfo = end .tzinfo ,
171
+ ),
184
172
)
185
173
else :
186
- _end = date (end .year , end .month , end .day )
174
+ _end = cast ( _T , date (end .year , end .month , end .day ) )
187
175
188
176
self ._invert = False
189
177
if start > end :
@@ -194,8 +182,8 @@ def __init__(
194
182
_end , _start = _start , _end
195
183
196
184
self ._absolute = absolute
197
- self ._start : pendulum . DateTime | pendulum . Date = start
198
- self ._end : pendulum . DateTime | pendulum . Date = end
185
+ self ._start : _T = start
186
+ self ._end : _T = end
199
187
self ._delta : PreciseDiff = precise_diff (_start , _end )
200
188
201
189
@property
@@ -227,11 +215,11 @@ def minutes(self) -> int:
227
215
return self ._delta .minutes
228
216
229
217
@property
230
- def start (self ) -> pendulum . DateTime | pendulum . Date | datetime | date :
218
+ def start (self ) -> _T :
231
219
return self ._start
232
220
233
221
@property
234
- def end (self ) -> pendulum . DateTime | pendulum . Date | datetime | date :
222
+ def end (self ) -> _T :
235
223
return self ._end
236
224
237
225
def in_years (self ) -> int :
@@ -301,9 +289,7 @@ def in_words(self, locale: str | None = None, separator: str = " ") -> str:
301
289
302
290
return separator .join (parts )
303
291
304
- def range (
305
- self , unit : str , amount : int = 1
306
- ) -> Iterator [pendulum .DateTime | pendulum .Date ]:
292
+ def range (self , unit : str , amount : int = 1 ) -> Iterator [_T ]:
307
293
method = "add"
308
294
op = operator .le
309
295
if not self ._absolute and self .invert :
@@ -314,7 +300,7 @@ def range(
314
300
315
301
i = amount
316
302
while op (start , end ):
317
- yield cast ( Union [ pendulum . DateTime , pendulum . Date ], start )
303
+ yield start
318
304
319
305
start = getattr (self .start , method )(** {unit : i })
320
306
@@ -326,12 +312,10 @@ def as_duration(self) -> Duration:
326
312
"""
327
313
return Duration (seconds = self .total_seconds ())
328
314
329
- def __iter__ (self ) -> Iterator [pendulum . DateTime | pendulum . Date ]:
315
+ def __iter__ (self ) -> Iterator [_T ]:
330
316
return self .range ("days" )
331
317
332
- def __contains__ (
333
- self , item : datetime | date | pendulum .DateTime | pendulum .Date
334
- ) -> bool :
318
+ def __contains__ (self , item : _T ) -> bool :
335
319
return self .start <= item <= self .end
336
320
337
321
def __add__ (self , other : timedelta ) -> Duration : # type: ignore[override]
@@ -400,13 +384,7 @@ def _cmp(self, other: timedelta) -> int:
400
384
401
385
return 0 if td == other else 1 if td > other else - 1
402
386
403
- def _getstate (
404
- self , protocol : SupportsIndex = 3
405
- ) -> tuple [
406
- pendulum .DateTime | pendulum .Date | datetime | date ,
407
- pendulum .DateTime | pendulum .Date | datetime | date ,
408
- bool ,
409
- ]:
387
+ def _getstate (self , protocol : SupportsIndex = 3 ) -> tuple [_T , _T , bool ]:
410
388
start , end = self .start , self .end
411
389
412
390
if self ._invert and self ._absolute :
@@ -416,26 +394,12 @@ def _getstate(
416
394
417
395
def __reduce__ (
418
396
self ,
419
- ) -> tuple [
420
- type [Self ],
421
- tuple [
422
- pendulum .DateTime | pendulum .Date | datetime | date ,
423
- pendulum .DateTime | pendulum .Date | datetime | date ,
424
- bool ,
425
- ],
426
- ]:
397
+ ) -> tuple [type [Self ], tuple [_T , _T , bool ]]:
427
398
return self .__reduce_ex__ (2 )
428
399
429
400
def __reduce_ex__ (
430
401
self , protocol : SupportsIndex
431
- ) -> tuple [
432
- type [Self ],
433
- tuple [
434
- pendulum .DateTime | pendulum .Date | datetime | date ,
435
- pendulum .DateTime | pendulum .Date | datetime | date ,
436
- bool ,
437
- ],
438
- ]:
402
+ ) -> tuple [type [Self ], tuple [_T , _T , bool ]]:
439
403
return self .__class__ , self ._getstate (protocol )
440
404
441
405
def __hash__ (self ) -> int :
0 commit comments