classification
Title: isoformat() / fromisoformat() for datetime.timedelta
Type: Stage:
Components: Library (Lib) Versions: Python 3.10
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: Erik Cederstrand, martin.panter, p-ganssle
Priority: normal Keywords:

Created on 2020-10-20 07:13 by Erik Cederstrand, last changed 2020-11-18 06:00 by Erik Cederstrand.

Messages (5)
msg379091 - (view) Author: Erik Cederstrand (Erik Cederstrand) Date: 2020-10-20 07:13
Python 3.7 gained support for parsing ISO 8601 formatted time, date and datetime strings via the fromisoformat() methods. Python has seen improved support for ISO 8601 in general; ISO calendar format codes were added in Python 3.6, and fromisocalendar() was added in Python 3.8.

ISO 8601 also has a standard for durations: https://en.wikipedia.org/wiki/ISO_8601#Durations

For consistency with the other objects in the datetime module, I suggest adding isoformat()/fromisoformat() methods for datetime.timedelta that implement ISO 8601 durations.

ISO 8601 durations support years and months that are not valid timedelta arguments because they are non-precise durations. I suggest throwing an exception if the conversion to or from timedelta cannot be done safely.

https://pypi.org/project/isodate/ implements a parse_duration() method that could be used for inspiration.
msg379096 - (view) Author: Erik Cederstrand (Erik Cederstrand) Date: 2020-10-20 07:31
Among other things, ISO 8601 duration strings are commonly used to communicate offset values in timezone definitions.
msg379097 - (view) Author: Martin Panter (martin.panter) * (Python committer) Date: 2020-10-20 07:57
There is related discussion in Issue 41254, about duration formats more generally.
msg381273 - (view) Author: Paul Ganssle (p-ganssle) * (Python committer) Date: 2020-11-17 18:54
This is probably more feasible than the proposal in bpo-41254 since it's a well-defined spec (mostly — it includes an optional alternative format and the number of digits allowed is defined "by agreement", thus defeating the purpose of using a spec in the first place) that's not even particularly difficult to implement, but there are still a few problems (and one reason I've never implemented this, despite desperately wanting a better string representation for time deltas). Two minor problems first:

1. Unlike ISO 8601 datetimes, these are not especially "human-friendly" formats, so I don't think they're especially useful for displaying timedeltas.

2. Also unlike ISO 8601 datetimes, I don't think these are in particularly wide use, or widely supported. That's not a major strike against it, but if it's not useful as something to show to humans and it's not especially useful as something to show to / read from other computers, that weighs against its inclusion in the standard library.

The biggest problem, however, is that `timedelta` does not and cannot represent "Year" or "Month", which means that `P1Y` or `P1M` would always need to be invalid to parse. We could eliminate this format, but it means that we would never at any point in the future be able to implement a parser for the full spec. Since the concept of a year and a month are ambiguous and at least the 2016 version of ISO 8601 doesn't seem to define what it means for a duration to last 1 year or 1 month, you can't even really count on such a thing as an interchange format, because different implementations might give you different results! What does `20200131T00:00:00/P1M` represent? The interval (2020-01-31, 2020-02-29)? (2020-01-31, 2020-03-02)? Something else?

A better target for parsing ISO 8601 durations would be something like `dateutil.relativedelta`, which does have defined semantics for years and months (though as I mentioned above, those are not necessarily consistent with the semantics of other libraries parsing or writing out this format).

I am also not entirely clear on whether "weeks" is just an alias for "7 days" or if it means something related to weeks in the ISO calendar (and if that makes a difference for durations).

I imagine that generating these formats is a bit more forgiving, because you would simply never generate the forbidden formats, and we can offer configuration options in the formatter method to allow the user to tweak the various ambiguities in the spec.
msg381314 - (view) Author: Erik Cederstrand (Erik Cederstrand) Date: 2020-11-18 06:00
There are two conflicting interests: ISO 8601 that allows non-precise durations, and timedelta that assumes precise durations.

For me, the non-precise durations only make sense in date arithmetic - to a human, it's pretty clear what adding 3 months or a year will do to the date. There may be edge cases when crossing DST, but normal arithmetic with timezone also have those cases.

Regarding ISO weeks, I'm pretty sure that they are only special in regards to calculating week numbers and the weekday they start. They still have a duration of 7 days.

Apart from being able to parse ISO durations coming from other systems, the non-precise durations would be useful e.g. when implementing recurring events. Calculating a series of dates for something that happens on the 12th day of every 2nd month is doable in Python, but not with the aid of timedelta.

I see four options here:

1) expand timedelta to allow month and year, with the implication that e.g. total_seconds() would fail or be ambiguous for these timedeltas

2) implement only the parts of ISO 8601 that can safely be represented by the current timedelta

3) add a new relativetimedelta class that allows representing non-precise durations

4) do nothing and leave it to 3rd party packages to implement this
History
Date User Action Args
2020-11-18 06:00:30Erik Cederstrandsetmessages: + msg381314
2020-11-17 18:54:27p-gansslesetmessages: + msg381273
2020-11-17 18:31:06p-gansslesetnosy: + p-ganssle
2020-10-20 07:57:56martin.pantersetnosy: + martin.panter
messages: + msg379097
2020-10-20 07:31:20Erik Cederstrandsetmessages: + msg379096
2020-10-20 07:13:53Erik Cederstrandcreate