sdispater / pendulum

Python datetimes made easy
https://pendulum.eustace.io
MIT License
6.21k stars 384 forks source link

instance() fails for datetimes with pytz.FixedOffsets #807

Open patrickmckenna opened 7 months ago

patrickmckenna commented 7 months ago

Issue

pendulum.instance() errors if passed a datetime.datetime where tzinfo is a pytz._FixedOffset() instance, e.g.

>>> pendulum.instance(datetime.datetime(2021, 2, 3, tzinfo=pytz.FixedOffset(60))
... 
... )
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/opt/prefect/.venv/lib/python3.12/site-packages/pendulum/__init__.py", line 244, in instance
    return DateTime.instance(obj, tz=tz)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/prefect/.venv/lib/python3.12/site-packages/pendulum/datetime.py", line 133, in instance
    tz = pendulum._safe_timezone(tz, dt=dt)
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/prefect/.venv/lib/python3.12/site-packages/pendulum/__init__.py", line 124, in _safe_timezone
    return timezone(obj)
           ^^^^^^^^^^^^^
  File "/opt/prefect/.venv/lib/python3.12/site-packages/pendulum/__init__.py", line 83, in timezone
    if name.lower() == "utc":
       ^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'lower'

The error seems to originate here: https://github.com/sdispater/pendulum/blob/3e3fec6a5b66759078c5ae39c736ca95b78adbef/src/pendulum/__init__.py#L110-L111

pytz._FixedOffset does define a localize() method, but it also explicitly sets zone = None. (I'm not familiar enough with pytz, or datetime.tzinfo, conventions to have anything useful to say about whether this is surprising.)

FWIW, pendulum.UTC.convert() does handle pytz._FixedOffset properly. Unsure whether the fix is to reuse that same logic in _safe_timezone()?

Also, https://github.com/sdispater/pendulum/pull/158 did add some logic to handle pytz offsets, but it appears test cases using pytz.FixedOffset instances might have been removed?