pkgsrc-Changes archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

CVS commit: pkgsrc/time/py-dateutil



Module Name:    pkgsrc
Committed By:   wiz
Date:           Fri Aug 21 12:17:33 UTC 2026

Modified Files:
        pkgsrc/time/py-dateutil: Makefile distinfo
Added Files:
        pkgsrc/time/py-dateutil/patches: patch-src_dateutil_parser___parser.py
            patch-src_dateutil_tz_tz.py patch-src_dateutil_zoneinfo_rebuild.py
            patch-tests_test__tz.py

Log Message:
py-dateutil: fix timezone handling on NetBSD.

>From upstream pull request (from 2020!) by Paul Eggert.

Bump PKGREVISION.


To generate a diff of this commit:
cvs rdiff -u -r1.41 -r1.42 pkgsrc/time/py-dateutil/Makefile
cvs rdiff -u -r1.22 -r1.23 pkgsrc/time/py-dateutil/distinfo
cvs rdiff -u -r0 -r1.1 \
    pkgsrc/time/py-dateutil/patches/patch-src_dateutil_parser___parser.py \
    pkgsrc/time/py-dateutil/patches/patch-src_dateutil_tz_tz.py \
    pkgsrc/time/py-dateutil/patches/patch-src_dateutil_zoneinfo_rebuild.py \
    pkgsrc/time/py-dateutil/patches/patch-tests_test__tz.py

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: pkgsrc/time/py-dateutil/Makefile
diff -u pkgsrc/time/py-dateutil/Makefile:1.41 pkgsrc/time/py-dateutil/Makefile:1.42
--- pkgsrc/time/py-dateutil/Makefile:1.41       Fri Aug 21 11:21:36 2026
+++ pkgsrc/time/py-dateutil/Makefile    Fri Aug 21 12:17:32 2026
@@ -1,8 +1,8 @@
-# $NetBSD: Makefile,v 1.41 2026/08/21 11:21:36 wiz Exp $
+# $NetBSD: Makefile,v 1.42 2026/08/21 12:17:32 wiz Exp $
 
 DISTNAME=      python-dateutil-2.9.0.post0
 PKGNAME=       ${PYPKGPREFIX}-${DISTNAME:S/python-//:S/post/0.0./}
-PKGREVISION=   2
+PKGREVISION=   3
 CATEGORIES=    time python
 MASTER_SITES=  ${MASTER_SITE_PYPI:=p/python-dateutil/}
 

Index: pkgsrc/time/py-dateutil/distinfo
diff -u pkgsrc/time/py-dateutil/distinfo:1.22 pkgsrc/time/py-dateutil/distinfo:1.23
--- pkgsrc/time/py-dateutil/distinfo:1.22       Fri Aug 21 11:21:36 2026
+++ pkgsrc/time/py-dateutil/distinfo    Fri Aug 21 12:17:32 2026
@@ -1,6 +1,10 @@
-$NetBSD: distinfo,v 1.22 2026/08/21 11:21:36 wiz Exp $
+$NetBSD: distinfo,v 1.23 2026/08/21 12:17:32 wiz Exp $
 
 BLAKE2s (python-dateutil-2.9.0.post0.tar.gz) = 853dce8ffa2bb628e0d82444793adb394e9962ddca529ce1dea814e30384b416
 SHA512 (python-dateutil-2.9.0.post0.tar.gz) = f76522de0ff21547327eaf6966e80a15c57f8f92588d520eabd354a732e5c4b51d9c3ac5effd9eaa6dd451d1bce329a54a3f4c6bf4f1bd08ff06b0305c994e5a
 Size (python-dateutil-2.9.0.post0.tar.gz) = 342432 bytes
+SHA1 (patch-src_dateutil_parser___parser.py) = fe00859ca998812df85ba5e800f5c673cf38987b
+SHA1 (patch-src_dateutil_tz_tz.py) = c14680fe7347d5b5e3d507f064728bdd4df55a62
+SHA1 (patch-src_dateutil_zoneinfo_rebuild.py) = d01e7abce705dffb1bd7624099cfe5e3f4340fb7
 SHA1 (patch-tests_test__isoparser.py) = d4cee0a18d24001746ad65ce5bad1f72ad253e7b
+SHA1 (patch-tests_test__tz.py) = 896c50c2739a725acf6c380592f8ec9b0b5a22a2

Added files:

Index: pkgsrc/time/py-dateutil/patches/patch-src_dateutil_parser___parser.py
diff -u /dev/null pkgsrc/time/py-dateutil/patches/patch-src_dateutil_parser___parser.py:1.1
--- /dev/null   Fri Aug 21 12:17:33 2026
+++ pkgsrc/time/py-dateutil/patches/patch-src_dateutil_parser___parser.py       Fri Aug 21 12:17:32 2026
@@ -0,0 +1,79 @@
+$NetBSD: patch-src_dateutil_parser___parser.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/parser/_parser.py.orig        2024-03-01 18:35:19.000000000 +0000
++++ src/dateutil/parser/_parser.py
+@@ -1389,7 +1389,8 @@ class _tzparser(object):
+ 
+     def parse(self, tzstr):
+         res = self._result()
+-        l = [x for x in re.split(r'([,:.]|[a-zA-Z]+|[0-9]+)',tzstr) if x]
++        token_re = r'([,:./+-]|[a-zA-Z]+|[0-9]+|<[a-zA-Z0-9+-]+>)'
++        l = [x for x in re.split(token_re, tzstr) if x]
+         used_idxs = list()
+         try:
+ 
+@@ -1398,20 +1399,25 @@ class _tzparser(object):
+             i = 0
+             while i < len_l:
+                 # BRST+3[BRDT[+2]]
++                abbr = ""
+                 j = i
+-                while j < len_l and not [x for x in l[j]
+-                                         if x in "0123456789:,-+"]:
++                while j < len_l and (l[j][0] == '<'
++                                     or not [x for x in l[j]
++                                             if x in "0123456789:,-+"]):
++                    if l[j][0] == '<':
++                        abbr += l[j][1:-1]
++                    else:
++                        abbr += l[j]
++                    used_idxs.append(j)
+                     j += 1
+                 if j != i:
+                     if not res.stdabbr:
+                         offattr = "stdoffset"
+-                        res.stdabbr = "".join(l[i:j])
++                        res.stdabbr = abbr
+                     else:
+                         offattr = "dstoffset"
+-                        res.dstabbr = "".join(l[i:j])
++                        res.dstabbr = abbr
+ 
+-                    for ii in range(j):
+-                        used_idxs.append(ii)
+                     i = j
+                     if (i < len_l and (l[i] in ('+', '-') or l[i][0] in
+                                        "0123456789")):
+@@ -1505,7 +1511,7 @@ class _tzparser(object):
+                      'TZ variable format.', tz.DeprecatedTzFormatWarning)
+             elif (l.count(',') == 2 and l[i:].count('/') <= 2 and
+                   not [y for x in l[i:] if x not in (',', '/', 'J', 'M',
+-                                                     '.', '-', ':')
++                                                     '.', '-', '+', ':')
+                        for y in x if y not in "0123456789"]):
+                 for x in (res.start, res.end):
+                     if l[i] == 'J':
+@@ -1542,6 +1548,12 @@ class _tzparser(object):
+                     if i < len_l and l[i] == '/':
+                         used_idxs.append(i)
+                         i += 1
++                        if l[i] in ('+', '-'):
++                            signal = (-1, 1)[l[i] == '+']
++                            used_idxs.append(i)
++                            i += 1
++                        else:
++                            signal = 1
+                         # start time
+                         len_li = len(l[i])
+                         if len_li == 4:
+@@ -1562,6 +1574,7 @@ class _tzparser(object):
+                             x.time = (int(l[i][:2]) * 3600)
+                         else:
+                             return None
++                        x.time *= signal
+                         used_idxs.append(i)
+                         i += 1
+ 
Index: pkgsrc/time/py-dateutil/patches/patch-src_dateutil_tz_tz.py
diff -u /dev/null pkgsrc/time/py-dateutil/patches/patch-src_dateutil_tz_tz.py:1.1
--- /dev/null   Fri Aug 21 12:17:33 2026
+++ pkgsrc/time/py-dateutil/patches/patch-src_dateutil_tz_tz.py Fri Aug 21 12:17:32 2026
@@ -0,0 +1,228 @@
+$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
Index: pkgsrc/time/py-dateutil/patches/patch-src_dateutil_zoneinfo_rebuild.py
diff -u /dev/null pkgsrc/time/py-dateutil/patches/patch-src_dateutil_zoneinfo_rebuild.py:1.1
--- /dev/null   Fri Aug 21 12:17:33 2026
+++ pkgsrc/time/py-dateutil/patches/patch-src_dateutil_zoneinfo_rebuild.py      Fri Aug 21 12:17:32 2026
@@ -0,0 +1,46 @@
+$NetBSD: patch-src_dateutil_zoneinfo_rebuild.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/zoneinfo/rebuild.py.orig      2024-03-01 18:35:19.000000000 +0000
++++ src/dateutil/zoneinfo/rebuild.py
+@@ -3,7 +3,7 @@ import json
+ import tempfile
+ import shutil
+ import json
+-from subprocess import check_call, check_output
++from subprocess import check_call
+ from tarfile import TarFile
+ 
+ from dateutil.zoneinfo import METADATA_FN, ZONEFILENAME
+@@ -39,27 +39,14 @@ def _run_zic(zonedir, filepaths):
+ 
+ 
+ def _run_zic(zonedir, filepaths):
+-    """Calls the ``zic`` compiler in a compatible way to get a "fat" binary.
+-
+-    Recent versions of ``zic`` default to ``-b slim``, while older versions
+-    don't even have the ``-b`` option (but default to "fat" binaries). The
+-    current version of dateutil does not support Version 2+ TZif files, which
+-    causes problems when used in conjunction with "slim" binaries, so this
+-    function is used to ensure that we always get a "fat" binary.
++    """Calls the ``zic`` compiler.
+     """
+ 
+     try:
+-        help_text = check_output(["zic", "--help"])
++        check_call(["zic", "-d", zonedir] + filepaths)
+     except OSError as e:
+         _print_on_nosuchfile(e)
+         raise
+-
+-    if b"-b " in help_text:
+-        bloat_args = ["-b", "fat"]
+-    else:
+-        bloat_args = []
+-
+-    check_call(["zic"] + bloat_args + ["-d", zonedir] + filepaths)
+ 
+ 
+ def _print_on_nosuchfile(e):
Index: pkgsrc/time/py-dateutil/patches/patch-tests_test__tz.py
diff -u /dev/null pkgsrc/time/py-dateutil/patches/patch-tests_test__tz.py:1.1
--- /dev/null   Fri Aug 21 12:17:33 2026
+++ pkgsrc/time/py-dateutil/patches/patch-tests_test__tz.py     Fri Aug 21 12:17:32 2026
@@ -0,0 +1,16 @@
+$NetBSD: patch-tests_test__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
+
+--- tests/test_tz.py.orig      2024-03-01 18:35:19.000000000 +0000
++++ tests/test_tz.py
+@@ -1642,7 +1642,7 @@ def test_valid_dateutil_format(tz_str, expected):
+     'hdfiughdfuig,dfughdfuigpu87ñ::',
+     ',dfughdfuigpu87ñ::',
+     '-1:WART4WARST,J1,J365/25',
+-    'WART4WARST,J1,J365/-25',
++    'WART4WARST,J1,J365/--25',
+     'IST-2IDT,M3.4.-1/26,M10.5.0',
+     'IST-2IDT,M3,2000,1/26,M10,5,0'
+ ])



Home | Main Index | Thread Index | Old Index