Description
At work today someone presented this problem (run with TZ=America/Los_Angeles):
>>> from datetime import datetime, utc
>>> time_utc = datetime(2023, 11, 5, 9, 15, tzinfo=UTC)
>>> (time_local := time_utc.astimezone())
datetime.datetime(2023, 11, 5, 1, 15, tzinfo=datetime.timezone(datetime.timedelta(days=-1, seconds=57600), 'PST'))
>>> print(time_local)
2023-11-05 01:15:00-08:00
>>> time_local_naive = time_local.replace(tzinfo=None)
>>> print(time_local_naive.astimezone())
2023-11-05 01:15:00-07:00
I think this is supposed to be equivalent to:
- Create a time in UTC (
time_utc
) - Convert it to local time with a fixed offset (
time_local
) - Convert the local time with a fixed offset to a naïve local time.
- Convert naïve local time to a local time with a fixed offset.
The problem is that step 3 doesn't work properly because step 2 isn't setting fold=1
. This is understandable, since the fixed offset zone doesn't need fold=1
, but because time_utc.astimezone(None)
creates a fixed-offset aware local time, we're not really providing a good way to go from an aware local time to a naïve local time (one that you can, e.g. do wall-time arithmetic on). It seems like the best way to go from aware → naïve local time is via .timestamp
:
>>> (time_local_naive_ts := datetime.fromtimestamp(time_local.timestamp()))
datetime.datetime(2023, 11, 5, 1, 15, fold=1)
>>> print(time_local_naive_ts.astimezone())
2023-11-05 01:15:00-08:00
It's not especially obvious that this is the right way to do it. I think the right way forward here is one of the following options:
- Set
fold
on the result of.astimezone()
so that.replace(tzinfo=None)
gives you a "naïve local time". - Add some mechanism to get a naïve local time from an aware datetime (in retrospect, it seems like maybe the current behavior should be the result of calling
.astimezone
with someLOCAL
sentinel object, and.astimezone()
should do what I'm asking for here, but it seems that ship has sailed). I guess this could either be a special sentinel or a new method like.asnaive()
or.aslocal()
or something. - Both 1 and 2.
I'm leaning towards starting with 1 if there's no fundamental reason we can't do it that way.
@abalkin Any thoughts on this?
(Tangentially related: #83861)
Linked PRs
Metadata
Metadata
Assignees
Projects
Status