Arrow v1.0: After 8 years, even better dates and times for Python
github.com
github.com
It has separate types for
• LocalTime (milliseconds after midnight)
• LocalDate (julian day),
• LocalDateTime (julian day and milliseconds after midnight),
• Instant (nanoseconds since EPOCH),
• ZonedDateTime (which is a point in time with a timezone, and exposes both the localdatetime and the instant APIs)
All of these types have a reason to exist, and definitely shouldn't be mixed together (like python does).
• If I program an alarm clock, I'll want to use LocalTime. Even if DST starts/ends, you still wanna get woken up at 8am.
• My birthday is a LocalDate. It usually has no time information, and usually isn't depending on a timezone. An anniversary is the same.
• The moment when a loggable event happened is an Instant. The event doesn't care about timezones, only the exact time it happened.
• A calendar event is a ZonedDateTime: the meeting will happen at 10am CET, regardless of which timezone I'm in at that point.
All these types describe different concepts, and they shouldn't be mixed together. Every language should adopt JSR310. Yes, it's relatively complicated, but it's extremely precise and accurate.
And you can convert them all!
•LocalDate + LocalTime becomes LocalDateTime
• LocalDateTime.atZone(ZoneId or ZoneOffset) becomes ZonedDateTime
• Instant.atZone(ZoneId or ZoneOffset) becomes ZonedDateTime
• ZonedDateTime.toInstant() or ZonedDateTime.toLocalDateTime() exposes local datetime and instant.
• LocalDate can easilybe converted to JapaneseDate, HebrewDate, ArabicDate.
[1] https://docs.rs/chrono/0.4.19/chrono/index.html
Edit: it seems like chrono's design took lessons learned from other time libraries, including JSR-310, into account, so that explains why they are so similar.
The new ES Temporal API is also inspired by the same API.
To be honest, I think JSR-310 is not correct in every regard and its implementation of every ISO 8601 format is a mistake. I even started out Chrono without referring to JSR-310 (because I have designed other date and time libraries in the past). But it is much better than, say, Python datetime to which is being compared.
Period is doubly problematic. It is important to realize that ISO 8601 is the standard for interchange formats, not the standard for computer data types (compare to, say, IEEE 754). As a result you need additional information to make it a proper data type standard. For ISO 8601 period you would need the actual algorithm to add it to a time point. What happens if you add 1 month (P1M) to January 30, 2021 (2021-01-30)? Would it be 2021-02-28 or 2021-03-02? Should we give both options to end users? You need a set of pluggable policies to make it work. JSR-310 Period class is pretty lacking in this regard. (In fact, pretty much every implementation of "relative delta" has the same problem. It can't be readily used in the business logic.)
Here, does julian day mean day number since 4713 BC or day number since the beginning of current year?
This allows you to specify year, month, and day easily, and expose it as hebrew date, japanese date, julian date or gregorian date easily.
For a day relative to the current year, there’s a separate type.
Yes. [1] Back in 2012, I filed a Python bug report that "datetime" has a formatter for ISO 8601 format strings, but no parser. I'd found four parsers, all with serious bugs.
After six years of discussion, it was fixed.[1]
(8601 is a huge spec, and we only needed a matching parser to start with. It is now free to grow.)
"Just have it parse .isoformat() and ship it!!"
The reason ISO 8601 handling is broken is because all these libraries are implementing against a wikipedia summary of a spec.
It's a strong argument for free, open standards.
[0] https://shop.bsigroup.com/ProductDetail/?pid=000000000030078...
I wouldn't have been able to design and implement Scaleway’s billing pipeline in 2013 without those.
More details at: https://kevin.deldycke.com/2020/10/billing-pipeline-critical...
Spice must flow!
Worse...too many modules included in the standard Python library with slightly incompatible implementations of the same functions.
I spent quite a while trying to understand why strptime was not working like I thought it should, before figuring out that I was using time.strptime when I should have been using datetime.strptime.
The difference that got me was that time.strptime was ignoring timezones in the format string and input string and assuming the local timezone. It was not an error to include %z in the format string and give it a time string that includes a timezone. It would simply silently be ignored and the local timezone used instead.
- requests
- arrow
Dates in Python are so fucked up that it is beyond imagination. I understand that there are philosophical reasons for that but I do not care. I need to compare dates, add dates, do sometime < now < someothertime, etc.
All this without a PhD in Time Pythonlology.
When I discovered arrow I fell in love and now I use it for anything. Need to output an ISO date? arrow. Need to output a timestamp? arrow. Need to compare two dates? arrow. arrow. arrow.
Yes, this is a hammer for any date nail *but it works*.
There are some great programs (such as Borg) that were hit by the monstruosities in pythin dates and eneded up with some half-baked semi-ISO output without timezones. Has the author used arrow by default he would not have gone wrong.
The main dev is great and a bit stubborn (he closed a Very important Issue Of Mine and I had to fix it myself :/) but I will be forever admirative about his work (and the work of other contributors).
I am waiting now for the next announce about requests.
EDIT: I also tried pendulum and delorean but always ended up back with arrow. I now need to understand how to move from moment.js to luxon.js and my life with dates will be complete.
> [the standard library has] too many types
No. That's just not at all true. In fact I would argue it's the opposite. You can make some very bad mistakes in python with dates because they silently coerce into each other in nonsensical ways. Arrow makes this much worse. A date is not the same as the millisecond at the start of thst date!
These such as Arrow, like moment.js, are good for UIs. But if you require plenty of date manipulation then I’d keep it native as possible with plenty of tests.
An example would be good as well.
I think dates have been my worst experience working in programming across a multitude of languages.
The Big Problem in Python's datetime library is the naive/tzaware thing. The same type is used for two very different concepts.
What kind of type errors? Maybe you mean naive and tzaware objects? Working on two tzaware objects with different offsets should not yield any error. Otherwise, it's worse than I thought.
> null timezone
What is a null timezone? Can you make an example of how it would be used in the real world?
If you want something for a point in time, you need an attached offset. That's an Instant in java.time.
If you need something more "human", then you get a LocalDateTime (in java.time parlance). Which is not a point in time unless you attach an offset to it, or localize it through a timezone.
Some operations just don't make sense between LocalDateTime. Example: can you measure the number of hours between one localdatetime and another localdatetime (or even an instant) ? No; because you don't know either offset.
Python doesn't prevent such operations; it tries to make things work in a simpler, but wrong way. Date/time handling is one of the hard things to get always right in software engineering; simplification doesn't work.
To be fair, it is an old language. Before Python 3, it used the old assumptions about text being just 1-byte characters. We all know how much trouble it was to switch to Unicode. At least it treats integers as true integers rather than your CPU's concept of an integer.
2021-02-27T00:00:00.000Z === 2021-02-27 if truncating.
But the day 2021-02-27, first of all starts and ends at different times, depending on your local timezone, but for me it's (in ISO8601 format) 2021-02-27T00:00:00.000+11/P24H.
To cover the whole world, it would be
2021-02-27T00:00+12/2021-02-27T23:59:59-12 or
2021-02-26T12:00Z/2021-02-28T11:59:59Z which is 48 hour duration :)
Pendulum does more. It has tools for manipulating a date. Add days, compare to other dates, etc.
Arrow appears primarily focused on parsing and formatting.
Each Arrow object has a `shift` method, which is how you can add or subtract units of time. Greater/less/equal comparisons work exactly as you'd expect them to.
I really wish improvements to python focused on things like this. Maybe an official higher level standard library for wrappers that focus on being nice to use like arrow, requests, envelopes, etc. (I know envelopes is not maintained but it was so nice)
[1] This needs elaboration. The local time zone is typically implemented by at least one of two ways: you read the central repository (`/etc/localtime` in Linux for example) every time local time is requested, or you listen to the time zone change event (`WM_SETTINGCHANGE` event in Windows for example). This is no different from your typical pan-process synchronization problem, which is complex and costly.
This is the main problem with python's builtin datetime module: the default is a kind of "localdate" or "localdatetime", and when you add a timezone it becomes an instant. It's a bad idea to conflate such two concepts.
OTOH arrow seems to think that "one size fits all". Which is bad as well :-/ I think joda time / java time design is good!
It parses from ISO8601, it has appropriate guards against coercing tz naive/aware instances and, unlike datetime, it behaves like ZonedDateTime, so tz aware instances are tied to instants. I would guess that it's faster than arrow-py or Pendulum, too, since it's part of Pandas, but don't have proof.
> The arrow of time, also called time's arrow, is the concept positing the "one-way direction" or "asymmetry" of time.
Fruit flies like bananas.
Okok I'm showing myself out...
One issue, though, is that the “correct” date-time representation is often use-case dependent.
There is a polyfill, but they recommend against production use.