8 ms·
Whenever: Typed and DST-safe datetimes for Python
- darthrupert 1y agoLooks 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 1y agoAh 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 1y agoWhat 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 1y agoThe 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 1y agoI think wesselbindt meant that datetimes should not inherit from dates.
- deleted 1y ago[deleted]
- OJFord 1y agoWhat would you do about equality comparisons?
- scott_w 1y agoThe 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 1y agoI’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 1y agoI really hoped this was about https://www.dangermouse.net/esoteric/whenever.html https://www.dangermouse.net/esoteric/whenever.html
- wodenokoto 1y agoFunny it doesn’t add comparison to date times in pandas, which is probably used to handle more dates than any of the others.
- jiggunjer 1y agoPandas uses stdlib or numpy for it seems.
- Kwpolska 1y ago> 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 1y agoThat 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 1y agoExtras 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 https://github.com/ariebovenberg/whenever/issues/158
- ariebovenberg 1y agoAuthor 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 1y ago1. 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.
- apeters 1y agoAm 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.
- johnfn 1y agoI think this is fairly unrealistic. Does all your datetime manipulation involve proper use of the fold parameter as indicated in the article?
- pkkm 1y agoI'm not the creator, the credit for that goes to Arie Bovenberg. I just wanted to show this to people.
- EdwardDiego 1y agoThere 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 https://github.com/jkittner/flake8-ban-utcnow
- raverbashing 1y agoHonestly yeah who in tarnation created that function and called it utcnow These things are really frustrating
- snvzz 1y agoA 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 1y agoAlmost 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 1y agoShouldn't people wanting to maximize the hours of daylight after work work night shifts?
- schrodinger 1y agoWhere do I find a software engineering job that has night shifts?
- fragmede 1y agoRemote job for a company in a different time zone
- vjerancrnjak 1y agoDoes 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 1y agoIn 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 1y agoBut 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 1y agoNo, 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 1y agoIf 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/ https://dev.arie.bovenberg.net/blog/python-datetime-pitfalls...
- JodieBenitez 1y agoExcellent read.
- jwilk 1y agoDiscussed on HN back then: https://news.ycombinator.com/item?id=39417231 https://news.ycombinator.com/item?id=39417231 (147 comments)
- mdaniel 1y agohttps://dev.arie.bovenberg.net/blog/python-datetime-pitfalls/#5-guessing-in-the-face-of-ambiguity 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-programmers-believe-about-time https://infiniteundo.com/post/25326999628/falsehoods-program...> <https://news.ycombinator.com/item?id=4128208 https://news.ycombinator.com/item?id=4128208>
- barbazoo 1y agoI 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.
- deleted 1y ago[deleted]
- atbpaca 1y agoI like that the type names are the same as in Java (java.time package). Great work!
- qwertox 1y ago> 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 1y agoAuthor 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 1y agoThank you. My apologies for not reading the FAQ. Also thank you for sharing your library.
- ariebovenberg 1y agoNo problem. After all, the readme does go from mentioning Pure Python directly to showing a benchmark graph where it's curiously absent
- davidkwast 1y agoI am still trying to cope with pytz and dateutils
- skeledrew 1y agoI 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 1y agoDates 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 1y agoHonestly, 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 1y agoI'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 1y agoAuthor 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-iso8601grammar https://tc39.es/proposal-temporal/#sec-temporal-iso8601gramm... [2] https://github.com/ariebovenberg/whenever/issues/204#issuecomment-2799955468 https://github.com/ariebovenberg/whenever/issues/204#issueco...
- mixmastamyk 1y agoSounds 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 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 1y agoWithout 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 https://www.iana.org/time-zones> and its friend <https://www.oracle.com/java/technologies/javase/tzupdater-readme.html 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 1y agoIt 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 1y agoIn 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.
- Jothamcloud 1y ago[flagged]
- kelseydh 1y agoA big revelation for me in solving so much timezone insanity came from realising that timezones should be expressed as locations rather than zones. Avoid general terms like "Pacific Standard Time" and stick to location-specific ones like: "Vancouver/Canada". The latter is how people expect their time to work, and correctly handles whatever quirky choices jurisdictions choose to do with their time.
- throwaway2037 1y agoIn my experience, all worthy date/time libraries use time zone IDs from the "tz database". Ref: https://en.wikipedia.org/wiki/Tz_database https://en.wikipedia.org/wiki/Tz_database Searching the list here: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones https://en.wikipedia.org/wiki/List_of_tz_database_time_zones I cannot find an entry for "Pacific Standard Time" nor "Vancouver/Canada", but I can see: "America/Vancouver".
- JimDabell 1y agoThe rule of thumb is: Use UTC to record when things happened (e.g. logging), use local time + timezone name (e.g. `Europe/London`) to schedule things for the future (e.g. meetings).
- throwaway2037 1y agoReading this post and comment section makes me shake my head. This looks like a near clone of Java JSR-310 (new date/time APIs), which was headed by the original author of Joda Time (Stephen Colebourne). Java 8 (and JSR-310) was released in 2014 -- 11 years ago(!). Amazingly, Python has suffered with their date/time libs this whole time with very little concerted effort to create new date/time APIs in the standard library. It's pathetic. I know I will be downvoted for this post, but I don't care. The Python standard library has so many of these awful weaknesses that other languages handle better. Except for machine learning R&D, I never recommend to use Python for any enterprise project except trivial ones. You are walking into a double trap of (1) weak types and (2) weak standard library.