Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

datetime.astimezone(None) does not set fold #103982

Open
pganssle opened this issue Apr 28, 2023 · 0 comments
Open

datetime.astimezone(None) does not set fold #103982

pganssle opened this issue Apr 28, 2023 · 0 comments
Labels
stdlib Python modules in the Lib dir type-bug An unexpected behavior, bug, or error

Comments

@pganssle
Copy link
Member

pganssle commented Apr 28, 2023

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:

  1. Create a time in UTC (time_utc)
  2. Convert it to local time with a fixed offset (time_local)
  3. Convert the local time with a fixed offset to a naïve local time.
  4. 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:

  1. Set fold on the result of .astimezone() so that .replace(tzinfo=None) gives you a "naïve local time".
  2. 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 some LOCAL 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.
  3. 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)

@pganssle pganssle added the type-bug An unexpected behavior, bug, or error label Apr 28, 2023
@iritkatriel iritkatriel added the stdlib Python modules in the Lib dir label Nov 26, 2023
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
stdlib Python modules in the Lib dir type-bug An unexpected behavior, bug, or error
Projects
Development

No branches or pull requests

2 participants