Prepare release 4.0.0 Run `towncrier build` for 4.0.0 and then curate the result by hand: the release opens with a note that 4.0 requires Python 3.11 and drops `six`, the `isoparse` entry is first among the bugfixes because it rejects strings that used to parse, the 1051, 1583 and 1625 entries are reworded, and the Hatchling and pyproject.toml entries are combined. The remaining CI-only entries in "Misc" are collapsed into a list of PR numbers.
diff --git a/NEWS b/NEWS index 6c0f428..26b3bb6 100644 --- a/NEWS +++ b/NEWS
@@ -1,3 +1,56 @@ +Version 4.0.0 (2026-11-01) +========================== + +``dateutil`` 4.0 requires Python 3.11 or later and no longer depends on +``six``. Apart from that, the changes in this release are bug fixes, but note +that ``isoparse`` is now stricter about the numeric fields it accepts (see +below). + + +Deprecations +------------ + +- Dropped support for Python versions older than 3.11 and removed the dependency + on ``six``, along with Python 2 compatibility helpers that were never part of + the public API, such as ``dateutil.tz.tzname_in_python2``. (gh pr #1625) + + +Bugfixes +-------- + +- ``parser.isoparse``, and the ``isoparser`` methods ``parse_isodate``, + ``parse_isotime`` and ``parse_tzstr``, now require each numeric field to be + exactly the expected number of ASCII digits. Strings that were previously + accepted, such as ``20200728121240`` (read as 21:24), ``2014- 4-21`` and + ``2_14-04-21``, and offsets such as ``+-1:00``, now raise ``ValueError``. + ``tzical`` applies the same check to ``TZOFFSETFROM`` and ``TZOFFSETTO``. + Reported by @janos-gonye (gh issue #1074). Fixed by @varun3257 (gh pr #1617). +- Fixed an issue where iterating over a cached ``rrule`` or ``rruleset`` could + hang forever if another iterator over the same rule had already completed the + cache, for example when a cached ``rrule`` was included twice in an + ``rruleset``. Reported by @bysiber (gh pr #1455). Fixed by @pganssle (gh pr + #1655). +- Unpickling a ``tzutc`` now gives the ``dateutil.tz.UTC`` singleton, and + unpickling a ``tzoffset`` gives the same object as calling + ``tzoffset(name, offset)``. Previously unpickling bypassed the + singleton-generation logic. Reported and fixed by @masipcat (gh issue #1051, + gh pr #1053). +- ``relativedelta(yearday=366)`` now resolves to December 31 in leap years. + Previously it gave December 30, the same date as ``yearday=365``. Reported + and fixed by @Master-Norna (gh pr #1583). + + +Misc +---- + +- The build backend is now Hatchling, and the package metadata is in + ``pyproject.toml``. Versions are still derived from Git tags and exposed as + ``dateutil.__version__``. This mainly affects people building ``dateutil`` + from source. (gh pr #1637, #1638) +- Changes to CI, tests and release tooling that do not affect users of the + package: gh pr #1636, #1644, #1645, #1646, #1648, #1649, #1650. + + Version 3.0.0 (2026-10-21) ==========================
diff --git a/changelog.d/1051.bugfix.rst b/changelog.d/1051.bugfix.rst deleted file mode 100644 index 24d6b65..0000000 --- a/changelog.d/1051.bugfix.rst +++ /dev/null
@@ -1 +0,0 @@ -Fixed issue where unpickling ``tzutc`` and ``tzoffset`` would bypass the singleton-generation logic. Unpickling a ``tzutc`` will now give the ``dateutil.tz.UTC`` singleton, and similarly unpickling a ``tzoffset`` will give you the same object that you would get by calling ``tzoffset(name, offset)``. Reported and fixed by @masipcat (gh issue #1051, gh pr #1053).
diff --git a/changelog.d/1583.bugfix.rst b/changelog.d/1583.bugfix.rst deleted file mode 100644 index cea930e..0000000 --- a/changelog.d/1583.bugfix.rst +++ /dev/null
@@ -1,3 +0,0 @@ -Fixed issue where ``relativedelta(yearday=366)`` resolved to December 30 -instead of December 31 in leap years, colliding with ``yearday=365``. -Reported and fixed by @Master-Norna (gh pr #1583).
diff --git a/changelog.d/1617.bugfix.rst b/changelog.d/1617.bugfix.rst deleted file mode 100644 index a30f258..0000000 --- a/changelog.d/1617.bugfix.rst +++ /dev/null
@@ -1 +0,0 @@ -Fixed ``isoparse`` accepting numeric fields that are not exactly the expected number of ASCII digits, which let strings like ``20200728121240``, ``2014- 4-21`` or an offset of ``+-1:00`` parse. The same check was added to the ``TZOFFSETFROM``/``TZOFFSETTO`` parsing in ``tzical``. Reported by @janos-gonye (gh issue #1074). Fixed by @varun3257 (gh pr #1617).
diff --git a/changelog.d/1625.deprecations.rst b/changelog.d/1625.deprecations.rst deleted file mode 100644 index c5ac453..0000000 --- a/changelog.d/1625.deprecations.rst +++ /dev/null
@@ -1,2 +0,0 @@ -Dropped support for Python versions older than 3.11 and removed the dependency -on ``six``.
diff --git a/changelog.d/1636.misc.rst b/changelog.d/1636.misc.rst deleted file mode 100644 index f51f13d..0000000 --- a/changelog.d/1636.misc.rst +++ /dev/null
@@ -1,2 +0,0 @@ -Switched CI environment creation and dependency installation to uv and tox-uv, -with dependency caching between runs. Fixed by @pganssle (gh pr #1636).
diff --git a/changelog.d/1637.misc.rst b/changelog.d/1637.misc.rst deleted file mode 100644 index da86831..0000000 --- a/changelog.d/1637.misc.rst +++ /dev/null
@@ -1,2 +0,0 @@ -Moved package metadata and pytest configuration to pyproject.toml. -Fixed by @pganssle (gh pr #1637).
diff --git a/changelog.d/1638.misc.rst b/changelog.d/1638.misc.rst deleted file mode 100644 index 51c3813..0000000 --- a/changelog.d/1638.misc.rst +++ /dev/null
@@ -1,2 +0,0 @@ -Switched the build backend to Hatchling while retaining Git-derived versions -and the public version attribute. Fixed by @pganssle (gh pr #1638).
diff --git a/changelog.d/1644.misc.rst b/changelog.d/1644.misc.rst deleted file mode 100644 index 28b9aec..0000000 --- a/changelog.d/1644.misc.rst +++ /dev/null
@@ -1,3 +0,0 @@ -CI now runs Python and timezone-data tests from the unpacked source distribution -during releases and when packaging changes. -Reported and fixed by @pganssle (gh pr #1644).
diff --git a/changelog.d/1645.misc.rst b/changelog.d/1645.misc.rst deleted file mode 100644 index e5d7e83..0000000 --- a/changelog.d/1645.misc.rst +++ /dev/null
@@ -1,2 +0,0 @@ -Added zizmor checks for the GitHub Actions workflows. -Fixed by @pganssle (gh pr #1645).
diff --git a/changelog.d/1646.misc.rst b/changelog.d/1646.misc.rst deleted file mode 100644 index 6c3d3aa..0000000 --- a/changelog.d/1646.misc.rst +++ /dev/null
@@ -1,2 +0,0 @@ -Enabled grouped monthly Dependabot updates for GitHub Actions commit pins. -Fixed by @pganssle (gh pr #1646).
diff --git a/changelog.d/1648.misc.rst b/changelog.d/1648.misc.rst deleted file mode 100644 index f83cafd..0000000 --- a/changelog.d/1648.misc.rst +++ /dev/null
@@ -1,2 +0,0 @@ -CI no longer collects coverage on PyPy, which made the PyPy jobs much slower. -Fixed by @pganssle (gh pr #1648).
diff --git a/changelog.d/1649.misc.rst b/changelog.d/1649.misc.rst deleted file mode 100644 index 99b3620..0000000 --- a/changelog.d/1649.misc.rst +++ /dev/null
@@ -1,2 +0,0 @@ -The test suite now runs in parallel with pytest-xdist. -Fixed by @pganssle (gh pr #1649).
diff --git a/changelog.d/1650.misc.rst b/changelog.d/1650.misc.rst deleted file mode 100644 index f571418..0000000 --- a/changelog.d/1650.misc.rst +++ /dev/null
@@ -1,2 +0,0 @@ -Removed an outdated warning that the tz tox environments modify the repository. -Fixed by @pganssle (gh pr #1650).
diff --git a/changelog.d/1655.bugfix.rst b/changelog.d/1655.bugfix.rst deleted file mode 100644 index dcb6a8e..0000000 --- a/changelog.d/1655.bugfix.rst +++ /dev/null
@@ -1,5 +0,0 @@ -Fixed an issue where iterating over a cached ``rrule`` or ``rruleset`` could -hang forever if another iterator over the same rule had already completed the -cache, for example when a cached ``rrule`` was included twice in an -``rruleset``. Reported by @bysiber (gh pr #1455). Fixed by @pganssle (gh pr -#1655).