head 1.2; access; symbols pkgsrc-2026Q3:1.1.0.2 pkgsrc-2026Q3-base:1.1; locks; strict; comment @# @; 1.2 date 2026.10.25.12.49.47; author wiz; state dead; branches; next 1.1; commitid 1zJJDydnsZ6kfR0H; 1.1 date 2026.08.21.12.17.32; author wiz; state Exp; branches; next ; commitid mS6XcU4GfVIz9vSG; desc @@ 1.2 log @py-dateutil: update to 3.0.0. Version 3.0.0 (2026-10-21) ========================== **This is the last major version of** ``dateutil`` **that will support any version of Python older than 3.11.** The next release will be the 4.x series, which will support Python 3.11 and later. We may release fixes for serious bugs in the 3.0.x series, but there are no plans for new features there. The biggest change in this release is a rewrite of ``tz.tzfile``, which affects nearly every user of ``dateutil.tz`` and changes the UTC offset of nonexistent times (see below). ``dateutil`` also now depends on the ``tzdata`` package, and no longer ships its own time zone database. Data updates ------------ - ``dateutil`` no longer bundles a copy of the IANA time zone database. Time zone data now comes from the system (see ``dateutil.tz.TZPATH``) or, failing that, from the new ``tzdata`` dependency, so the data version is whatever version of ``tzdata`` is installed. (gh pr #1130) Features -------- - Rewrote ``tz.tzfile`` based on a backport of the ``zoneinfo`` module's pure-Python implementation. This adds support for Version 2 and Version 3 ``tzfile(5)`` binaries, resolving issues with timestamps beyond 2038 and "slim" format binaries. (gh issues #462, #1059, gh pr #1130) - Added ``dateutil.tz.TZPATH`` and ``dateutil.tz.reset_tzpath`` to allow for runtime configuration of the IANA time zone data search path. These replace the mutable ``dateutil.tz.TZPATHS`` list, which has been removed. (gh pr #1130) - ``dateutil`` now depends on the ``tzdata`` package, which ``gettz`` consults after the search path and before the Windows registry. On Windows this means that names that are both IANA keys and Windows time zone names, such as ``"UTC"``, now return a ``tzfile`` rather than a ``tzwin``. (gh pr #1130) Bugfixes -------- - ``tz.tzfile`` now follows PEP 495 for times that fall in a gap: with ``fold=0`` it uses the offset from before the transition, and with ``fold=1`` the offset from after it. Previously it always used the offset from after the transition, so for example ``datetime(2003, 4, 6, 2, 30, tzinfo=tz.gettz("America/New_York"))`` had a UTC offset of -04:00, where it now has -05:00, the same as with ``zoneinfo``. (gh pr #1130) - ``tz.tzfile`` objects for fixed-offset zones, such as ``tz.gettz("UTC")``, now return their offset, DST offset and abbreviation when ``utcoffset``, ``dst`` and ``tzname`` are called with ``None``, as ``tz.tzutc``, ``tz.tzoffset`` and ``zoneinfo.ZoneInfo`` do. This means that ``datetime.time`` objects with such a zone attached are now aware: ``time(12, tzinfo=tz.gettz("UTC")).isoformat()`` is now ``"12:00:00+00:00"`` rather than ``"12:00:00"``. (gh pr #1130) - ``tz.tzfile`` now infers ``dst()`` from the standard time on both sides of each DST period, rather than only the one before it, and does so for each transition rather than for each local time type. This fixes ``dst()`` for double summer time (e.g. in ``Europe/London`` in the 1940s), for half-hour DST (e.g. in ``Pacific/Rarotonga``) and where the standard offset changed at the same time as a DST transition (e.g. in ``America/Bahia_Banderas`` in 2010). Against the standard offsets in the tz database source, the only remaining errors are in ``Europe/Paris`` in 1944 and 1945. (gh pr #1130) - Fixed ``rrulestr`` raising ``ValueError`` on experimental ``X-`` parameters in an ``RRULE`` line (such as GNOME Evolution's ``X-EVOLUTION-ENDDATE``); these are now ignored as RFC 5545 permits. Fixed by @@yajo (gh pr #1374) - Enabled pickling and deepcopy of cached ``rrule`` and ``rruleset`` instances. The cache setting is preserved, and cached results are regenerated on demand without copying locks or generators. Reported by @@niccokunzmann (gh issue #1369). Fixed by @@Jay1023CN (gh pr #1600). - Fixed ``relativedelta.__ne__`` raising ``TypeError`` when comparing against an unsupported type such as ``None``; it now returns ``True``. Reported and fixed by @@kevinkt1 (gh issue #1157, gh pr #1158) - Raised the minimum version of ``six`` to 1.6, fixing ``No module named 'six.moves'`` errors with older versions. Reported by @@skytreader (gh issue #1415), fixed by @@jdarias3 (gh pr #1424). Deprecations ------------ - Deprecated the ``dateutil.zoneinfo`` module. The module now acts as a wrapper around the ``tzdata`` package and will be removed in a future version. Users are encouraged to migrate to ``dateutil.tz.gettz`` or the standard library's ``zoneinfo`` module. ``dateutil.zoneinfo.rebuild.rebuild`` no longer does anything, and by default raises ``RebuildDeprecationWarning`` as an error; filter the warning to call it as a no-op. (gh pr #1130) - Deprecated passing ``gettz`` a relative key that refers to a file outside of every directory on ``TZPATH``, such as ``"../../etc/localtime"``. By default this now raises ``dateutil.tz.DeprecatedTzKeyWarning`` as an error; filter the warning to keep the old behavior for now, or pass an absolute path instead. (gh pr #1130) Documentation changes --------------------- - Added intersphinx to the docs build and cleaned up some broken links. (gh pr #1463) Misc ---- - Releases are now uploaded to PyPI using trusted publishing, and the built sdist and wheel are tested on all supported platforms before upload. (gh pr #1619, #1622) - Changes to CI, tests and release tooling that do not affect users of the package: gh pr #1417, #1462, #1464, #1465, #1466, #1467, #1468, #1469, #1470, #1499, #1501, #1504, #1576, #1577, #1578, #1581, #1585. @ text @$NetBSD: patch-src_dateutil_tz_tz.py,v 1.1 2026/08/21 12:17:32 wiz Exp $ Support Internet RFC 8536 TZif files https://github.com/dateutil/dateutil/pull/1091 --- src/dateutil/tz/tz.py.orig 2024-03-01 18:35:19.000000000 +0000 +++ src/dateutil/tz/tz.py @@@@ -376,7 +376,8 @@@@ class _tzfile(object): information read from binary tzfiles. """ attrs = ['trans_list', 'trans_list_utc', 'trans_idx', 'ttinfo_list', - 'ttinfo_std', 'ttinfo_dst', 'ttinfo_before', 'ttinfo_first'] + 'ttinfo_std', 'ttinfo_dst', 'ttinfo_before', 'ttinfo_first', + 'tz_string_info'] def __init__(self, **kwargs): for attr in self.attrs: @@@@ -486,8 +487,6 @@@@ class tzfile(_tzinfo): setattr(self, '_' + attr, getattr(tzobj, attr)) def _read_tzfile(self, fileobj): - out = _tzfile() - # From tzfile(5): # # The time zone information files used by tzset(3) @@@@ -500,8 +499,22 @@@@ class tzfile(_tzinfo): if fileobj.read(4).decode() != "TZif": raise ValueError("magic not found") - fileobj.read(16) + version = fileobj.read(1).decode() + fileobj.read(15) + out = self._read_data_block(fileobj, 4, 'l') + if version < '2': + return out + fileobj.read(20) + out = self._read_data_block(fileobj, 8, 'q') + fileobj.read(1) + tz_string = fileobj.readline()[:-1].decode() + out.tz_string_info = tzstr(tz_string, posix_offset=True) + return out + + def _read_data_block(self, fileobj, time_size, format_char): + out = _tzfile() + ( # The number of UTC/local indicators stored in the file. ttisgmtcnt, @@@@ -527,16 +540,18 @@@@ class tzfile(_tzinfo): ) = struct.unpack(">6l", fileobj.read(24)) - # The above header is followed by tzh_timecnt four-byte - # values of type long, sorted in ascending order. + # The above header is followed by tzh_timecnt TIME_SIZE-byte + # signed integer values, sorted in ascending order. # These values are written in ``standard'' byte order. # Each is used as a transition time (as returned by # time(2)) at which the rules for computing local time # change. if timecnt: - out.trans_list_utc = list(struct.unpack(">%dl" % timecnt, - fileobj.read(timecnt*4))) + format = ">%d%s" % (timecnt, format_char) + size = timecnt * time_size + out.trans_list_utc = list(struct.unpack(format, + fileobj.read(size))) else: out.trans_list_utc = [] @@@@ -571,18 +586,18 @@@@ class tzfile(_tzinfo): abbr = fileobj.read(charcnt).decode() - # Then there are tzh_leapcnt pairs of four-byte + # Then there are tzh_leapcnt pairs of # values, written in standard byte order; the - # first value of each pair gives the time (as + # first (TIME_SIZE-byte) value of each pair gives the time (as # returned by time(2)) at which a leap second - # occurs; the second gives the total number of + # occurs; the second (4-byte) value gives the total number of # leap seconds to be applied after the given time. # The pairs of values are sorted in ascending order # by time. # Not used, for now (but seek for correct file position) if leapcnt: - fileobj.seek(leapcnt * 8, os.SEEK_CUR) + fileobj.seek(leapcnt * (time_size + 4), os.SEEK_CUR) # Then there are tzh_ttisstdcnt standard/wall # indicators, each stored as a one-byte value; @@@@ -712,6 +727,8 @@@@ class tzfile(_tzinfo): def _find_last_transition(self, dt, in_utc=False): # If there's no list, there are no transitions to find if not self._trans_list: + if self._tz_string_info: + return -2 return None timestamp = _datetime_to_timestamp(dt) @@@@ -721,6 +738,8 @@@@ class tzfile(_tzinfo): trans_list = self._trans_list_utc if in_utc else self._trans_list idx = bisect.bisect_right(trans_list, timestamp) + if idx == len(trans_list) and self._tz_string_info: + return -2 # We want to know when the previous transition was, so subtract off 1 return idx - 1 @@@@ -735,11 +754,6 @@@@ class tzfile(_tzinfo): return self._trans_idx[idx] - def _find_ttinfo(self, dt): - idx = self._resolve_ambiguous_time(dt) - - return self._get_ttinfo(idx) - def fromutc(self, dt): """ The ``tzfile`` implementation of :py:func:`datetime.tzinfo.fromutc`. @@@@ -768,12 +782,18 @@@@ class tzfile(_tzinfo): # First treat UTC as wall time and get the transition we're in. idx = self._find_last_transition(dt, in_utc=True) - tti = self._get_ttinfo(idx) - dt_out = dt + datetime.timedelta(seconds=tti.offset) + # For a timestamp in indefinite future, use the TZ string if available. + if idx == -2: + tzinfo = self._tz_string_info + dt_out = tzinfo.fromutc(dt.replace(tzinfo=tzinfo)) + fold = tzinfo._fold(dt_out) + dt_out = dt_out.replace(tzinfo=self) + else: + tti = self._get_ttinfo(idx) + dt_out = dt + datetime.timedelta(seconds=tti.offset) + fold = self.is_ambiguous(dt_out, idx=idx) - fold = self.is_ambiguous(dt_out, idx=idx) - return enfold(dt_out, fold=int(fold)) def is_ambiguous(self, dt, idx=None): @@@@ -793,6 +813,10 @@@@ class tzfile(_tzinfo): if idx is None: idx = self._find_last_transition(dt) + # For a timestamp in indefinite future, use the TZ string if available. + if idx == -2: + return self._tz_string_info.is_ambiguous(dt) + # Calculate the difference in offsets from current to previous timestamp = _datetime_to_timestamp(dt) tti = self._get_ttinfo(idx) @@@@ -809,11 +833,11 @@@@ class tzfile(_tzinfo): idx = self._find_last_transition(dt) # If we have no transitions, return the index - _fold = self._fold(dt) - if idx is None or idx == 0: + if idx is None or idx <= 0: return idx # If it's ambiguous and we're in a fold, shift to a different index. + _fold = self._fold(dt) idx_offset = int(not _fold and self.is_ambiguous(dt, idx)) return idx - idx_offset @@@@ -822,19 +846,27 @@@@ class tzfile(_tzinfo): if dt is None: return None + idx = self._resolve_ambiguous_time(dt) + if idx == -2: + return self._tz_string_info.utcoffset(dt) + if not self._ttinfo_std: return ZERO - return self._find_ttinfo(dt).delta + return self._get_ttinfo(idx).delta def dst(self, dt): if dt is None: return None + idx = self._resolve_ambiguous_time(dt) + if idx == -2: + return self._tz_string_info.dst(dt) + if not self._ttinfo_dst: return ZERO - tti = self._find_ttinfo(dt) + tti = self._get_ttinfo(idx) if not tti.isdst: return ZERO @@@@ -845,15 +877,21 @@@@ class tzfile(_tzinfo): @@tzname_in_python2 def tzname(self, dt): - if not self._ttinfo_std or dt is None: + if dt is None: return None - return self._find_ttinfo(dt).abbr + idx = self._resolve_ambiguous_time(dt) + if idx == -2: + return self._tz_string_info.tzname(dt) + if not self._ttinfo_std: + return None + return self._get_ttinfo(idx).abbr def __eq__(self, other): if not isinstance(other, tzfile): return NotImplemented return (self._trans_list == other._trans_list and self._trans_idx == other._trans_idx and + self._tz_string_info == other._tz_string_info and self._ttinfo_list == other._ttinfo_list) __hash__ = None @ 1.1 log @py-dateutil: fix timezone handling on NetBSD. From upstream pull request (from 2020!) by Paul Eggert. Bump PKGREVISION. @ text @d1 1 a1 1 $NetBSD$ @