[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)