Paul Ganssle
blog.ganssle.io · Personal blog · on HN since 2018
Paul Ganssle, a Python core developer, writes about datetime and time zone handling, packaging and testing in Python.
What HN saysCommenters cite his articles as clear explanations of why not to use utcnow and of naive local datetimes, and call the first one great.
22HN people shared it
9linked it in comments
15stories submitted
297story points
10 months agolast shared
2018people per year2026
Most-shared posts
- 1Stop using utcnow and utcfromtimestamp6 people · 145 points · first shared 2019 · 103 comments on HN
- 2You shouldn't invoke setup.py directly6 people · 140 points · first shared 2021 · 123 comments on HN
- 3Pytz: The Fastest Footgun in the West5 people · 4 points · first shared 2018 · discussion on HN
- 4Naive local datetimes2 people · first shared 2022
- 5A pseudo-TDD workflow using expected failures1 people · 2 points · first shared 2021 · discussion on HN
- 6Subtests in Python1 people · 2 points · first shared 2022 · discussion on HN
- 7Xfail and Code Coverage1 people · 2 points · first shared 2021 · discussion on HN
- 8Attractive Nuisances in Software Design1 people · 1 points · first shared 2023 · discussion on HN
- 9Semantics of timezone-aware datetime arithmetic1 people · 1 points · first shared 2024 · 1 comments on HN
What HN people wrote when they linked it
talboren · 2023-11-19
Paul Ganssle released a great article[1] explaining why you shouldn't use utcnow in 2019.
[1] https://blog.ganssle.io/articles/2019/11/utcnow.html
snthd · 2022-10-09
(2019)
A follow up from April 2022:
https://blog.ganssle.io/articles/2022/04/naive-local-datetimes.html
svat · 2019-05-27
It took me some effort to understand the issue here, so an alternative explanation in case it helps someone.
First, the part that's independent of programming language. You may want to read about absolute time and civil time (e.g. from https://abseil.io/docs/cpp/guides/time) but if you don't, in short: “civil time” refers to something like “2019 May 26 at 2:45 pm in New York City” (or “in the America/New_York time zone”), which means (roughly) whatever time the locals in New York City (or a larger shared geo-political zone) would agree is 2:45 pm on that date. To convert this to an absolute time, or in other words to make sense of “2019-05-26 14:45 in America/New_York”, we need data about the real world as of that date: most obviously we need to know whether Daylight-Saving Time was in effect on that date, but also what conventions were in use at the time. (This also means it's hard to know for certain what such a notation in the future means in terms of absolute time, as possibly DST could be abolished or the dates when it comes into effect could change.)
It so happens that in 1884 the conventions of New York City were such that it was about 4 minutes ahead of the then-recently standardized Eastern Time, so about 4 hours and 56 behind GMT.
So, in any “correct” library, we should see the following respected:
• “2019 May 26 at 2:45 pm in New York” should mean “2019 May 26 at 18:45 UTC” (timezone is EDT i.e. UTC minus 4 hours).
• “2019 Jan 26 at 2:45 pm in New York”…
pganssle · 2023-05-12
Actually, naïve times are considered aware in the system time zone. There's no good way to create a `tzinfo` object that behaves like "the system time zone" and doesn't have unfortunate consequences. See this article: https://blog.ganssle.io/articles/2022/04/naive-local-datetimes.html
It's not an ideal situation, but given path dependence I don't think it can be improved much from here.
mr_mitm · 2022-09-12
What do you mean? You type `pip install west` and a binary will appear in `~/.local/bin/west`. This directory needs to be part of your $PATH variable. Done.
Using virtual envs or pipx or poetry or whatever are non-standard.
Packaging Python projects, however, ... don't get me started on the whole `setup.py`, `setup.cfg`, `pyproject.toml` debacle. This article has more information about it, but the fact that this is supposed to be the short version makes it even more infuriating: https://blog.ganssle.io/articles/2021/10/setup-py-deprecated.html
dharmab · 2021-11-19
Poetry still uses setuptools! It makes it a lot easier for mortals. This is the blog post that convinced me to switch away from my old build system: https://blog.ganssle.io/articles/2021/10/setup-py-deprecated.html
zahlman · 2025-12-26
> Isn't assigning out what all made things fast presumptive without benchmarks?
We also have the benchmark of "pip now vs. pip years ago". That has to be controlled for pip version and Python version, but the former hasn't seen a lot of changes that are relevant for most cases, as far as I can tell.
> This also doesn't cover subtle things. Unsure if rkyv is being used to reduce the number of times that TOML is parsed but TOML parse times do show up in benchmarks in Cargo and Cargo/uv's TOML parser is much faster than Python's (note: Cargo team member, `toml` maintainer). I wish the TOML comparison page was still up and showed actual numbers to be able to point to.
This is interesting in that I wouldn't expect that the typical resolution involves a particularly large quantity of TOML. A package installer really only needs to look at it at all when building from source, and part of what these standards have done for us is improve wheel coverage. (Other relevant PEPs here include 600 and its predecessors.) Although that has also largely been driven by education within the community, things like e.g. https://blog.ganssle.io/articles/2021/10/setup-py-deprecated.html and https://pradyunsg.me/blog/2022/12/31/wheels-are-faster-pure-python/ .
Someone · 2025-03-28
Clickable footnotes:
[0]: https://pypi.org/project/stringcase
[1]: https://pypistats.org/packages/stringcase
[2]: https://pradyunsg.me/blog/2022/12/31/wheels-are-faster-pure-python
[3]: https://github.com/pypa/setuptools/issues/4910
[4]: https://github.com/zahlman/stringcase-new
[5]: https://pypi.org/project/stringcase-new
[6]: https://github.com/dmlls/python-casefy
[7]: https://pypistats.org/packages/casefy
[8]: https://peps.python.org/pep-0541/#how-to-request-a-name-transfer
[9]: https://github.com/frictionlessdata/frictionless-py
[10]: https://github.com/frictionlessdata/frictionless-py/pull/1727
[11]: https://github.com/notatallshaw
[12]: https://discuss.python.org/t/_/85847
[13]: https://blog.ganssle.io/articles/2021/10/setup-py-deprecated.html