[HN Gopher] Whenever - typed and DST-safe datetimes for Python
       ___________________________________________________________________
        
       Whenever - typed and DST-safe datetimes for Python
        
       Author : pkkm
       Score  : 237 points
       Date   : 2025-04-13 09:12 UTC (13 hours ago)
        
 (HTM) web link (github.com)
 (TXT) w3m dump (github.com)
        
       | darthrupert wrote:
       | Looks amazing. I had to deal with time handling in my very first
       | programming job 25 years ago, and lousy handling has been a pet
       | peeve of mine ever since.
        
       | wesselbindt wrote:
       | Ah nice it solves the Liskov violation that the standard library
       | has. In the standard library, dates can be compared with <, and
       | datetimes are dates. But compare a datetime with a date with <,
       | and you get an error. This drove me nuts at work recently.
       | 
       | I wonder what benefits this choice has that outweigh the risks of
       | this behavior.
        
         | heavenlyblue wrote:
         | What do you expect? There are so many ways to handle this
         | behvaiour it's pretty obvious why this is not allowed. Do you
         | take datetime.date and then compare? Do you assume all dates
         | are datetimes at midnight?
        
           | MrJohz wrote:
           | The issue isn't that the comparison should be valid, the
           | issue is that datetimes should not be dates. At best, there
           | is a "has a" relationship, but there shouldn't be an "is a"
           | relationship.
        
           | pkkm wrote:
           | I think wesselbindt meant that datetimes should not inherit
           | from dates.
        
         | OJFord wrote:
         | What would you do about equality comparisons?
        
           | scott_w wrote:
           | The author wrote a blog post describing that the problem is
           | datetime inherits from date when it shouldn't. The fact they
           | do but can't be compared is a compounding of the problem with
           | hidden bugs
        
       | JimDabell wrote:
       | I've tried Arrow, Delorean, and Pendulum, plus the stdlib
       | datetime of course, and settled on Whenever. It fits what I
       | actually do with datetimes better, plus it seems more actively
       | maintained. With the others I always seem to have a nagging
       | feeling in the back of my mind that I am missing a whole load of
       | edge cases. With Pendulum that seems more baked into the API.
        
       | dwattttt wrote:
       | I really hoped this was about
       | https://www.dangermouse.net/esoteric/whenever.html
        
       | wodenokoto wrote:
       | Funny it doesn't add comparison to date times in pandas, which is
       | probably used to handle more dates than any of the others.
        
         | jiggunjer wrote:
         | Pandas uses stdlib or numpy for it seems.
        
       | Kwpolska wrote:
       | > available in Rust or pure Python.
       | 
       | Hard pass. The complexity of having to use binary packages or
       | build things is not worth the performance benefit. The pure-
       | Python version requires building from source and passing special
       | flags, so it is not possible to specify it in requirements.txt.
        
         | stavros wrote:
         | That seems like an easy fix, they could release it as
         | `whenever[pure]`. It would probably take less time to write up
         | the issue than to write your comment.
        
           | Kwpolska wrote:
           | Extras only affect dependencies, you can't have different
           | codebases for them.
           | 
           | An issue was closed as not planned:
           | https://github.com/ariebovenberg/whenever/issues/158
        
             | ariebovenberg wrote:
             | Author here. To summarize the long discussion in the issue:
             | 
             | 1. I _love_ pure Python packages. Not everybody should be
             | forced to use Rust. I want installing pure-Python to be as
             | easy as possible
             | 
             | 2. Having separate names on PyPi (with or without extras)
             | creates confusion for libraries depending on whenever:
             | should they depend on whenever-py or whenever-rust? If one
             | "overwrites" the other, this adds confusion.
             | 
             | 3. Most users expect to "pip install whenever" and start
             | using the "fast" version
             | 
             | For me, points (3) and (2) weigh heavy enough to make (1)
             | slightly more cumbersome.
             | 
             | But: Maybe I've missed something. Have a read in the above
             | issue or add your 2 cents.
             | 
             | edit: formatting
        
               | Kwpolska wrote:
               | 1. Is the Rust version really faster enough to warrant
               | the extra complication? Is it faster in real-life code,
               | not only in synthetic benchmarks?
               | 
               | 2. I would expect `pip install whenever` to give me the
               | pure-Python version, and `pip install whenever-rust` to
               | give me the Rust extras. Both packages can be installed
               | at the same time; the pure-Python package detects and
               | uses the Rust implementation if present.
        
               | sirfz wrote:
               | Maybe something like psycopg[binary], would it be
               | possible to separate the rust binaries as an extra which
               | would be imported if it exists (i.e. When installed with
               | whenever[binary]) otherwise the vanilla python version is
               | used. Not sure of the specifics tho, just throwing out an
               | idea
        
         | OJFord wrote:
         | > The pure-Python version requires building from source and
         | passing special flags, so it is not possible to specify it in
         | requirements.txt.
         | 
         | You can put any flags in requirements.txt, including
         | -r[equiring] another txt etc.
         | 
         | Your point may apply to modern pyproject.toml tooling though,
         | or at least that it wouldn't be simply another entry in the
         | dependencies array.
        
           | Kwpolska wrote:
           | The special flags are environment variables, you can't pass
           | that in requirements.txt:
           | https://whenever.readthedocs.io/en/latest/faq.html#how-
           | can-i...
        
         | BiteCode_dev wrote:
         | Ah, so you are not using pyQT, numpy, any database driver,
         | pillow or anything using cryptography, then?
        
           | Kwpolska wrote:
           | For the libraries you listed, the benefits of using a native
           | library are much larger, since they're wrapping a well-known
           | library that is known to be secure and fully-featured, or
           | since the performance benefits are actually visible in any
           | significant code snippet. But here, there is no Rust library
           | to wrap, and I doubt the performance of a date-time library
           | would have any effect on the performance of virtually all
           | applications (maybe except for calendar apps).
        
       | apeters wrote:
       | Am I the only one to stick with the std lib, read the docs and
       | changelogs carefully, and implement functions I really need the
       | way my application makes use of them?
       | 
       | I learned the hard way, that dependencies kill projects.
       | 
       | Not saying this isn't great, thanks for creating it! It does have
       | its use cases, of course.
        
         | pkkm wrote:
         | I'm not the creator, the credit for that goes to Arie
         | Bovenberg. I just wanted to show this to people.
        
         | EdwardDiego wrote:
         | There are so many footguns in the datetime lib.
         | 
         | That's why I use a Flake8 plugin to prohibit especially
         | egregious footguns.
         | 
         | https://github.com/jkittner/flake8-ban-utcnow
        
           | raverbashing wrote:
           | Honestly yeah who in tarnation created that function and
           | called it utcnow
           | 
           | These things are really frustrating
        
             | mark-r wrote:
             | Yeah, utcnow is completely broken. They should have fixed
             | it when they created datetime.timezone.utc, but they
             | didn't. The recommendation is to use
             | datetime.datetime.now(datetime.timezone.utc) instead.
             | utcnow should be deprecated and eventually removed.
        
               | jessekv wrote:
               | I recently learned that there is datetime.UTC which is an
               | alias of datetime.timezone.utc
               | 
               | It helps a bit with the verbosity:
               | 
               | from datetime import datetime, UTC
               | 
               | datetime.now(UTC)
        
               | maleldil wrote:
               | That's from 3.11 onwards.
        
         | stavros wrote:
         | > Am I the only one to stick with the std lib, read the docs
         | and changelogs carefully
         | 
         | I work in healthcare. If I have a choice between "reading
         | docs/changelogs carefully, implementing functions", and "adding
         | an extra dependency", I'm taking the dependency every single
         | time.
         | 
         | I don't want footguns in my code, I don't want code I have to
         | write and test myself, and I don't want to have to become an
         | expert in a domain before I can write something that serves my
         | purpose.
         | 
         | For the datetime library, specifically, I'm switching to
         | whenever for everything, because I've been bitten by
         | conversions and naive/aware datetime confusion too many times.
        
           | globular-toast wrote:
           | > I work in healthcare. If I have a choice between "reading
           | docs/changelogs carefully, implementing functions", and
           | "adding an extra dependency", I'm taking the dependency every
           | single time.
           | 
           | This kinda sums up the sorry state of software engineering.
           | People can't even be bothered to read docs but will just
           | blindly install a package just because someone was able to
           | package it and upload it to PyPI.
           | 
           | Taking on a dependency does not relieve you of reading docs,
           | but it also adds a further burden as you now need to trust
           | the code. The stdlib is much more heavily tested and
           | documented than any 3rd party library will be.
        
             | mr_mitm wrote:
             | > People can't even be bothered to read docs but will just
             | blindly install a package just because someone was able to
             | package it and upload it to PyPI.
             | 
             | That's a straw man argument. No one said "blindly". You can
             | very well carefully consider the pros and cons of adding a
             | dependency and arrive at the conclusion that it makes
             | sense. Many PyPI packages are in the Debian stable
             | repositories, you could use that as an additional barrier
             | as well.
        
               | freehorse wrote:
               | To be fair, comment^^ actually said
               | choice between "reading docs/changelogs carefully,
               | implementing functions", and "adding an extra dependency"
               | 
               | which is what comment^ answers to, which to me actually
               | sounds like that the added dependency comes in place of
               | "reading docs/changelogs carefully".
               | 
               | I think it matters a lot how much one can trust a 3rd
               | party library, how much it is used, how much it is
               | maintained etc. Moreover, it also matters how central and
               | important this is to what you are actually doing, for
               | example if the datetimes I come across are pretty much
               | specific and with limited scope, I would probably care
               | about reading docs less than if I am reading data with
               | datetimes that may be totally wild. Furthermore, there
               | are some libraries that are just considered the standard
               | in some fields. If I use python I call pandas to read
               | csvs, I am obviously not gonna write my own csv parser.
               | It will also make your code more readable for others that
               | already know and use the same libraries if they are so
               | standard. But that's probably a very small minority of
               | libraries that people actually use in certain languages.
        
               | robertlagrant wrote:
               | > If I use python I call pandas to read csvs
               | 
               | So it's you that isn't just using the built in csv parser
               | in this project I inherited. Come back and repent.
        
               | akerl_ wrote:
               | How could it possibly be true that libraries that are so
               | commonly used that you consider them "the standard" are
               | so infrequently used as to be a "very small minority" of
               | libraries people actually use?
        
             | stavros wrote:
             | > The stdlib is much more heavily tested and documented
             | than any 3rd party library will be.
             | 
             | You initially said you write your own code instead of using
             | libraries, I replied to that, and now it's that you use the
             | stdlib instead of libraries. I won't argue against shifting
             | goalposts.
        
               | filoeleven wrote:
               | The poster who you just replied to is not the same person
               | who started the thread. I am yet another person.
               | 
               | In addition, the original post begins with, "Am I the
               | only one to stick with the std lib". The goalposts are
               | stable.
        
               | stavros wrote:
               | Again, the library in the article removes some stdlib
               | footguns. The footguns are there, and if you use the
               | stdlib, you need to remove (or avoid) them yourself.
               | There's no free lunch, and you'll either need to remove
               | them yourself (and test that code), avoid them (and
               | constantly remember to not hit them), or use another
               | library.
               | 
               | It's not a choice between "using a dependency" or "using
               | something in the stdlib", where all other code remains
               | the same, otherwise there would be no point to writing a
               | library, as it would offer nothing over `datetime`.
        
               | ok_dad wrote:
               | That's why I'm a software developer though, because I
               | learned the footguns in the standard library. I use it
               | before third party libraries whenever I can. I can't
               | understand the fear, just learn your job.
        
               | stavros wrote:
               | If your approach to footguns is "just learn your job",
               | I'm sorry, but you aren't a very good software developer.
        
             | oefrha wrote:
             | The stdlib datetime module is in more of a sorry state than
             | certain third party libraries and is full of footguns, as
             | you, a read-the-docs-and-changelogs-carefully person, can
             | surely tell from the myriad deprecations and warnings added
             | over the years, not to mention the confusing params like tz
             | and tzinfo. Heavily tested doesn't mean shit when the
             | semantics of the API is fundamentally flawed and can't be
             | updated.
        
             | paulddraper wrote:
             | Did OP blindly install the package?
             | 
             | Or do it with sight?
        
             | crote wrote:
             | > Taking on a dependency does not relieve you of reading
             | docs, but it also adds a further burden as you now need to
             | trust the code. The stdlib is much more heavily tested and
             | documented than any 3rd party library will be.
             | 
             | Sure, but the opposite applies as well. Sticking with the
             | flawed stdlib means you are trusting that _every single
             | future developer_ is as careful in reading all the docs as
             | you are - even when it 's someone reviewing that random
             | trivial-looking patch which is secretly hiding a massive
             | footgun. A junior developer submitted a five-line patch
             | touching datetime? Better schedule several hours for a
             | proper analysis!
             | 
             | Or you can write your own wrapper code, of course. Which
             | will almost certainly have worse documentation and testing
             | than a popular third-party library.
             | 
             | External libraries aren't evil. When chosen properly, they
             | _relieve_ you of burdens. You shouldn 't grab any random
             | "leftpad"-like dependency like they are going out of
             | fashion, but something as complicated as timezone handling
             | is best left to code written by domain experts - which
             | means using a library.
        
           | jethkl wrote:
           | My hope is that a lib like this one or similar could rally
           | mindshare and become integrated as the new standard, and
           | adopted by the wider developer community. In near term, it
           | comes down to trade-offs. I see no decision that works for
           | all use cases. Dependencies introduce ticking time bombs,
           | stdlibs should be correct and intuitive, but at least when
           | not they are usually well tested and maintained, but when
           | stdlib don't meet urgent production needs you have to do
           | something.
           | 
           | Link to Tom Scott & Computerphile from 10y ago on tz madness.
           | https://www.youtube.com/watch?v=-5wpm-gesOY
        
             | mark-r wrote:
             | Is there any part of the Python standard library written in
             | Rust? I would see that as a big impediment to having
             | Whenever adopted as standard.
        
               | thijsvandien wrote:
               | I don't think so, but they do offer a pure-Python version
               | as well.
               | 
               | https://whenever.readthedocs.io/en/latest/faq.html#how-
               | can-i...
        
               | mark-r wrote:
               | True, but does it suffer in efficiency? I wish they had
               | included the pure Python version in their benchmark.
        
           | barbazoo wrote:
           | I get where you're coming from. There's a price you pay
           | though eventually. You'll have to thoroughly vet all your
           | dependencies for malicious code at some point. Otherwise how
           | do you have any clue what you're running?
        
         | sgarland wrote:
         | You are a sad minority, IME. I'm right there with you. I
         | extended the uuid library to generate UUIDv7, based off of the
         | RFC. It's pretty easy to implement, as it turns out. Overruled,
         | because "we don't want to have to maintain additional code." As
         | if the ABI for bitshifts is going to change?!
        
           | ljm wrote:
           | There's an out of sight, out of mind mentality with
           | dependencies.
           | 
           | As long as there is a conscious decision to build or 'buy',
           | it's fine. I think some people can be a little too careless
           | with adding dependencies though, not realising they can have
           | an equal if not greater maintenance burden.
        
         | mvanbaak wrote:
         | As others stated, there are many rough edges and footguns in
         | the stdlib. BUT ... in my (and yours apparently) opinion, it's
         | a matter of knowing those edges/guns, and work with them. Like
         | you, I also prefer to create my own code around those instead
         | of bringing in some library that brings in their own foot guns
         | and possibly sub-dependencies and and and...
        
           | matsemann wrote:
           | So your projects end up with their own "lib" of scattered
           | time functions, possibly with new small bugs. I'd then rather
           | have a proper well-tested and maintained library.
        
             | mvanbaak wrote:
             | The "lib" one needs for date time functions is as good as
             | non-existent.
             | 
             | But yeah, you will have to create tests for the codepath,
             | instead of relying on the tests the library maintainers
             | create.
        
               | scott_w wrote:
               | Given the list of issues (most of which I had never heard
               | of) that the library author describes with datetime, I
               | think I trust his tests over the ones I'd write.
               | 
               | Given how many tests I see fail on 29th February at the
               | companies I've been at, I don't trust my colleagues'
               | tests either!
        
               | brookst wrote:
               | In a previous job where we had complete hell with an
               | internal datetime lib under ambiguous ownership, a
               | colleague joked that the original authors had taken early
               | retirement when they turned 2,147,483,647 years old.
        
         | mr_mitm wrote:
         | Are you saying you never pull in dependencies? Why stop there,
         | why not re-implement the std lib as well? Surely there is a
         | sensible middle ground: If you only need a small part of a
         | dependency, consider implementing it. If you make heavy use of
         | a dependency and want to benefit of years if not decades of
         | dedicated developers testing and maturing its code, with a
         | large community who has already stepped in all pitfalls you
         | might step into and collectively encountered all the edge
         | cases, just use the dependency.
        
         | xandrius wrote:
         | Creating from scratch also creates hidden debt, it's just moved
         | onto yourself. Especially when working with dates and
         | timezones.
        
           | raverbashing wrote:
           | A library that goes "poof" when you need to upgrade it is
           | also a hidden debt
        
             | scott_w wrote:
             | A member of staff who goes "poof" as the only one who
             | understands your wrapper library that has a critical bug is
             | a more common kind of hidden debt.
        
             | 0xCE0 wrote:
             | There is also a distinction to be made between "technical"
             | and "political" dependencies. Technical dependencies
             | usually track some spec or common consensus, and political
             | dependencies are e.g. timedate-library. Political
             | dependencies are almost like business logic, because they
             | have to track changing political decision made all over the
             | world (or be local to some country).
             | 
             | Timedates are hard, and units may require even harder
             | historical/present "political" tracking as how they are
             | defined, and I would never want to maintain this kind of
             | dependency: https://github.com/ryantenney/gnu-
             | units/blob/master/units.da...
             | 
             | And what comes to timedate problems, I try to keep it
             | simple if the project allows: store and operate with UTC
             | timestamps everywhere and only temporarily convert to to
             | local time (DSTs applied, if such) when displaying it in
             | user-facing UI. This functionality/understanding can be
             | locked into own 20-line microlibrary-dependency, which
             | forces its responsible person to understand country's
             | timezone and when e.g. DST changes and where/how/who
             | decides DST changes and what APIs is used to get UTC time
             | (and of course, its dependencies, e.g. NTP, and its
             | dependencies. e.g. unperturbed ground-state hyperfine
             | transition frequency of the caesium-133 atom, which result
             | is then combined with the Pope Gregory XIII's Gregorian
             | calendar, which is a type of solar calendar mixed with
             | religious event for fixing the time, which which is then
             | finally corrected by rewinding/forwarding "the clock"
             | because its too bright or dark for the politicians).
        
             | xandrius wrote:
             | A service goes poof, a library either slowly deteriorates
             | or breaks just as easily as a self-written one (if an
             | underlying platform breaks it for some reason). The self-
             | written one is maintained by 1 person, the other is used by
             | 100+ people who could jump in a collaborate on its fixing.
             | 
             | I would still rather using a library for dates, a million
             | times so.
        
               | raverbashing wrote:
               | > a library either slowly deteriorates or breaks just as
               | easily as a self-written one
               | 
               | Yes, I agree with this
               | 
               | > The self-written one is maintained by 1 person, the
               | other is used by 100+ people who could jump in a
               | collaborate on its fixing.
               | 
               | Libraries that have 100 people collaborating on it are
               | very few
               | 
               | Most likely you'll have to vendor it and fix whatever
               | issues you have.
               | 
               | Even worse when it's a dependency of a dependency and you
               | also use it, so, let's say a dependency of yours bumps
               | the version but this breaks your code. (Not sure this
               | breaks only in python or in js as well, but it's possibly
               | that it does)
        
               | no_wizard wrote:
               | Honest question: why is it so common for software
               | developers to not upgrade their dependencies on regular
               | intervals?
               | 
               | I can't for the life of me figure out why. If you update
               | everything incrementally you bypass the upgrade version
               | problem when you're so far behind that so much has
               | changed that it becomes an overwhelming burden.
               | 
               | I think frozen dependencies are a big anti pattern, and
               | places where I work that regularly update their deps
               | tended to have better software practices generally
        
               | crote wrote:
               | Because time spent updating dependencies won't contribute
               | to adding new features.
               | 
               | Besides, any update risks breaking stuff. _Not_ freezing
               | dependencies isn 't an option, because that means any
               | commit can cause breakage in a _completely unrelated_
               | part of the codebase, in a way which can be extremely
               | confusing to debug. And you don 't really want to install
               | the very newest versions either, better wait a week or
               | two for someone else to run into bugs and release a .1
               | version.
               | 
               | The sweet spot is somewhere in the middle: update often
               | enough to avoid updates becoming a massive burden, stick
               | with fixed versions between updates. I reckon it's best
               | to just schedule some dedicated time for it every month
               | or two.
        
               | no_wizard wrote:
               | That's why we do it on an interval and not when it's
               | first available. Avoids bleeding edge bugs but prevents
               | the overwhelming factor of being years out of date. It
               | typically gets handed out at the end of the month or
               | there about.
               | 
               | Being judicious in selecting dependencies goes a long way
               | too. Not always easy but certainly worth the time
        
               | mdaniel wrote:
               | I'm glad to hear that all libraries you use honor semver
               | religiously. For the rest of us stuck here on planet
               | Earth it's rolling the dice what, exactly, is going to
               | happen going from 1.7.12 to 1.7.13 for any random dep.
               | The only way to find out is to _try it_ and then _unfuck
               | things_ when it spits out some transitive error message
               | because it turns out that package-A and package-F hate
               | each other but only on Thursdays with a full moon
        
               | no_wizard wrote:
               | They don't all follow semver perfectly or in some cases
               | at all, but we have an interval when we do upgrades.
               | 
               | Our test suite is comprehensive and will catch most
               | breakages automatically. The key to success is robust
               | testing, as it cuts the manual footprint significantly.
               | 
               | This does mean we are quite judicious with selecting
               | dependencies.
               | 
               | It isn't all that complicated when everyone is following
               | best practices most of the time I have found[0]
               | 
               | It still leavings me wondering in a lot of cases
               | 
               | [0]: perhaps this is the real heart of the issue is best
               | practices are systematically ignored. I've worked at
               | places like that and it's no wonder they grind through
               | folks
        
               | mdaniel wrote:
               | I mean this seriously: congratulations on working
               | someplace that has such rigorous requirements that you
               | are able to write a comprehensive test suite that doesn't
               | get completely rewritten every month or so. I guess
               | because I enjoy working in startups, the cost I have to
               | pay is that "requirements" are spelt "fever dream" and
               | the "acceptance criteria" field in Jira is often just "."
               | (because it's a required field, donchano)
        
           | brookst wrote:
           | I cannot imagine having the spare time to invest in building
           | date/time foundations and maintaining them through changes to
           | DST timing and country/time zone changes.
           | 
           | The only crazier idea I can think of is implementing
           | character encoding conversions myself.
        
             | crazygringo wrote:
             | Seriously.
             | 
             | Nobody needs a package for "left-pad", which is the most
             | infamous example.
             | 
             | But there are a _lot_ of areas where it 's not a good use
             | of your time to reinvent the wheel. There's no moral virtue
             | in writing everything yourself. And popular packages have
             | gone through a more bug-finding and bug-fixing than your
             | personal code probably ever will.
        
         | dmos62 wrote:
         | Curious about examples of projects being killed by
         | dependencies.
        
           | michaelt wrote:
           | While I've never seen a project _killed_ by dependencies, I
           | 've certainly seen projects stuck on treadmill of constant
           | dependency updates.
           | 
           | You know, they import 5 libraries, each of which imports 5
           | more libraries, each of which imports 5 more libraries, and
           | suddenly they're buried in 'critical' updates because there's
           | a denial-of-service bug in the date parser used by the yaml
           | parser used by the configuration library used by the logging
           | library used by the application.
        
           | ljm wrote:
           | Not killed IME but bloated and dragged down by tech debt.
           | 
           | E.g the JS project that uses the stdlib Date API, and pulls
           | in moment.js, and also uses date-fns.
           | 
           | Or the one that pulls in bits and pieces of lodash, ramda,
           | and other functional libraries.
           | 
           | And maybe it uses native fetch and axios depending on the
           | current phase of the moon.
           | 
           | They don't die but time is wasted in code review trying to
           | understand if there is any kind of deliberate approach behind
           | the scattershot application of packages with duplicated
           | purposes.
           | 
           | (picking on JS is perhaps unfair but it's probably the most
           | egregious example of dependency hell)
        
             | MrJohz wrote:
             | The Date example is possibly an even better example of why
             | dependencies that get hard problems right are so important.
             | If Python's datetime library is bad, Date is truly
             | terrible. Every time I have used it I have regretted it
             | long term (including when using it in combination with
             | date-fns in the hope that that makes it usable). And in the
             | end, trying to keep things simple with Date has caused more
             | technical debt than using a sensible dependency.
             | 
             | Some problems simply require using the right tools. They
             | aren't necessarily hard, but they will be if you try to
             | hammer a nail in with a screwdriver. The Date API, and to a
             | certain extent Python's datetime module, are screwdrivers
             | for a nail-shaped problem.
             | 
             | The rest of your example seem to have more to do with bad
             | dependency practices than using dependencies in the first
             | place. If you are going to include a dependency, think
             | about it, consider whether it's worth it, document that
             | decision, and then consistently use that dependency. Just
             | because you've seen projects use dependencies poorly
             | doesn't mean dependents are bad by themselves.
        
               | Gare wrote:
               | Fortunately, JS is getting Temporal, which will be great.
               | No such thing on the horizon for Python yet.
        
               | MrJohz wrote:
               | Well, there's libraries like this one, which is the point
               | here.
               | 
               | And even in JS, Temporal won't be available broadly for a
               | good while yet (it will probably be rolling out in
               | Firefox in a couple of months' time, but in Safari it's
               | still behind a feature flag, and I don't think there's
               | even a feature-flagged implementation for Chrome yet). In
               | the meantime, it makes sense to use a polyfill -- again a
               | library.
               | 
               | By all means choose your dependencies wisely, but the
               | point I'm trying to make is that very often a sensible
               | use of dependencies will reduce your technical debt, and
               | attempting to use bad approaches to complex topics just
               | because they're built into the standard library will
               | cause so many problems down the line.
        
               | Gare wrote:
               | I fully agree with that. Just a bit disappointed that
               | Python is not even considering to fix/replace it's
               | problematic datetime library (as far as I know).
               | Excellent third-party library is good, but an excellent
               | standard library is even better!
        
               | burntsushi wrote:
               | Maybe this is the first step toward that future.
               | 
               | In Temporal's case, it takes _significant_ inspiration
               | from several existing datetime libraries in Javascript.
               | Those were all stepping stones (among others) that led to
               | Temporal.
        
         | foolfoolz wrote:
         | this is a great idea if you want to slow down your project.
         | most projects start with few rules and "best practices" like
         | this. everyone is free to pull in dependencies as needed.
         | because they are needed. but then once the project grows
         | larger, those who have been around longer want to reverse
         | course and gatekeep dependencies. but this is the opposite of
         | what helped the project grow initially. and later contributors
         | have a harder time making similar progress because they have to
         | fight to add basic libraries. ensuring that efficiency per
         | engineer goes down
        
         | johnfn wrote:
         | I think this is fairly unrealistic. Does all your datetime
         | manipulation involve proper use of the fold parameter as
         | indicated in the article?
        
         | BiteCode_dev wrote:
         | Functions that you have to document, test and maintain of
         | course. You do that, right? And all the people in your team,
         | they do that and will keep doing that once you leave, right?
         | And they all understand the business domain and all the
         | pitfalls that come with it and have the skill, time, and
         | resources to take care of it, right?
         | 
         | And this for every single problem: time, text, maths, network,
         | parsing, formatting, validating, authenticating...
        
       | snvzz wrote:
       | A tangent, but I hope the world gets its shit together and gets
       | rid of DST.
       | 
       | I am currently enjoying DST-free life in Japan, and feel that
       | people around the world deserve to get this much respect from
       | their own official clocks.
        
         | Mountain_Skies wrote:
         | Almost everyone wants to get rid of the twice annual clock
         | changes but are nearly evenly divided on if DST should be
         | permanent or cease to exist. It's a strange artifact of wanting
         | clock noon to be the midpoint of the workday but also wanting
         | to maximize the hours of daylight after work.
        
           | orthoxerox wrote:
           | Shouldn't people wanting to maximize the hours of daylight
           | after work work night shifts?
        
             | schrodinger wrote:
             | Where do I find a software engineering job that has night
             | shifts?
        
               | fragmede wrote:
               | Remote job for a company in a different time zone
        
               | mdaniel wrote:
               | Spoken as if 80% of the software engineer workload isn't
               | attending status update meetings to provide updates on
               | why nothing is getting done
        
               | fragmede wrote:
               | I'm not saying it isn't, but when the 9am scrum meeting
               | is at 4pm your time, you can be quite the night owl!
        
           | gjm11 wrote:
           | Who wants clock noon to be the midpoint of the workday? The
           | canonical working hours are 9am to 5pm [Parton 1980] whose
           | midpoint is at 1pm. Many people work earlier and/or later,
           | but my impression is that it's pretty unusual to have the
           | midpoint at noon.
           | 
           | ( _Schools_ tend to have earlier times. It 's not so unusual
           | for a school's workday to have its midpoint at about noon, I
           | think.)
        
             | brookst wrote:
             | 9-5 sounds so luxurious in today's 8-6 world where comms
             | start at 7am and wrap up around 9pm.
        
               | snvzz wrote:
               | I hope you get paid for being on-call those hours.
        
           | globular-toast wrote:
           | Clock noon already isn't the midpoint of the working day
           | (9-5) for many people. I don't think anyone cares about it
           | being when the sun is at its highest in the sky either. This
           | isn't even something most people know, and it's not even true
           | unless you live on the Greenwich meridian or n*15 degrees
           | east or west. What matters is how early we have to get up in
           | winter vs early we have to go to bed in the summer.
           | 
           | I've always been in favour of keeping the clocks at non-DST
           | all year, but now I have a new proposal: keep them at DST and
           | just hibernate in the winter. Work an hour or two less in the
           | winter when it's miserable.
        
         | layer8 wrote:
         | I would wish for that as well, but it's unlikely to happen. In
         | the EU for example, some countries would be on the losing side,
         | either by getting "bad" hours or by having to move to a
         | different time zone than their neighbor, which has significant
         | economic consequences. Such countries won't agree to a DST
         | abolishment that disadvantages them.
         | 
         | And for program code, it wouldn't really help as long as it's
         | still expected to be able to correctly handle dates in the
         | past.
        
           | brookst wrote:
           | I don't understand how eliminating DST would impact economics
           | of neighboring countries... today they both change clocks,
           | tomorrow they don't. What changes?
        
             | layer8 wrote:
             | It's not eliminating DST as such, it's switching to a
             | different time zone than their neighbor. Eliminating DST
             | means that either the East-most or West-most country would
             | get unfavorable hours, either in summer or winter. They can
             | mitigate that by changing their time zone, but now that
             | means they'll be in a different time zone than their
             | neighbor, which they previously shared a time zone with.
             | For example Spain could switch to a different time zone
             | than France, to get less extreme hours of days compared to
             | what is currently Central European Time, but having a time
             | difference would have economic costs between Spain and the
             | rest of CET land. (Arguably, both Spain and France should
             | switch to UTC, based on their proximity to the Greenwich
             | meridian, but a time difference between France and Germany
             | would be even worse.)
             | 
             | I'm not sure how real those costs would be beyond a
             | transitional period, but that's the discussions that have
             | been going on. It's a political risk, and nobody wants to
             | be on the losing side of such a change.
        
       | vjerancrnjak wrote:
       | Does someone know when these performance issues matter? My
       | understanding is that datetime is a shortlived object, you
       | wouldn't want thousands of datetime objects all over the
       | codebase.
       | 
       | Almost all of the time UTC is enough, if I need to
       | filter/bucket/aggregate by some range, I can reach for datetime
       | with tz for these filter/bucket/aggregate criteria, convert them
       | to UTC and on continues `int` comparison.
       | 
       | I'd imagine all of the cases handled by Whenever are mostly when
       | datetime is a long lived object, which I don't see a need for at
       | all.
       | 
       | I use it purely for allowing tz input from client, convert to UTC
       | immediately when it arrives, or, if I really need the tz, then
       | save it separately, which is rare (one example is calendar, where
       | tz should be stored, although probably not even next to every UTC
       | but at the user level, another is workforce scheduling, where
       | 8am-4pm or 8pm-4am can mean different things for different
       | locations -- but this is no longer datetime, it's purely time in
       | a timezone).
        
         | crazygringo wrote:
         | In my experience it's for calendar-related stuff. You need to
         | store things permanently with the timezone, especially for
         | recurring events. You don't want your scheduled lunch to move
         | from 12 to 1 because it's DST.
         | 
         | And so anything server-related with calendars will be making
         | tons of these conversions constantly. And you can't cache
         | things long-term in UTC because the conversions of future
         | events can change, when countries change DST etc.
        
           | vjerancrnjak wrote:
           | But lunch is 12 in time, not in date. You have to decide,
           | with short lived datetime what the desired outcome is for
           | today.
           | 
           | So you would not store that in UTC but just in time.
           | 
           | But yes, I'm ignoring the standard of calendar formats ,
           | maybe they are simpler .
           | 
           | I read through the article listing all the weirdness of other
           | datetime libraries and I'd say many were covering cases where
           | you behave that timezoned datetime is long lived .
           | 
           | One case even pointed out datetime construction with an
           | impossible hour.
        
             | crazygringo wrote:
             | No, my weekly lunch is at 12 every 7 days across a variety
             | of dates. The number of hours between each lunch changes
             | due to DST.
        
       | Hasnep wrote:
       | If you've not read the blog post that explains why this library
       | exists I recommend it. It's called "Ten Python datetime pitfalls,
       | and what libraries are (not) doing about it"
       | 
       | https://dev.arie.bovenberg.net/blog/python-datetime-pitfalls...
        
         | JodieBenitez wrote:
         | Excellent read.
        
         | jwilk wrote:
         | Discussed on HN back then:
         | 
         | https://news.ycombinator.com/item?id=39417231 (147 comments)
        
         | mdaniel wrote:
         | https://dev.arie.bovenberg.net/blog/python-datetime-pitfalls...
         | highlighted yet another thing that I hadn't previously
         | considered and makes me plug
         | <https://infiniteundo.com/post/25326999628/falsehoods-
         | program...> <https://news.ycombinator.com/item?id=4128208>
        
         | barbazoo wrote:
         | I am a seasoned programmer but whenever I deal with datetime
         | objects I do my best with unit tests and then just hope none of
         | these "edge" cases apply to us. Meaning: I have no idea really
         | how it works under the hood.
         | 
         | Now at least there's an LLM that might spot a bug every now and
         | then so that's nice.
        
       | atbpaca wrote:
       | I like that the type names are the same as in Java (java.time
       | package). Great work!
        
       | qwertox wrote:
       | > If performance isn't your top priority, a pure Python version
       | is available as well.
       | 
       | Then it would have been nice to see the benchmarks of the pure
       | Python implementation as well. What if it's worse than arrow?
        
         | ariebovenberg wrote:
         | Author here. It's answered briefly in the FAQ
         | 
         | > In casual benchmarks, the pure-Python version is about 10x
         | slower than the Rust version, making it 5x slower than the
         | standard library but still (in general) faster than Pendulum
         | and Arrow.
         | 
         | "(in general)" here since the speed compares differently per
         | operation, while the Rust version is faster across the board.
         | That said, there's no operation that is _significantly_ (or
         | unnecessarily) slower than Arrow or Pendulum.
         | 
         | edit: I'm considering adding comparison to the pure Python
         | version once I get the time for a more expanded "benchmarks"
         | page in the docs
        
           | qwertox wrote:
           | Thank you. My apologies for not reading the FAQ. Also thank
           | you for sharing your library.
        
             | ariebovenberg wrote:
             | No problem. After all, the readme does go from mentioning
             | Pure Python directly to showing a benchmark graph where
             | it's curiously absent
        
       | davidkwast wrote:
       | I am still trying to cope with pytz and dateutils
        
       | skeledrew wrote:
       | I go for Arrow when I want anything beyond the basics. This looks
       | pretty interesting, not really because of the greater coverage in
       | edge cases, but because while it has a Rustified mode, a pure
       | Python mode is also available. If I do use whenever, I don't have
       | to worry about having something else or falling back to datetime
       | if I want better datetime handling in a project on my phone, or
       | in some other environment where the Rust toolchain is non-
       | existent or problematic. Kudos.
        
       | BrandoElFollito wrote:
       | Dates and HTTP requests are the two things I always manipulate
       | through libraries (no matter the language, except maybe for
       | timestamps). It is so much simpler that way.
       | 
       | I am an amateur dev, though, so maybe someone who masters the
       | language will be better off using the raw standard libraries.
        
         | scott_w wrote:
         | Honestly, no. There are times when you want to get low level
         | but, when you do, you need to commit to learning that domain
         | _as well as_ the problem domain you're being paid to solve. If
         | those are disjoint, well, have fun!
        
       | iknownothow wrote:
       | I've read the link and the GitHub readme page.
       | 
       | I'm sure I'm in the top 1% of software devs for the most number
       | of timestamps parsed. [1]
       | 
       | DST is not a problem in Python. It's parsing string timestamps.
       | All libraries are bad, including this one, except Pandas. Pandas
       | does great at DST too btw.
       | 
       | And I'm not shilling for Pandas either. I'm a Polars user who
       | helicopters Pandas in whenever there's a timestamp that needs to
       | be parsed.
       | 
       | Pandas has great defaults. Here's string timestamps I expect to
       | be paesed by default. I'm willing to pass timezone in case of
       | naive timestamps:
       | 
       | * All ISO 8601 formats and all its weird mutant children that
       | differ by a tiny bit.
       | 
       | * 2025-05-01 (parsed not as date, but as timestamp)
       | 
       | * 2025-05-01 00:00:00 (or 00.0 or 00.000 or 0.000000 etc)
       | 
       | * 2025-05-01 00:00:00z (or uppercase Z or 00.0z or 00.000z or
       | 0.000000z)
       | 
       | * 2025-05-01 00:00:00+02:00 (I don't need this converted to some
       | time zone. Store offset if you must or convert to UTC. It should
       | be comparable to other non naive timestamps).
       | 
       | * 2025-03-30 02:30:00+02:00 (This is a non existent timestamp wrt
       | European DST but a legitimate timestamp in timestamp
       | representation, therefore it should be allowed unless I specify
       | CET or Europe/Berlin whatever)
       | 
       | * There's other timestamps formats that are non standard but are
       | obvious. Allow for a Boolean parameter called
       | accept_sensible_string_parsing and then parse the following:
       | \* 2025-05-01 00:00 (HH:mm format)            \* 2025-05-01
       | 00:00+01:00 (HH:mm format)
       | 
       | [1] It's not a real statistic, it's just that I work with a lot
       | of time series and customer data.
       | 
       | Disclaimer: I'm on the phone and on the couch so I wasn't able to
       | test the lib for its string parsing before posting this comment.
        
         | ariebovenberg wrote:
         | Author here. It's indeed a hard problem to parse "All ISO 8601
         | formats and all its weird mutant children that differ by a tiny
         | bit." Since the ISO standard is so expansive, every library
         | needs to decide for itself what to support. The ISO standard
         | allows all sorts of weird things, like 2-digit years,
         | fractional months, disallowing -00:00 offset, ordinal days,
         | etc.
         | 
         | Javascript's big datetime redesign (Temporal) has an
         | interesting overview of the decisions they made [1]. Whenever
         | is currently undergoing an expansion of ISO support as well, if
         | you'd like to chime in [2].
         | 
         | [1] https://tc39.es/proposal-temporal/#sec-temporal-
         | iso8601gramm... [2]
         | https://github.com/ariebovenberg/whenever/issues/204#issueco...
        
           | iknownothow wrote:
           | Thanks for the reply and apologies for the general cynicism.
           | It's not lost on me that it's people like you that build
           | tools that make the work tick. I'm just a loud potential
           | customer and I'm just forwarding the frustration that I have
           | with my own customers onto you :)
           | 
           | Your customers are software devs like me. When we're in
           | control of generating timestamps, we know we must use
           | standard ISO formatting.
           | 
           | However, what do I do when my customers give me access to an
           | S3 bucket with 1 billion timestamps in an arbitrary (yet
           | decipherable) format?
           | 
           | In the GitHub issue you seem to have undergone an evolution
           | from purity to pragmatism. I support this 100%.
           | 
           | What I've also noticed is that you seem to try to find
           | grounding or motivation for "where to draw the line" from
           | what's already been done in Temporal or Python stdlib etc.
           | This is where I'd like to challenge your intuitions and ask
           | you instead to open the flood gates and accept any format
           | that is theoretically sensible under ISO format.
           | 
           | Why? The damage has already been done. Any format you can
           | think of, already exists out there. You just haven't realized
           | it yet.
           | 
           | You know who has accepted this? Pandas devs (I assume, I
           | don't them). The following are legitimate timestamps under
           | Pandas (22.2.x):
           | 
           | * 2025-03-30T (nope, not a typo)
           | 
           | * 2025-03-30T01 (HH)
           | 
           | * 2025-03-30 01 (same as above)
           | 
           | * 2025-03-30 01 (two or more spaces is also acceptable)
           | 
           | In my opinion Pandas doesn't go far enough. Here's an example
           | from real customer data I've seen in the past that Pandas
           | doesn't parse.
           | 
           | * 2025-03-30+00:00 (this is very sensible in my opinion.
           | Unless there's a deeper theoretical regex pattern conflicts
           | with other parts of the ISO format)
           | 
           | Here's an example that isn't decipherable under a flexible
           | ISO interpretation and shouldn't be supported.
           | 
           | * 2025-30-03 (theoretically you can infer that 30 is a day,
           | and 03 is month. BUT you shouldn't accept this. Pandas used
           | to allow such things. I believe they no longer do)
           | 
           | I understand writing these flexible regexes or if-else
           | statements will hurt your benchmarks and will be painful to
           | maintain. Maybe release them under an new call like
           | `parse_best_effort` (or even `youre_welcome`) and document
           | pitfalls and performance degradation. Trust me, I'd rather
           | use a reliable generic but slow parser than spend hours
           | writing a write a god awful regex that I will only use once
           | (I've spent literal weeks writing regexes and fixes in the
           | last decade).
           | 
           | Pandas has been around since 2012 dealing with customer data.
           | They have seen it all and you can learn a lot from them. ISOs
           | and RFCs when it comes to timestamps don't mean squat. If
           | possible try to make Whenever useful rather than fast or
           | pure. I'd rather use a slimmer faster alternative to pandas
           | for parsing Timestamps if one is available but there aren't
           | any at the moment.
           | 
           | If time permits I'll try to compile a non exhaustive list of
           | real world timestamp formats and post in the issue.
           | 
           | Thank you for your work!
           | 
           | P.S. seeing BurntSushi in the GitHub issue gives me imposter
           | syndrome :)
        
             | burntsushi wrote:
             | Because you pinged me... Jiff also generally follows in
             | Temporal's footsteps here. Your broader point of supporting
             | things _beyond_ the specs (ISO 8601, RFC 3339, RFC 9557,
             | RFC 2822 and so on) has already been absorbed into the
             | Temporal ISO 8601 extensions. And that 's what Jiff
             | supports (and presumably, whenever, although I don't know
             | enough about whenever to be absolutely precise in what it
             | supports). So I think the philosophical point has already
             | been conceded by the Temporal project itself. What's left,
             | it seems, is a measure of degree. How far do you go in
             | supporting oddball formats?
             | 
             | I honestly do not know the answer to that question myself.
             | But I wouldn't necessarily look to Pandas as the shining
             | beacon on a hill here. Not because Pandas is doing anything
             | wrong per se, but because it's a totally different domain
             | and use case. On the one hand, you have a general purpose
             | library that needs to consider all of its users for all
             | general purpose datetime use cases. On the other hand, you
             | have a data scienc-y library designed for trying to slurp
             | up and make sense of messy data at scale. There may be
             | things that make sense in the latter that don't in the
             | former.
             | 
             | In particular, a major gap in your reasoning, from what I
             | can see, is that _constraints beget better error
             | reporting_. I don 't know how to precisely weigh error
             | reporting versus flexible parsing, but there _ought_ to be
             | some deliberation there. The more flexible your format, the
             | harder it is to give good error messages when you get
             | invalid data.
             | 
             | Moreover, "flexible parsing" doesn't actually have to be in
             | the datetime library. The task of flexible parsing is not,
             | in and of itself, overtly challenging. It's a tedious task
             | that can be build on top of the foundation of a good
             | datetime library. I grant that this is a bit of a cop-out,
             | but it's part of the calculus when designing ecosystem
             | libraries like this.
             | 
             | Speaking for me personally (in the context of Jiff),
             | something I wouldn't mind so much is adding a dedicated
             | "flexible" parsing mode that one can opt into. But I don't
             | think I'd want to make it the default.
        
       | mixmastamyk wrote:
       | Sounds like we need an industry/language-wide test suite to check
       | these many date/time/calendar libraries against. Like the browser
       | acid tests, though focused to baseline functionality only.
       | 
       | https://en.wikipedia.org/wiki/Acid3
       | 
       | I like this new lib (Thank You) but the name unfortunately
       | implies the opposite of what it is. "Whenever" sounds like you
       | don't care, but you'd only be using this if you _did_ care! Also
       | Shakira, haha. Hmm, pedantic is taken. Timely, precise, punctual,
       | meticulous, ahorita, pronto, etc. I like that temporal name.
       | 
       | Finally, none of these links mention immutability, but it should
       | be mentioned at the top.
        
         | mdaniel wrote:
         | Without the slightest sense of irony, I actually strongly
         | suspect such a test suite would only be valid at one moment in
         | time, since the timezone legislation is almost continuously in
         | flux. That's why <https://www.iana.org/time-zones> and its
         | friend
         | <https://www.oracle.com/java/technologies/javase/tzupdater-
         | re...> exist. As if to illustrate my point, the latest update
         | was 2025-03-22, presumably nuking any such conformance test
         | from Mar 21st
        
           | mixmastamyk wrote:
           | It would have to take the real world into account, no?
           | Additionally it could test various timezone definition
           | permutations without necessarily being dependent on a real
           | one.
        
           | NeutralForest wrote:
           | In that case, you'd have unit tests that confirm behaviors
           | like compatibility or failure of some operations between
           | types and integrations tests which pull an up to date DB of
           | rules and tests against that.
        
       ___________________________________________________________________
       (page generated 2025-04-13 23:00 UTC)