# dateutil tells you its own downloads stopped being signed, and its licence depends on the date

> dateutil/dateutil extends Python's standard datetime module with relative deltas, recurrence rules, flexible parsing and timezone handling, and two things about it are stated in its own readme rather than discovered later. The first is a supply chain warning: distributions from 2.4.1 through 2.8.2 carried a rotating signature, the fingerprint is published, and everything uploaded since carries no signature at all. The second is a licence that changes with the calendar, since contributions after December 2017 are dual licensed and everything before it is under one of the two. The package name is also not the name you import.

**dateutil/dateutil** — Useful extensions to the standard Python datetime features

- Repository: https://github.com/dateutil/dateutil
- Stars: 2,638 · Forks: 598
- Language: Python
- License: NOASSERTION
- Published: 2026-09-28 · Updated: 2026-09-28 · Language: en
- Canonical page: https://hysenlabs.com/projects/dateutil-dateutil

## The project tells you its own downloads stopped being signed

The readme carries a short table of release signing key fingerprints, and a sentence on each side of it that together form a supply chain notice. From version 2.4.1 up to and including 2.8.2, every source and binary distribution was signed by a key that had itself been signed by the key that made the release before it, which is the usual way of building a chain of trust across rotations. After that range, the page says new releases may have signed tags but that binary and source distributions uploaded to the package index will no longer have signatures attached. That last part has been in the readme since well before the current release, so nobody is discovering it today. It also means the verification story for this package moved to whatever your installer does on its own, and the project is not pretending otherwise.

## The licence depends on the date a line was contributed

The licence section has a date in it. Everything contributed after the first of December 2017 is released under a choice of two licences, a permissive one and a three clause BSD. Everything contributed before that date is released under the three clause BSD only, unless it was explicitly relicensed. There is also a deliberate inconsistency in the sentence, a doubled word in the clause about earlier contributions, which suggests the paragraph was edited in place rather than rewritten. For most users this changes nothing, since both options are permissive. For anyone redistributing, vendoring or auditing, the licence of a given file is a question with a date attached, and the readme is the only place the answer is written down.

## The package name and the name you import are different

The installation section tells you to install the package with pip and then adds a parenthetical that the package name is different from the importable name. The installed distribution carries one name and the import statement uses another, and the page bothers to say so because that mismatch is the first thing a newcomer trips over. The related questions people ask about this package are full of the same confusion, some of them spelling the import in the wrong case, which the standard library's module search would not forgive. Nothing here is unusual for an old package that predates the current naming conventions, and the maintainers have kept the original names rather than breaking every import in the ecosystem, which is the right trade.

## The flagship example is a doctest the packaging step switches off

The quick example is a session transcript: parse a date from a string, use a recurrence rule to find the next year whose thirteenth of August falls on a Friday, compute the relative distance to Easter in that year, print the results, and finish with a line about the six month gap being a coincidence. It is a genuinely good demonstration because it uses four separate modules in one pass. It is also written as a documentation directive that the packaging script explicitly rewrites, replacing that directive with a plain code block, because the package index does not support it. The consequence is that the transcript's expected output is decoration rather than a test on the page where most people will meet it, and the real verification lives in the test suite the features list mentions in passing.

## The build script's compatibility guard runs after the import it guards

The packaging script does something few projects do any more, which is override the deprecated test command so that running it prints a message telling you to use a real runner and exits with a failure. That is good practice. It also opens by importing a loose version comparison helper from a module the standard library has been retiring, and only afterwards compares the packaging tool's version against a floor to warn about a separate requirement. So the warning about an old tool version runs after the import that a retired module would break, and cannot protect the case it was written for. It is a small file and a small problem, and it is the sort of thing a reader auditing the build will notice before they notice anything else.

## The timezone data is a file the project regenerates itself

The features list claims internally up to date world timezone information based on Olson's database, and the repository root shows how that is kept true: there is a script whose name says it updates the zone information and a metadata file describing the zone file the data came from. So the package does not read the host's timezone database at runtime for its own knowledge, it ships its own and refreshes it deliberately. That matters more than it sounds, because timezone rules change with political decisions and a library whose data goes stale reports offsets that were correct when the release was cut. The file is also why the package is larger than its feature list suggests, and why the readme mentions Windows registry zones alongside the usual suspects: those come from the same bundled dataset.

## Two documentation URLs, one on stable and one on latest

The readme points its prose links at the stable documentation and its badge at the latest. Both are the same service and both resolve, and a reader following the badge lands on documentation for a version they may not have installed while a reader following the prose link lands on documentation for a version that may be older than what they have. The install line itself is the shortest thing on the page and the easiest thing to get wrong:

```bash
pip install python-dateutil
```

For a library with a long stable history and infrequent releases, the stable documentation link is the one you want. Two other build badges are worth noticing for a different reason: coverage is pinned to the default branch by name in the badge query, and a chat badge points at a service that predates the current generation of developer chat, so the row is describing an older toolchain than the rest of the repository uses.

## Conclusion

Use dateutil for relative arithmetic, recurrence rules and parsing when the standard library stops short, which is what it has been good at since 2003 and still is. Three things to know. Read the licence paragraph rather than assuming a single licence, because which one applies to a given file depends on when it was contributed, and that matters if you are redistributing. Treat the published package as unsigned, because the project says so itself, and verify it the way your environment requires rather than trusting the upload. And pin the version, because the newest tagged release is from 2024 while the repository has taken commits since, so the code you would install is not everything the project has worked on.

## FAQ

### How do I install the dateutil module in Python?

With pip, and the package name is not the import name: you install python-dateutil and then import dateutil. The readme calls that difference out explicitly, because it is the first thing a newcomer trips over.

### is dateutil a standard python library

No. It is a separate package published on the package index that extends the standard library's datetime module, which is why the readme's installation step is a pip install rather than an import from the standard library.

### What does dateutil add to the standard datetime module?

Relative deltas such as next month or the last week of a month, deltas between two dates, recurrence rules from a superset of the iCalendar specification, parsing of dates from almost any string format, timezone implementations including registry based zones on Windows, and Easter Sunday dates by three different algorithms.

### Are dateutil's releases still signed?

No, and the readme says so. Distributions from version 2.4.1 up to 2.8.2 were signed by a rotating key whose fingerprint the page publishes, and it states that releases uploaded to the package index no longer carry signatures, while tags may still be signed.

### What license is dateutil under?

It depends on when a line was contributed. Everything after the first of December 2017 is dual licensed under either the Apache 2.0 licence or the BSD 3-Clause licence, and earlier contributions are BSD 3-Clause only unless they were explicitly relicensed.

### How does dateutil keep its timezone data current?

It ships its own copy of the world timezone information based on Olson's database, and the repository root carries both a script that updates that zone information and a metadata file describing the zone file it came from.

## Sources

- [dateutil/dateutil on GitHub](https://github.com/dateutil/dateutil)
- [Issues](https://github.com/dateutil/dateutil/issues)
- [README](https://github.com/dateutil/dateutil/blob/master/README.md)
- [Releases](https://github.com/dateutil/dateutil/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/dateutil-dateutil
