dateutilx 0.2.0__tar.gz → 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {dateutilx-0.2.0 → dateutilx-0.3.0}/.gitignore +0 -3
- {dateutilx-0.2.0 → dateutilx-0.3.0}/PKG-INFO +1 -1
- {dateutilx-0.2.0/src → dateutilx-0.3.0/dateutilx}/__init__.py +1 -1
- {dateutilx-0.2.0/src → dateutilx-0.3.0/dateutilx}/parser/_parser.py +12 -12
- {dateutilx-0.2.0/src → dateutilx-0.3.0/dateutilx}/parser/isoparser.py +7 -7
- {dateutilx-0.2.0/src → dateutilx-0.3.0/dateutilx}/relativedelta.py +51 -34
- {dateutilx-0.2.0/src → dateutilx-0.3.0/dateutilx}/rrule.py +10 -11
- {dateutilx-0.2.0/src → dateutilx-0.3.0/dateutilx}/tz/__init__.py +5 -14
- dateutilx-0.3.0/dateutilx/tz/_factories.py +61 -0
- {dateutilx-0.2.0/src → dateutilx-0.3.0/dateutilx}/tz/_win.py +5 -5
- {dateutilx-0.2.0/src → dateutilx-0.3.0/dateutilx}/tz/tz.py +20 -24
- {dateutilx-0.2.0/src → dateutilx-0.3.0/dateutilx}/tz/win.py +2 -5
- dateutilx-0.3.0/dateutilx/utils/__init__.py +10 -0
- dateutilx-0.2.0/src/utils.py → dateutilx-0.3.0/dateutilx/utils/funcs.py +7 -9
- {dateutilx-0.2.0/src → dateutilx-0.3.0/dateutilx/utils}/weekday.py +6 -7
- {dateutilx-0.2.0 → dateutilx-0.3.0}/pyproject.toml +3 -3
- dateutilx-0.2.0/src/helper/__init__.py +0 -4
- dateutilx-0.2.0/src/helper/funcs.py +0 -5
- dateutilx-0.2.0/src/tz/_factories.py +0 -67
- dateutilx-0.2.0/src/tzwin.py +0 -4
- {dateutilx-0.2.0 → dateutilx-0.3.0}/.base_project/LICENSE +0 -0
- {dateutilx-0.2.0 → dateutilx-0.3.0}/LICENSE +0 -0
- {dateutilx-0.2.0 → dateutilx-0.3.0}/README.md +0 -0
- {dateutilx-0.2.0/src → dateutilx-0.3.0/dateutilx}/easter.py +0 -0
- {dateutilx-0.2.0/src → dateutilx-0.3.0/dateutilx}/errors.py +0 -0
- {dateutilx-0.2.0/src → dateutilx-0.3.0/dateutilx}/info.py +0 -0
- {dateutilx-0.2.0/src → dateutilx-0.3.0/dateutilx}/parser/__init__.py +0 -0
- {dateutilx-0.2.0/src → dateutilx-0.3.0/dateutilx}/parser/utils.py +0 -0
- {dateutilx-0.2.0/src → dateutilx-0.3.0/dateutilx}/tz/_common.py +0 -0
- {dateutilx-0.2.0/src/helper → dateutilx-0.3.0/dateutilx/utils}/constants.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dateutilx
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Modern extension to the standard Python datetime module
|
|
5
5
|
Project-URL: Homepage, https://github.com/rsb-23/dateutilx
|
|
6
6
|
Project-URL: Documentation, https://dateutilx.readthedocs.io/en/stable/
|
|
@@ -13,7 +13,7 @@ def __getattr__(name):
|
|
|
13
13
|
|
|
14
14
|
if name in __all__:
|
|
15
15
|
return importlib.import_module(f".{name}", __name__)
|
|
16
|
-
raise AttributeError(f"module {__name__!r} has
|
|
16
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
def __dir__():
|
|
@@ -39,8 +39,8 @@ from decimal import Decimal
|
|
|
39
39
|
from io import StringIO
|
|
40
40
|
from warnings import warn
|
|
41
41
|
|
|
42
|
-
from
|
|
43
|
-
from
|
|
42
|
+
from dateutilx import relativedelta, tz
|
|
43
|
+
from dateutilx.errors import ParserError, UnknownTimezoneWarning
|
|
44
44
|
|
|
45
45
|
from .utils import standard_dt_parser
|
|
46
46
|
|
|
@@ -562,8 +562,8 @@ class Parser:
|
|
|
562
562
|
.. doctest::
|
|
563
563
|
:options: +NORMALIZE_WHITESPACE
|
|
564
564
|
|
|
565
|
-
>>> from
|
|
566
|
-
>>> from
|
|
565
|
+
>>> from dateutilx.parser import parse
|
|
566
|
+
>>> from dateutilx.tz import gettz
|
|
567
567
|
>>> tzinfos = {"BRST": -7200, "CST": gettz("America/Chicago")}
|
|
568
568
|
>>> parse("2012-01-19 17:21:00 BRST", tzinfos=tzinfos)
|
|
569
569
|
datetime.datetime(2012, 1, 19, 17, 21, tzinfo=tzoffset(u'BRST', -7200))
|
|
@@ -667,7 +667,7 @@ class Parser:
|
|
|
667
667
|
|
|
668
668
|
.. doctest::
|
|
669
669
|
|
|
670
|
-
>>> from
|
|
670
|
+
>>> from dateutilx.parser import parse
|
|
671
671
|
>>> parse("Today is January 1, 2047 at 8:21:00AM", fuzzy_with_tokens=True)
|
|
672
672
|
(datetime.datetime(2047, 1, 1, 8, 21), (u'Today is ', u' ', u'at '))
|
|
673
673
|
|
|
@@ -1132,9 +1132,9 @@ class Parser:
|
|
|
1132
1132
|
if isinstance(tzdata, datetime.tzinfo) or tzdata is None:
|
|
1133
1133
|
tzinfo = tzdata
|
|
1134
1134
|
elif isinstance(tzdata, str):
|
|
1135
|
-
tzinfo = tz.
|
|
1135
|
+
tzinfo = tz.TzStr(tzdata)
|
|
1136
1136
|
elif isinstance(tzdata, int):
|
|
1137
|
-
tzinfo = tz.
|
|
1137
|
+
tzinfo = tz.TzOffset(tzname, tzdata)
|
|
1138
1138
|
else:
|
|
1139
1139
|
raise TypeError("Offset must be tzinfo subclass, tz string, or int offset.")
|
|
1140
1140
|
return tzinfo
|
|
@@ -1146,7 +1146,7 @@ class Parser:
|
|
|
1146
1146
|
aware = self._assign_tzname(aware, res.tzname)
|
|
1147
1147
|
|
|
1148
1148
|
elif res.tzname and res.tzname in time.tzname:
|
|
1149
|
-
aware = naive.replace(tzinfo=tz.
|
|
1149
|
+
aware = naive.replace(tzinfo=tz.TzLocal())
|
|
1150
1150
|
|
|
1151
1151
|
# Handle ambiguous local datetime
|
|
1152
1152
|
aware = self._assign_tzname(aware, res.tzname)
|
|
@@ -1159,7 +1159,7 @@ class Parser:
|
|
|
1159
1159
|
aware = naive.replace(tzinfo=tz.UTC)
|
|
1160
1160
|
|
|
1161
1161
|
elif res.tzoffset:
|
|
1162
|
-
aware = naive.replace(tzinfo=tz.
|
|
1162
|
+
aware = naive.replace(tzinfo=tz.TzOffset(res.tzname, res.tzoffset))
|
|
1163
1163
|
|
|
1164
1164
|
elif not res.tzname:
|
|
1165
1165
|
# i.e. no timezone information was found.
|
|
@@ -1268,8 +1268,8 @@ def parse(timestr, parser_info=None, **kwargs):
|
|
|
1268
1268
|
.. doctest::
|
|
1269
1269
|
:options: +NORMALIZE_WHITESPACE
|
|
1270
1270
|
|
|
1271
|
-
>>> from
|
|
1272
|
-
>>> from
|
|
1271
|
+
>>> from dateutilx.parser import parse
|
|
1272
|
+
>>> from dateutilx.tz import gettz
|
|
1273
1273
|
>>> tzinfos = {"BRST": -7200, "CST": gettz("America/Chicago")}
|
|
1274
1274
|
>>> parse("2012-01-19 17:21:00 BRST", tzinfos=tzinfos)
|
|
1275
1275
|
datetime.datetime(2012, 1, 19, 17, 21, tzinfo=tzoffset(u'BRST', -7200))
|
|
@@ -1305,7 +1305,7 @@ def parse(timestr, parser_info=None, **kwargs):
|
|
|
1305
1305
|
|
|
1306
1306
|
.. doctest::
|
|
1307
1307
|
|
|
1308
|
-
>>> from
|
|
1308
|
+
>>> from dateutilx.parser import parse
|
|
1309
1309
|
>>> parse("Today is January 1, 2047 at 8:21:00AM", fuzzy_with_tokens=True)
|
|
1310
1310
|
(datetime.datetime(2047, 1, 1, 8, 21), (u'Today is ', u' ', u'at '))
|
|
1311
1311
|
|
|
@@ -12,7 +12,7 @@ import datetime as dt
|
|
|
12
12
|
import re
|
|
13
13
|
from functools import wraps
|
|
14
14
|
|
|
15
|
-
from
|
|
15
|
+
from dateutilx.tz import UTC, TzOffset
|
|
16
16
|
|
|
17
17
|
__all__ = ["isoparse", "isoparser"]
|
|
18
18
|
|
|
@@ -107,10 +107,10 @@ class IsoParser:
|
|
|
107
107
|
- `±HHMM`
|
|
108
108
|
- `±HH`
|
|
109
109
|
|
|
110
|
-
Offsets will be represented as :class:`dateutilx.tz.
|
|
110
|
+
Offsets will be represented as :class:`dateutilx.tz.TzOffset` objects,
|
|
111
111
|
with the exception of UTC, which will be represented as
|
|
112
|
-
:class:`dateutilx.tz.
|
|
113
|
-
as `+00:00`) will also be represented as :class:`dateutilx.tz.
|
|
112
|
+
:class:`dateutilx.tz.TzUTC`. Time zone offsets equivalent to UTC (such
|
|
113
|
+
as `+00:00`) will also be represented as :class:`dateutilx.tz.TzUTC`.
|
|
114
114
|
|
|
115
115
|
:param dt_str:
|
|
116
116
|
A string or stream containing only an ISO-8601 datetime string
|
|
@@ -188,11 +188,11 @@ class IsoParser:
|
|
|
188
188
|
A string representing an ISO time zone offset
|
|
189
189
|
|
|
190
190
|
:param zero_as_utc:
|
|
191
|
-
Whether to return :class:`dateutilx.tz.
|
|
191
|
+
Whether to return :class:`dateutilx.tz.TzUTC` for zero-offset zones
|
|
192
192
|
|
|
193
193
|
:return:
|
|
194
|
-
Returns :class:`dateutilx.tz.
|
|
195
|
-
:class:`dateutilx.tz.
|
|
194
|
+
Returns :class:`dateutilx.tz.TzOffset` for offsets and
|
|
195
|
+
:class:`dateutilx.tz.TzUTC` for ``Z`` and (if ``zero_as_utc`` is
|
|
196
196
|
specified) offsets equivalent to UTC.
|
|
197
197
|
"""
|
|
198
198
|
return self._parse_tzstr(tzstr, zero_as_utc=zero_as_utc)
|
|
@@ -3,18 +3,13 @@ import datetime as dt
|
|
|
3
3
|
import operator
|
|
4
4
|
from math import copysign
|
|
5
5
|
from types import NotImplementedType
|
|
6
|
-
from typing import Self
|
|
6
|
+
from typing import Self
|
|
7
7
|
from warnings import warn
|
|
8
8
|
|
|
9
|
-
from
|
|
9
|
+
from dateutilx.utils import Weekday, weekdays
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
__all__ = ["RelativeDelta", "MO", "TU", "WE", "TH", "FR", "SA", "SU"]
|
|
14
|
-
Number: TypeAlias = float | int
|
|
15
|
-
|
|
16
|
-
REL_FIELDS = "years", "months", "days", "hours", "minutes", "seconds", "microseconds"
|
|
17
|
-
ABS_FIELDS = "year", "month", "day", "hour", "minute", "second", "microsecond"
|
|
11
|
+
__all__ = ["RelativeDelta"]
|
|
12
|
+
Number = float | int
|
|
18
13
|
|
|
19
14
|
|
|
20
15
|
class RelativeDelta:
|
|
@@ -91,7 +86,7 @@ class RelativeDelta:
|
|
|
91
86
|
For example
|
|
92
87
|
|
|
93
88
|
>>> from datetime import datetime
|
|
94
|
-
>>> from
|
|
89
|
+
>>> from dateutilx.relativedelta import RelativeDelta, MO
|
|
95
90
|
>>> dt_ = datetime(2018, 4, 9, 13, 37, 0)
|
|
96
91
|
>>> delta = RelativeDelta(hours=25, day=1, weekday=MO(1))
|
|
97
92
|
>>> dt_ + delta
|
|
@@ -177,7 +172,7 @@ class RelativeDelta:
|
|
|
177
172
|
|
|
178
173
|
# Remove the year/month delta so the timedelta is just well-defined
|
|
179
174
|
# time units (seconds, days and microseconds)
|
|
180
|
-
dtm = self
|
|
175
|
+
dtm = self.__radd__(dt2)
|
|
181
176
|
|
|
182
177
|
# If we've overshot our target, make an adjustment
|
|
183
178
|
if dt1 < dt2:
|
|
@@ -190,7 +185,7 @@ class RelativeDelta:
|
|
|
190
185
|
while compare(dt1, dtm):
|
|
191
186
|
months += increment
|
|
192
187
|
self._set_months(months)
|
|
193
|
-
dtm = self
|
|
188
|
+
dtm = self.__radd__(dt2)
|
|
194
189
|
|
|
195
190
|
# Get the timedelta between the "months-adjusted" date and dt1
|
|
196
191
|
delta = dt1 - dtm
|
|
@@ -227,15 +222,37 @@ class RelativeDelta:
|
|
|
227
222
|
resolved = dt.date(2001, 1, 1) + dt.timedelta(days=yday - 1)
|
|
228
223
|
self.day, self.month = resolved.day, resolved.month
|
|
229
224
|
|
|
225
|
+
def _absolutes(self) -> dict[str, Number]:
|
|
226
|
+
return {
|
|
227
|
+
"year": self.year,
|
|
228
|
+
"month": self.month,
|
|
229
|
+
"day": self.day,
|
|
230
|
+
"hour": self.hour,
|
|
231
|
+
"minute": self.minute,
|
|
232
|
+
"second": self.second,
|
|
233
|
+
"microsecond": self.microsecond,
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
def _relatives(self) -> dict[str, Number]:
|
|
237
|
+
return {
|
|
238
|
+
"years": self.years,
|
|
239
|
+
"months": self.months,
|
|
240
|
+
"days": self.days,
|
|
241
|
+
"hours": self.hours,
|
|
242
|
+
"minutes": self.minutes,
|
|
243
|
+
"seconds": self.seconds,
|
|
244
|
+
"microseconds": self.microseconds,
|
|
245
|
+
}
|
|
246
|
+
|
|
230
247
|
def _reset(self):
|
|
231
248
|
self.leapdays = 0
|
|
232
249
|
self.weekday = None
|
|
233
250
|
self._has_time = 0
|
|
234
251
|
|
|
235
|
-
for attr in
|
|
252
|
+
for attr in ("years", "months", "days", "hours", "minutes", "seconds", "microseconds"):
|
|
236
253
|
setattr(self, attr, 0)
|
|
237
254
|
|
|
238
|
-
for attr in
|
|
255
|
+
for attr in ("year", "month", "day", "hour", "minute", "second", "microsecond"):
|
|
239
256
|
setattr(self, attr, None)
|
|
240
257
|
|
|
241
258
|
def _fix(self):
|
|
@@ -295,8 +312,8 @@ class RelativeDelta:
|
|
|
295
312
|
|
|
296
313
|
def _make_relativedelta(self, **kwargs) -> Self:
|
|
297
314
|
"""Factory method to create a new RelativeDelta with given overrides."""
|
|
298
|
-
rel_fields = {field: kwargs.get(field,
|
|
299
|
-
abs_fields = {field: kwargs.get(field,
|
|
315
|
+
rel_fields = {field: kwargs.get(field, val) for field, val in self._relatives().items()}
|
|
316
|
+
abs_fields = {field: kwargs.get(field, val) for field, val in self._absolutes().items()}
|
|
300
317
|
return self.__class__(
|
|
301
318
|
**rel_fields,
|
|
302
319
|
**abs_fields,
|
|
@@ -337,8 +354,8 @@ class RelativeDelta:
|
|
|
337
354
|
def __add__(self, other):
|
|
338
355
|
if isinstance(other, RelativeDelta):
|
|
339
356
|
kwargs = {
|
|
340
|
-
field:
|
|
341
|
-
for field in
|
|
357
|
+
field: val if getattr(other, field) is None else getattr(other, field)
|
|
358
|
+
for field, val in self._absolutes().items()
|
|
342
359
|
}
|
|
343
360
|
return self._make_relativedelta(
|
|
344
361
|
years=other.years + self.years,
|
|
@@ -407,10 +424,7 @@ class RelativeDelta:
|
|
|
407
424
|
if not isinstance(other, RelativeDelta):
|
|
408
425
|
return NotImplemented # In case the other object defines __rsub__
|
|
409
426
|
|
|
410
|
-
kwargs = {
|
|
411
|
-
field: getattr(other, field) if getattr(self, field) is None else getattr(self, field)
|
|
412
|
-
for field in ABS_FIELDS
|
|
413
|
-
}
|
|
427
|
+
kwargs = {field: getattr(other, field) if val is None else val for field, val in self._absolutes().items()}
|
|
414
428
|
return self._make_relativedelta(
|
|
415
429
|
years=self.years - other.years,
|
|
416
430
|
months=self.months - other.months,
|
|
@@ -424,25 +438,28 @@ class RelativeDelta:
|
|
|
424
438
|
)
|
|
425
439
|
|
|
426
440
|
def __abs__(self):
|
|
427
|
-
fields = {field: abs(
|
|
441
|
+
fields = {field: abs(val) for field, val in self._relatives().items()}
|
|
428
442
|
return self._make_relativedelta(**fields)
|
|
429
443
|
|
|
430
444
|
def __neg__(self):
|
|
431
|
-
fields = {field: -
|
|
445
|
+
fields = {field: -val for field, val in self._relatives().items()}
|
|
432
446
|
return self._make_relativedelta(**fields)
|
|
433
447
|
|
|
434
|
-
def __bool__(self):
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
448
|
+
def __bool__(self) -> bool:
|
|
449
|
+
return (
|
|
450
|
+
any(value for value in self._relatives().values())
|
|
451
|
+
or bool(self.leapdays)
|
|
452
|
+
or bool(self.weekday)
|
|
453
|
+
or any(value is not None for value in self._absolutes().values())
|
|
454
|
+
)
|
|
438
455
|
|
|
439
|
-
def __mul__(self, other) ->
|
|
456
|
+
def __mul__(self, other) -> Self | NotImplementedType:
|
|
440
457
|
try:
|
|
441
458
|
f = float(other)
|
|
442
459
|
except TypeError:
|
|
443
460
|
return NotImplemented
|
|
444
461
|
|
|
445
|
-
fields = {field: int(
|
|
462
|
+
fields = {field: int(val * f) for field, val in self._relatives().items()}
|
|
446
463
|
return self._make_relativedelta(**fields)
|
|
447
464
|
|
|
448
465
|
__rmul__ = __mul__
|
|
@@ -463,8 +480,10 @@ class RelativeDelta:
|
|
|
463
480
|
return False
|
|
464
481
|
|
|
465
482
|
return (
|
|
466
|
-
all((
|
|
483
|
+
all((a == b for a, b in zip(self._relatives().values(), other._relatives().values())))
|
|
484
|
+
and all((a == b for a, b in zip(self._absolutes().values(), other._absolutes().values())))
|
|
467
485
|
and self.leapdays == other.leapdays
|
|
486
|
+
and self.weekday == other.weekday
|
|
468
487
|
)
|
|
469
488
|
|
|
470
489
|
def __hash__(self):
|
|
@@ -483,7 +502,7 @@ class RelativeDelta:
|
|
|
483
502
|
return NotImplemented
|
|
484
503
|
return not self.__eq__(other)
|
|
485
504
|
|
|
486
|
-
def
|
|
505
|
+
def __truediv__(self, other) -> NotImplementedType | Self:
|
|
487
506
|
try:
|
|
488
507
|
reciprocal = 1 / float(other)
|
|
489
508
|
except TypeError:
|
|
@@ -491,8 +510,6 @@ class RelativeDelta:
|
|
|
491
510
|
|
|
492
511
|
return self.__mul__(reciprocal)
|
|
493
512
|
|
|
494
|
-
__truediv__ = __div__
|
|
495
|
-
|
|
496
513
|
def __repr__(self):
|
|
497
514
|
_tmp_list = []
|
|
498
515
|
for attr in ["years", "months", "days", "leapdays", "hours", "minutes", "seconds", "microseconds"]:
|
|
@@ -6,7 +6,6 @@ the recurrence rules documented in the
|
|
|
6
6
|
including support for caching of results.
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
|
-
import _thread
|
|
10
9
|
import calendar
|
|
11
10
|
import contextlib
|
|
12
11
|
import datetime as dt
|
|
@@ -15,14 +14,14 @@ import itertools
|
|
|
15
14
|
import operator
|
|
16
15
|
import re
|
|
17
16
|
import sys
|
|
17
|
+
import threading
|
|
18
18
|
from functools import wraps
|
|
19
19
|
from itertools import product
|
|
20
20
|
from math import gcd
|
|
21
21
|
from typing import Any
|
|
22
22
|
from warnings import warn
|
|
23
23
|
|
|
24
|
-
from .
|
|
25
|
-
from .weekday import Weekday, weekdays
|
|
24
|
+
from dateutilx.utils import Day, Frequency, Weekday, weekdays
|
|
26
25
|
|
|
27
26
|
# fmt: off
|
|
28
27
|
__all__ = [
|
|
@@ -79,7 +78,7 @@ class RruleBase:
|
|
|
79
78
|
def __init__(self, cache=False):
|
|
80
79
|
if cache:
|
|
81
80
|
self._cache = []
|
|
82
|
-
self._cache_lock =
|
|
81
|
+
self._cache_lock = threading.Lock()
|
|
83
82
|
self._invalidate_cache()
|
|
84
83
|
else:
|
|
85
84
|
self._cache = None
|
|
@@ -270,7 +269,7 @@ class Rrule(RruleBase):
|
|
|
270
269
|
This can lead to possibly surprising behavior when, for example, the
|
|
271
270
|
start date occurs at the end of the month:
|
|
272
271
|
|
|
273
|
-
>>> from
|
|
272
|
+
>>> from dateutilx.rrule import rrule, MONTHLY
|
|
274
273
|
>>> from datetime import datetime
|
|
275
274
|
>>> start_date = datetime(2014, 12, 31)
|
|
276
275
|
>>> list(rrule(freq=MONTHLY, count=4, dtstart=start_date))
|
|
@@ -498,7 +497,7 @@ class Rrule(RruleBase):
|
|
|
498
497
|
self._byeaster = None
|
|
499
498
|
if byeaster is not None:
|
|
500
499
|
if not easter:
|
|
501
|
-
from
|
|
500
|
+
from dateutilx import easter
|
|
502
501
|
if isinstance(byeaster, int):
|
|
503
502
|
self._byeaster = (byeaster,)
|
|
504
503
|
else:
|
|
@@ -1001,7 +1000,7 @@ class Rrule(RruleBase):
|
|
|
1001
1000
|
|
|
1002
1001
|
return cset
|
|
1003
1002
|
|
|
1004
|
-
def __mod_distance(self, value, byxxx, base):
|
|
1003
|
+
def __mod_distance(self, value, byxxx, base) -> tuple[int, int]:
|
|
1005
1004
|
"""
|
|
1006
1005
|
Calculates the next value in a sequence where the `FREQ` parameter is
|
|
1007
1006
|
specified along with a `BYXXX` parameter at the same "level"
|
|
@@ -1032,7 +1031,7 @@ class Rrule(RruleBase):
|
|
|
1032
1031
|
accumulator += div
|
|
1033
1032
|
if value in byxxx:
|
|
1034
1033
|
return accumulator, value
|
|
1035
|
-
|
|
1034
|
+
raise ValueError("No valid values found")
|
|
1036
1035
|
|
|
1037
1036
|
|
|
1038
1037
|
# pylint: disable=E0203
|
|
@@ -1403,7 +1402,7 @@ class _RRuleStr:
|
|
|
1403
1402
|
def _handle_until(rrkwargs, name, value, **kwargs):
|
|
1404
1403
|
global parser
|
|
1405
1404
|
if not parser:
|
|
1406
|
-
from
|
|
1405
|
+
from dateutilx import parser
|
|
1407
1406
|
try:
|
|
1408
1407
|
rrkwargs["until"] = parser.parse(value, ignoretz=kwargs.get("ignoretz"), tzinfos=kwargs.get("tzinfos"))
|
|
1409
1408
|
except ValueError as e:
|
|
@@ -1465,7 +1464,7 @@ class _RRuleStr:
|
|
|
1465
1464
|
def _parse_date_value(self, date_value, parms, rule_tzids, *, ignoretz, tzids, tzinfos):
|
|
1466
1465
|
global parser
|
|
1467
1466
|
if not parser:
|
|
1468
|
-
from
|
|
1467
|
+
from dateutilx import parser
|
|
1469
1468
|
|
|
1470
1469
|
datevals = []
|
|
1471
1470
|
value_found = False
|
|
@@ -1597,7 +1596,7 @@ class _RRuleStr:
|
|
|
1597
1596
|
|
|
1598
1597
|
if forceset or len(rrulevals) > 1 or rdatevals or exrulevals or exdatevals:
|
|
1599
1598
|
if not parser and (rdatevals or exdatevals):
|
|
1600
|
-
from
|
|
1599
|
+
from dateutilx import parser
|
|
1601
1600
|
rset = RruleSet(cache=cache)
|
|
1602
1601
|
for value in rrulevals:
|
|
1603
1602
|
rset.rrule(self._parse_rfc_rrule(value, dtstart=dtstart, ignoretz=ignoretz, tzinfos=tzinfos))
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
from .tz import (
|
|
2
|
-
UTC,
|
|
3
2
|
TzFile,
|
|
4
3
|
TzIcal,
|
|
5
4
|
TzLocal,
|
|
@@ -12,25 +11,17 @@ from .tz import (
|
|
|
12
11
|
gettz,
|
|
13
12
|
resolve_imaginary,
|
|
14
13
|
)
|
|
15
|
-
from .win import TzWin, TzWinLocal, tzwin, tzwinlocal
|
|
16
14
|
|
|
17
15
|
# fmt: off
|
|
18
16
|
__all__ = ["TzFile", "TzIcal", "TzLocal", "TzOffset", "TzRange", "TzStr", "TzUTC",
|
|
19
|
-
"
|
|
17
|
+
"gettz", "datetime_ambiguous", "datetime_exists",
|
|
20
18
|
"resolve_imaginary", "UTC", "DeprecatedTzFormatWarning",
|
|
21
|
-
|
|
19
|
+
]
|
|
22
20
|
# fmt: on
|
|
23
21
|
|
|
24
22
|
|
|
25
|
-
|
|
26
|
-
"""Warning raised when time zones are parsed from deprecated formats."""
|
|
23
|
+
UTC = TzUTC()
|
|
27
24
|
|
|
28
25
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
tzfile = TzFile
|
|
32
|
-
tzical = TzIcal
|
|
33
|
-
tzlocal = TzLocal
|
|
34
|
-
tzoffset = TzOffset
|
|
35
|
-
tzrange = TzRange
|
|
36
|
-
tzutc = TzUTC
|
|
26
|
+
class DeprecatedTzFormatWarning(Warning):
|
|
27
|
+
"""Warning raised when time zones are parsed from deprecated formats."""
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import weakref
|
|
2
|
+
from collections import OrderedDict
|
|
3
|
+
from datetime import timedelta
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class _TzSingleton(type):
|
|
7
|
+
def __init__(cls, *args, **kwargs):
|
|
8
|
+
cls.__instance = None
|
|
9
|
+
super().__init__(*args, **kwargs)
|
|
10
|
+
|
|
11
|
+
def __call__(cls):
|
|
12
|
+
if cls.__instance is None:
|
|
13
|
+
cls.__instance = super().__call__()
|
|
14
|
+
return cls.__instance
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class _TzFactory(type):
|
|
18
|
+
def instance(cls, *args, **kwargs):
|
|
19
|
+
"""Alternate constructor that returns a fresh instance"""
|
|
20
|
+
return type.__call__(cls, *args, **kwargs)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class _TzCachedFactory(_TzFactory):
|
|
24
|
+
"""Factory with a weak identity cache plus a small strong LRU cache
|
|
25
|
+
to keep the most recently used instances alive."""
|
|
26
|
+
|
|
27
|
+
_strong_cache_size = 8
|
|
28
|
+
|
|
29
|
+
def __init__(cls, *args, **kwargs):
|
|
30
|
+
cls._instances = weakref.WeakValueDictionary()
|
|
31
|
+
cls._strong_cache = OrderedDict()
|
|
32
|
+
super().__init__(*args, **kwargs)
|
|
33
|
+
|
|
34
|
+
def _cache_key(cls, *args, **kwargs):
|
|
35
|
+
"""Subclasses define how constructor args map to a cache key."""
|
|
36
|
+
raise NotImplementedError
|
|
37
|
+
|
|
38
|
+
def __call__(cls, *args, **kwargs):
|
|
39
|
+
key = cls._cache_key(*args, **kwargs)
|
|
40
|
+
|
|
41
|
+
instance = cls._instances.get(key)
|
|
42
|
+
if instance is None:
|
|
43
|
+
instance = cls._instances.setdefault(key, cls.instance(*args, **kwargs))
|
|
44
|
+
|
|
45
|
+
cls._strong_cache[key] = cls._strong_cache.pop(key, instance)
|
|
46
|
+
if len(cls._strong_cache) > cls._strong_cache_size:
|
|
47
|
+
cls._strong_cache.popitem(last=False)
|
|
48
|
+
|
|
49
|
+
return instance
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class _TzOffsetFactory(_TzCachedFactory):
|
|
53
|
+
def _cache_key(cls, name, offset):
|
|
54
|
+
if isinstance(offset, timedelta):
|
|
55
|
+
offset = offset.total_seconds()
|
|
56
|
+
return name, offset
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class _TzStrFactory(_TzCachedFactory):
|
|
60
|
+
def _cache_key(cls, s, posix_offset=False):
|
|
61
|
+
return s, posix_offset
|
|
@@ -69,7 +69,7 @@ class TzRes:
|
|
|
69
69
|
"""
|
|
70
70
|
Load a timezone name from a DLL offset (integer).
|
|
71
71
|
|
|
72
|
-
>>> from
|
|
72
|
+
>>> from dateutilx.tzwin import TzRes
|
|
73
73
|
>>> tzr = TzRes()
|
|
74
74
|
>>> print(tzr.load_name(112))
|
|
75
75
|
'Eastern Standard Time'
|
|
@@ -93,7 +93,7 @@ class TzRes:
|
|
|
93
93
|
Parse strings as returned from the Windows registry into the time zone
|
|
94
94
|
name as defined in the registry.
|
|
95
95
|
|
|
96
|
-
>>> from
|
|
96
|
+
>>> from dateutilx.tzwin import TzRes
|
|
97
97
|
>>> tzr = TzRes()
|
|
98
98
|
>>> print(tzr.name_from_string('@tzres.dll,-251'))
|
|
99
99
|
'Dateline Daylight Time'
|
|
@@ -255,16 +255,16 @@ class TzWinLocal(TzWinBase):
|
|
|
255
255
|
"""
|
|
256
256
|
Class representing the local time zone information in the Windows registry
|
|
257
257
|
|
|
258
|
-
While :class:`dateutilx.tz.
|
|
258
|
+
While :class:`dateutilx.tz.TzLocal` makes system calls (via the :mod:`time`
|
|
259
259
|
module) to retrieve time zone information, ``tzwinlocal`` retrieves the
|
|
260
260
|
rules directly from the Windows registry and creates an object like
|
|
261
261
|
:class:`dateutilx.tz.tzwin`.
|
|
262
262
|
|
|
263
263
|
Because Windows does not have an equivalent of :func:`time.tzset`, on
|
|
264
|
-
Windows, :class:`dateutilx.tz.
|
|
264
|
+
Windows, :class:`dateutilx.tz.TzLocal` instances will always reflect the
|
|
265
265
|
time zone settings *at the time that the process was started*, meaning
|
|
266
266
|
changes to the machine's time zone settings during the run of a program
|
|
267
|
-
on Windows will **not** be reflected by :class:`dateutilx.tz.
|
|
267
|
+
on Windows will **not** be reflected by :class:`dateutilx.tz.TzLocal`.
|
|
268
268
|
Because ``tzwinlocal`` reads the registry directly, it is unaffected by
|
|
269
269
|
this issue.
|
|
270
270
|
"""
|
|
@@ -7,19 +7,19 @@ from relative deltas), local machine timezone, fixed offset timezone, and UTC
|
|
|
7
7
|
timezone.
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
|
-
import _thread
|
|
11
10
|
import bisect
|
|
12
11
|
import contextlib
|
|
13
12
|
import datetime
|
|
14
13
|
import os
|
|
15
14
|
import struct
|
|
15
|
+
import threading
|
|
16
16
|
import time
|
|
17
17
|
import weakref
|
|
18
18
|
from collections import OrderedDict
|
|
19
19
|
from dataclasses import dataclass
|
|
20
20
|
from typing import Any
|
|
21
21
|
|
|
22
|
-
from
|
|
22
|
+
from dateutilx.utils import Day, is_windows_os, weekdays
|
|
23
23
|
|
|
24
24
|
from ._common import TzRangeBase, _TzInfo, _validate_fromutc_inputs
|
|
25
25
|
from ._factories import _TzOffsetFactory, _TzSingleton, _TzStrFactory
|
|
@@ -29,6 +29,7 @@ rrule = None # pylint: disable=c0103
|
|
|
29
29
|
ZERO = datetime.timedelta(0)
|
|
30
30
|
EPOCH = datetime.datetime(1970, 1, 1, 0, 0)
|
|
31
31
|
EPOCHORDINAL = EPOCH.toordinal()
|
|
32
|
+
SU = weekdays[Day.SU]
|
|
32
33
|
|
|
33
34
|
|
|
34
35
|
class TzUTC(datetime.tzinfo, metaclass=_TzSingleton):
|
|
@@ -40,7 +41,7 @@ class TzUTC(datetime.tzinfo, metaclass=_TzSingleton):
|
|
|
40
41
|
.. doctest::
|
|
41
42
|
|
|
42
43
|
>>> import datetime as dt
|
|
43
|
-
>>> from
|
|
44
|
+
>>> from dateutilx.tz import *
|
|
44
45
|
|
|
45
46
|
>>> dt.datetime.now()
|
|
46
47
|
datetime.datetime(2003, 9, 27, 9, 40, 1, 521290)
|
|
@@ -57,7 +58,7 @@ class TzUTC(datetime.tzinfo, metaclass=_TzSingleton):
|
|
|
57
58
|
|
|
58
59
|
.. doctest::
|
|
59
60
|
|
|
60
|
-
>>> from
|
|
61
|
+
>>> from dateutilx.tz import tzutc, UTC
|
|
61
62
|
>>> tzutc() is tzutc()
|
|
62
63
|
True
|
|
63
64
|
>>> tzutc() is UTC
|
|
@@ -111,9 +112,6 @@ class TzUTC(datetime.tzinfo, metaclass=_TzSingleton):
|
|
|
111
112
|
return f"{self.__name__}()"
|
|
112
113
|
|
|
113
114
|
|
|
114
|
-
#: Convenience constant providing a :class:`tzutc()` instance
|
|
115
|
-
#:
|
|
116
|
-
#: .. versionadded:: 2.7.0
|
|
117
115
|
UTC = TzUTC()
|
|
118
116
|
|
|
119
117
|
|
|
@@ -242,7 +240,7 @@ class TzLocal(_TzInfo):
|
|
|
242
240
|
# The code above yields the following result:
|
|
243
241
|
#
|
|
244
242
|
# >>> import tz, datetime
|
|
245
|
-
# >>> t = tz.
|
|
243
|
+
# >>> t = tz.TzLocal()
|
|
246
244
|
# >>> datetime.datetime(2003,2,15,23,tzinfo=t).tzname()
|
|
247
245
|
# 'BRDT'
|
|
248
246
|
# >>> datetime.datetime(2003,2,16,0,tzinfo=t).tzname()
|
|
@@ -344,9 +342,6 @@ class _TzFile:
|
|
|
344
342
|
ttinfo_first: Any | None = None
|
|
345
343
|
|
|
346
344
|
|
|
347
|
-
_tzfile = _TzFile
|
|
348
|
-
|
|
349
|
-
|
|
350
345
|
class TzFile(_TzInfo):
|
|
351
346
|
"""
|
|
352
347
|
This is a ``tzinfo`` subclass that allows one to use the ``tzfile(5)``
|
|
@@ -384,7 +379,7 @@ class TzFile(_TzInfo):
|
|
|
384
379
|
|
|
385
380
|
.. testsetup:: tzfile
|
|
386
381
|
|
|
387
|
-
from
|
|
382
|
+
from dateutilx.tz import gettz
|
|
388
383
|
from datetime import datetime
|
|
389
384
|
|
|
390
385
|
.. doctest:: tzfile
|
|
@@ -446,7 +441,7 @@ class TzFile(_TzInfo):
|
|
|
446
441
|
def _set_tzdata(self, tzobj):
|
|
447
442
|
"""Set the time zone data of this object from a _tzfile object"""
|
|
448
443
|
# Copy the relevant attributes over as private attributes
|
|
449
|
-
for attr in
|
|
444
|
+
for attr in _TzFile.__slots__:
|
|
450
445
|
setattr(self, f"_{attr}", getattr(tzobj, attr))
|
|
451
446
|
|
|
452
447
|
def _read_tzfile(self, fileobj):
|
|
@@ -867,14 +862,14 @@ class TzRange(TzRangeBase):
|
|
|
867
862
|
|
|
868
863
|
.. testsetup:: tzrange
|
|
869
864
|
|
|
870
|
-
>>> from
|
|
865
|
+
>>> from dateutilx.tz import tzrange, tzstr
|
|
871
866
|
|
|
872
867
|
.. doctest:: tzrange
|
|
873
868
|
|
|
874
869
|
>>> tzstr('EST5EDT') == tzrange("EST", -18000, "EDT")
|
|
875
870
|
True
|
|
876
871
|
|
|
877
|
-
>>> from
|
|
872
|
+
>>> from dateutilx.relativedelta import *
|
|
878
873
|
>>> range1 = tzrange("EST", -18000, "EDT")
|
|
879
874
|
>>> range2 = tzrange("EST", -18000, "EDT", -14400,
|
|
880
875
|
... RelativeDelta(hours=+2, month=4, day=1,
|
|
@@ -888,7 +883,8 @@ class TzRange(TzRangeBase):
|
|
|
888
883
|
|
|
889
884
|
def __init__(self, stdabbr, stdoffset=None, dstabbr=None, dstoffset=None, *, start=None, end=None):
|
|
890
885
|
# global relativedelta
|
|
891
|
-
from
|
|
886
|
+
from dateutilx.relativedelta import RelativeDelta
|
|
887
|
+
from dateutilx.utils.weekday import SU
|
|
892
888
|
|
|
893
889
|
self._std_abbr = stdabbr
|
|
894
890
|
self._dst_abbr = dstabbr
|
|
@@ -1009,7 +1005,7 @@ class TzStr(TzRange, metaclass=_TzStrFactory):
|
|
|
1009
1005
|
|
|
1010
1006
|
def __init__(self, s, posix_offset=False):
|
|
1011
1007
|
global parser
|
|
1012
|
-
from
|
|
1008
|
+
from dateutilx.parser import _parser as parser
|
|
1013
1009
|
|
|
1014
1010
|
self._s = s
|
|
1015
1011
|
|
|
@@ -1038,7 +1034,7 @@ class TzStr(TzRange, metaclass=_TzStrFactory):
|
|
|
1038
1034
|
self.hasdst = bool(self._start_delta)
|
|
1039
1035
|
|
|
1040
1036
|
def _delta(self, x, isend=0):
|
|
1041
|
-
from
|
|
1037
|
+
from dateutilx import relativedelta
|
|
1042
1038
|
|
|
1043
1039
|
kwargs = {}
|
|
1044
1040
|
if x.month is not None:
|
|
@@ -1058,11 +1054,11 @@ class TzStr(TzRange, metaclass=_TzStrFactory):
|
|
|
1058
1054
|
if not isend:
|
|
1059
1055
|
kwargs["month"] = 4
|
|
1060
1056
|
kwargs["day"] = 1
|
|
1061
|
-
kwargs["weekday"] =
|
|
1057
|
+
kwargs["weekday"] = SU(+1)
|
|
1062
1058
|
else:
|
|
1063
1059
|
kwargs["month"] = 10
|
|
1064
1060
|
kwargs["day"] = 31
|
|
1065
|
-
kwargs["weekday"] =
|
|
1061
|
+
kwargs["weekday"] = SU(-1)
|
|
1066
1062
|
|
|
1067
1063
|
kwargs["seconds"] = x.time if x.time is not None else 7200 # Default is 2AM.
|
|
1068
1064
|
|
|
@@ -1094,7 +1090,7 @@ class _TzIcalVtz(_TzInfo):
|
|
|
1094
1090
|
self._tzid = tzid
|
|
1095
1091
|
self._comps = comps or []
|
|
1096
1092
|
self._cache = OrderedDict()
|
|
1097
|
-
self._cache_lock =
|
|
1093
|
+
self._cache_lock = threading.Lock()
|
|
1098
1094
|
|
|
1099
1095
|
def _find_comp(self, dt):
|
|
1100
1096
|
if len(self._comps) == 1:
|
|
@@ -1176,7 +1172,7 @@ class TzIcal:
|
|
|
1176
1172
|
def __init__(self, fileobj):
|
|
1177
1173
|
global rrule
|
|
1178
1174
|
if not rrule:
|
|
1179
|
-
from
|
|
1175
|
+
from dateutilx import rrule
|
|
1180
1176
|
|
|
1181
1177
|
if isinstance(fileobj, str):
|
|
1182
1178
|
self._s = fileobj
|
|
@@ -1436,7 +1432,7 @@ def __get_gettz():
|
|
|
1436
1432
|
self.__instances = weakref.WeakValueDictionary()
|
|
1437
1433
|
self.__strong_cache_size = 8
|
|
1438
1434
|
self.__strong_cache = OrderedDict()
|
|
1439
|
-
self._cache_lock =
|
|
1435
|
+
self._cache_lock = threading.Lock()
|
|
1440
1436
|
|
|
1441
1437
|
def __call__(self, name=None):
|
|
1442
1438
|
with self._cache_lock:
|
|
@@ -1651,7 +1647,7 @@ def resolve_imaginary(dt):
|
|
|
1651
1647
|
|
|
1652
1648
|
.. doctest::
|
|
1653
1649
|
|
|
1654
|
-
>>> from
|
|
1650
|
+
>>> from dateutilx import tz
|
|
1655
1651
|
>>> from datetime import datetime
|
|
1656
1652
|
>>> NYC = tz.gettz('America/New_York')
|
|
1657
1653
|
>>> print(tz.resolve_imaginary(datetime(2017, 3, 12, 2, 30, tzinfo=NYC)))
|
|
@@ -2,14 +2,11 @@
|
|
|
2
2
|
Wrapper for _win.py to handle platform dependent import
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
from
|
|
5
|
+
from dateutilx.utils import is_windows_os
|
|
6
6
|
|
|
7
7
|
if is_windows_os():
|
|
8
8
|
from ._win import TzRes, TzWin, TzWinLocal
|
|
9
9
|
else:
|
|
10
10
|
TzRes = TzWin = TzWinLocal = None
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
tzres = TzRes
|
|
14
|
-
tzwin = TzWin
|
|
15
|
-
tzwinlocal = TzWinLocal
|
|
12
|
+
__all__ = ["TzRes", "TzWin", "TzWinLocal"]
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from .constants import Day, Frequency, Month
|
|
2
|
+
from .funcs import default_tzinfo, is_windows_os, today, within_delta
|
|
3
|
+
from .weekday import Weekday, weekdays
|
|
4
|
+
|
|
5
|
+
# fmt: off
|
|
6
|
+
__all__ = ["Day", "Frequency", "Month",
|
|
7
|
+
"default_tzinfo", "is_windows_os", "today", "within_delta",
|
|
8
|
+
"Weekday", "weekdays"
|
|
9
|
+
]
|
|
10
|
+
# fmt: on
|
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
datetimes.
|
|
1
|
+
import datetime as dt
|
|
2
|
+
import sys
|
|
4
3
|
|
|
5
|
-
.. versionadded:: 2.7.0
|
|
6
|
-
"""
|
|
7
4
|
|
|
8
|
-
|
|
5
|
+
def is_windows_os() -> bool:
|
|
6
|
+
return sys.platform.startswith("win")
|
|
9
7
|
|
|
10
8
|
|
|
11
9
|
def today(tzinfo=None):
|
|
@@ -33,9 +31,9 @@ def default_tzinfo(dt, tzinfo):
|
|
|
33
31
|
|
|
34
32
|
.. doctest::
|
|
35
33
|
|
|
36
|
-
>>> from
|
|
37
|
-
>>> from
|
|
38
|
-
>>> from
|
|
34
|
+
>>> from dateutilx.tz import tzoffset
|
|
35
|
+
>>> from dateutilx.parser import parse
|
|
36
|
+
>>> from dateutilx.utils import default_tzinfo
|
|
39
37
|
>>> dflt_tz = tzoffset("EST", -18000)
|
|
40
38
|
>>> print(default_tzinfo(parse('2014-01-01 12:30 UTC'), dflt_tz))
|
|
41
39
|
2014-01-01 12:30:00+00:00
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from typing import Any
|
|
2
2
|
|
|
3
|
-
from
|
|
3
|
+
from .constants import Day
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
class NthWeekday:
|
|
@@ -22,6 +22,9 @@ class NthWeekday:
|
|
|
22
22
|
except AttributeError:
|
|
23
23
|
return False
|
|
24
24
|
|
|
25
|
+
def __hash__(self):
|
|
26
|
+
return hash((self.weekday, self.n))
|
|
27
|
+
|
|
25
28
|
def __repr__(self) -> str:
|
|
26
29
|
name = self.weekday.name
|
|
27
30
|
return f"{name}({self.n:+d})" if self.n else name
|
|
@@ -30,13 +33,9 @@ class NthWeekday:
|
|
|
30
33
|
# pylint: disable=r0903
|
|
31
34
|
class Weekday(NthWeekday):
|
|
32
35
|
def __init__(self, wkday: int, n: int | None = None):
|
|
36
|
+
if not 0 <= wkday <= 6:
|
|
37
|
+
raise ValueError(f"Weekday must be between 0 and 6, got {wkday}")
|
|
33
38
|
super().__init__(wkday=Day(wkday), n=n)
|
|
34
39
|
|
|
35
|
-
def __hash__(self):
|
|
36
|
-
return hash((self.weekday, self.n))
|
|
37
|
-
|
|
38
40
|
|
|
39
41
|
MO, TU, WE, TH, FR, SA, SU = weekdays = tuple(Weekday(x) for x in range(7))
|
|
40
|
-
|
|
41
|
-
# Alias
|
|
42
|
-
weekday = Weekday
|
|
@@ -43,12 +43,12 @@ Source = "https://github.com/rsb-23/dateutilx"
|
|
|
43
43
|
[tool.hatch.version]
|
|
44
44
|
source = "vcs"
|
|
45
45
|
[tool.hatch.build.targets.sdist]
|
|
46
|
-
include = ["
|
|
46
|
+
include = ["dateutilx", "LICENSE", "README.md", "pyproject.toml"]
|
|
47
47
|
[tool.hatch.build.targets.wheel]
|
|
48
|
-
packages = ["
|
|
48
|
+
packages = ["dateutilx"]
|
|
49
49
|
|
|
50
50
|
[tool.coverage.run]
|
|
51
|
-
source = ["
|
|
51
|
+
source = ["dateutilx"]
|
|
52
52
|
[tool.coverage.report]
|
|
53
53
|
fail_under = 85.0
|
|
54
54
|
skip_covered = true
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import weakref
|
|
2
|
-
from collections import OrderedDict
|
|
3
|
-
from datetime import timedelta
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class _TzSingleton(type):
|
|
7
|
-
def __init__(cls, *args, **kwargs):
|
|
8
|
-
cls.__instance = None
|
|
9
|
-
super().__init__(*args, **kwargs)
|
|
10
|
-
|
|
11
|
-
def __call__(cls):
|
|
12
|
-
if cls.__instance is None:
|
|
13
|
-
cls.__instance = super().__call__()
|
|
14
|
-
return cls.__instance
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
class _TzFactory(type):
|
|
18
|
-
def instance(cls, *args, **kwargs):
|
|
19
|
-
"""Alternate constructor that returns a fresh instance"""
|
|
20
|
-
return type.__call__(cls, *args, **kwargs)
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
class _TzOffsetFactory(_TzFactory):
|
|
24
|
-
def __init__(cls, *args, **kwargs):
|
|
25
|
-
cls.__instances = weakref.WeakValueDictionary()
|
|
26
|
-
cls.__strong_cache = OrderedDict()
|
|
27
|
-
cls.__strong_cache_size = 8
|
|
28
|
-
|
|
29
|
-
def __call__(cls, name, offset):
|
|
30
|
-
if isinstance(offset, timedelta):
|
|
31
|
-
key = (name, offset.total_seconds())
|
|
32
|
-
else:
|
|
33
|
-
key = (name, offset)
|
|
34
|
-
|
|
35
|
-
instance = cls.__instances.get(key, None)
|
|
36
|
-
if instance is None:
|
|
37
|
-
instance = cls.__instances.setdefault(key, cls.instance(name, offset))
|
|
38
|
-
|
|
39
|
-
cls.__strong_cache[key] = cls.__strong_cache.pop(key, instance)
|
|
40
|
-
|
|
41
|
-
# Remove an item if the strong cache is overpopulated
|
|
42
|
-
if len(cls.__strong_cache) > cls.__strong_cache_size:
|
|
43
|
-
cls.__strong_cache.popitem(last=False)
|
|
44
|
-
|
|
45
|
-
return instance
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
class _TzStrFactory(_TzFactory):
|
|
49
|
-
def __init__(cls, *args, **kwargs):
|
|
50
|
-
cls.__instances = weakref.WeakValueDictionary()
|
|
51
|
-
cls.__strong_cache = OrderedDict()
|
|
52
|
-
cls.__strong_cache_size = 8
|
|
53
|
-
|
|
54
|
-
def __call__(cls, s, posix_offset=False):
|
|
55
|
-
key = (s, posix_offset)
|
|
56
|
-
instance = cls.__instances.get(key, None)
|
|
57
|
-
|
|
58
|
-
if instance is None:
|
|
59
|
-
instance = cls.__instances.setdefault(key, cls.instance(s, posix_offset))
|
|
60
|
-
|
|
61
|
-
cls.__strong_cache[key] = cls.__strong_cache.pop(key, instance)
|
|
62
|
-
|
|
63
|
-
# Remove an item if the strong cache is overpopulated
|
|
64
|
-
if len(cls.__strong_cache) > cls.__strong_cache_size:
|
|
65
|
-
cls.__strong_cache.popitem(last=False)
|
|
66
|
-
|
|
67
|
-
return instance
|
dateutilx-0.2.0/src/tzwin.py
DELETED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|