Re: [Python-Dev] Status on PEP-431 Timezones
On 15-04-08, Lennart Regebro wrote:
=== Stdlib option 2: A datetime _is_dst flag ===
By having a flag on the datetime instance that says "this is in DST or not" the timezone implementation can be kept simpler.
Storing the offset itself instead of a flag makes things conceptually cleaner. You get a representation that's slightly harder to construct from the sorts of information you have lying around (tz name, naive datetime, is_dst flag) but is no harder to construct *and* validate, and then is easier to work with and harder to misuse. As an added bonus, you get a representation that's still meaningful when time changes happen for political rather than DST reasons. Pros: - tzinfo.utcoffset() and local->UTC conversions don't require zoneinfo access. - it's harder to represent "I know this time is DST but I don't know what tz it's in" [I put this in pro because I don't see how this kind of ambiguity can lead to anything but trouble, but ymmv] - this representation is meaningful regardless of whether a time zone has DST - this representation meaningfully disambiguates across time changes not resulting from DST Cons: - tzinfo.dst() requires zoneinfo access - tzinfo.tzname() requires zoneinfo access IF you want those horrible ambiguous abbreviations (is CST America/Chicago or America/Havana?) [I really wanted to put this in pro] - (datetime, offset, tz) triples require validation [but so do (datetime, is_dst, tz) triples, even though it's easy to pretend they don't] - constructing an aware datetime from a naive one, an is_dst flag, and a time zone requires zoneinfo access [but this is needed for the validation step anyway] On 15-04-08, Alexander Belopolsky wrote:
With datetime, we also have a problem that POSIX APIs don't have to deal with: local time arithmetics. What is t + timedelta(1) when t falls on the day before DST change? How would you set the isdst flag in the result?
It's whatever time comes 60*60*24 seconds after t in the same time zone, because the timedelta class isn't expressive enough to represent anything but absolute time differences (nor should it be, IMO). But it might make sense to import dateutil.relativedelta or mxDateTime.RelativeDateTime into the stdlib to make relative time differences (same local time on the next day, for instance) possible. ijs
On Wed, Apr 8, 2015 at 9:57 PM, Isaac Schwabacher <ischwabacher@wisc.edu> wrote:
On 15-04-08, Lennart Regebro wrote:
=== Stdlib option 2: A datetime _is_dst flag ===
By having a flag on the datetime instance that says "this is in DST or not" the timezone implementation can be kept simpler.
Storing the offset itself instead of a flag makes things conceptually cleaner.
The concept would be pretty much the same, but yes, you would be able to save lookups in the dst() call, so that's a benefit. I was planning on storing the dst() offset at least lazily, but I'm not sure that means we can get rid of the flag.
As an added bonus, you get a representation that's still meaningful when time changes happen for political rather than DST reasons.
That's a good point. Although you would still have to use the is_dst flag to choose in that case, even if neither or both is actually DST. Unless we come up with another name for that flag, which I don't think is important. //Lennart
On Wed, Apr 8, 2015 at 3:57 PM, Isaac Schwabacher <ischwabacher@wisc.edu> wrote:
On 15-04-08, Lennart Regebro wrote:
=== Stdlib option 2: A datetime _is_dst flag ===
By having a flag on the datetime instance that says "this is in DST or
not"
the timezone implementation can be kept simpler.
Storing the offset itself instead of a flag makes things conceptually cleaner.
It is important to distinguish two notions that unfortunately both called a "time zone." For lack of better terms, let me define "named offsets" and "locations" as follows: A "named offset" is an abbreviation such as UTC, EST, MSK, MSD which (at any given time) corresponds to a fixed offset from UTC. Since at different historical times, the same abbreviation such as MSK may correspond to a different offset, you cannot always derive one from another and extended struct tm provides fields for both: tm_gmtoff and tm_zone. A location is a name of geographical entity such as America/New_York which follows the same timekeeping rules. The isdst flag is necessary when you know the location and local time and want to find out the corresponding UTC time. In many locations, there is one our every year when knowing local time is not enough because the same local time corresponds to two different UTC times. This happens in the US when we move the clock back one hour some day in the Fall. UTC time marches on, but local time repeats the same hour. So in order to know what 01:30 AM is in New York, you also need to know whether it is before we moved the clocks back or after. So "storing the offset" and "storing a flag" are not two alternative solutions to the same problem- these are two solutions to two different problems. ..
On 15-04-08, Alexander Belopolsky wrote:
With datetime, we also have a problem that POSIX APIs don't have to deal with: local time arithmetics. What is t + timedelta(1) when t falls on the day before DST change? How would you set the isdst flag in the result?
It's whatever time comes 60*60*24 seconds after t in the same time zone, because the timedelta class isn't expressive enough to represent anything but absolute time differences (nor should it be, IMO).
This is not what most uses expect. The expect datetime(y, m, d, 12, tzinfo=New_York) + timedelta(1) to be datetime(y, m, d+1, 12, tzinfo=New_York)
On Thu, Apr 9, 2015 at 8:32 AM, Alexander Belopolsky <alexander.belopolsky@gmail.com> wrote:
A "named offset" is an abbreviation such as UTC, EST, MSK, MSD which (at any given time) corresponds to a fixed offset from UTC.
That assumes the abbreviations are unique. They're not. Just this morning I had to explain to a new student of mine that no, my time zone is not "EST" = New York time, it's actually "EST" = Melbourne time. Granted, most of the time New York and Melbourne are opposite on DST, so one will be EST and one EDT, but that trick won't always help you. (BTW, thanks Lennart for your "Blame it on Caesar" PyCon talk. I linked my student to it as a "for further information" resource. Good fun, and a great summary of why political time is such a minefield.) If this proposal goes through, in some form or another, will there be One Obvious Way to do timezone-aware calculations in Python? That would definitely be an improvement. ChrisA
On Wed, Apr 8, 2015 at 7:32 PM, Chris Angelico <rosuav@gmail.com> wrote:
On Thu, Apr 9, 2015 at 8:32 AM, Alexander Belopolsky <alexander.belopolsky@gmail.com> wrote:
A "named offset" is an abbreviation such as UTC, EST, MSK, MSD which (at any given time) corresponds to a fixed offset from UTC.
That assumes the abbreviations are unique. They're not. Just this morning I had to explain to a new student of mine that no, my time zone is not "EST" = New York time, it's actually "EST" = Melbourne time. Granted, most of the time New York and Melbourne are opposite on DST, so one will be EST and one EDT, but that trick won't always help you.
I should have been more precise in my definitions. A "named offset" is a pair (tm_gmtoff, tm_zone). Given a location and a UTC time (UNIX timestamp), you should be able to produce a "named offset". $ TZ=Australia/Melbourne date -d @1428536256 +"%z %Z" +1000 EST The "name" part is usually redundant, but convenient for human readers. The opposite is not true: you cannot derive location from either or both parts.
Alexander Belopolsky <alexander.belopolsky@gmail.com> writes:
On Wed, Apr 8, 2015 at 3:57 PM, Isaac Schwabacher <ischwabacher@wisc.edu> wrote:
On 15-04-08, Alexander Belopolsky wrote:
With datetime, we also have a problem that POSIX APIs don't have to
deal with: local time
arithmetics. What is t + timedelta(1) when t falls on the day before DST change? How would you set the isdst flag in the result?
It's whatever time comes 60*60*24 seconds after t in the same time zone, because the timedelta class isn't expressive enough to represent anything but absolute time differences (nor should it be, IMO).
This is not what most uses expect. The expect
datetime(y, m, d, 12, tzinfo=New_York) + timedelta(1)
to be
datetime(y, m, d+1, 12, tzinfo=New_York)
It is incorrect. If you want d+1 for +timedelta(1); use a **naive** datetime. Otherwise +timedelta(1) is +24h: tomorrow = tz.localize(aware_dt.replace(tzinfo=None) + timedelta(1), is_dst=None) dt_plus24h = tz.normalize(aware_dt + timedelta(1)) # +24h *tomorrow* and *aware_dt* have the *same* time but it is unknown how many hours have passed if the utc offset has changed in between. *dt_plus24h* may have a different time but there are exactly 24 hours have passed between *dt_plush24* and *aware_dt* http://stackoverflow.com/questions/441147/how-can-i-subtract-a-day-from-a-py...
participants (5)
-
Akira Li
-
Alexander Belopolsky
-
Chris Angelico
-
Isaac Schwabacher
-
Lennart Regebro