sdispater / pendulum

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

`Exception 'NoneType' object has no attribute 'replace'` when parsing specific dates #840

Open ssssam opened 2 months ago

ssssam commented 2 months ago

Issue

An exception is raised when parsing specific date times.

Current date time on my machine, in case that is relevant.

>>> pendulum.now()                                                                                                                                                                                                  
DateTime(2024, 8, 29, 16, 46, 14, 16970, tzinfo=Timezone('Europe/London')) 

Example of the bad case:

>>> pendulum.parse('Tue, 02 Mar 2024 06:00:00 GMT', tz="UTC", strict=False)                                                                                                                                         
Traceback (most recent call last):                                                                                                                                                                                  
  File "<stdin>", line 1, in <module>                                                                                                                                                                               
  File "/home/sam/flexget.venv/lib64/python3.12/site-packages/pendulum/parser.py", line 30, in parse                                                                                                                
    return _parse(text, **options)                                                                                                                                                                                  
           ^^^^^^^^^^^^^^^^^^^^^^^                                                                                                                                                                                  
  File "/home/sam/flexget.venv/lib64/python3.12/site-packages/pendulum/parser.py", line 46, in _parse                                                                                                               
    return pendulum.datetime(                                                                                                                                                                                       
           ^^^^^^^^^^^^^^^^^^                                                                                                                                                                                       
  File "/home/sam/flexget.venv/lib64/python3.12/site-packages/pendulum/__init__.py", line 143, in datetime                                                                                                          
    return DateTime.create(                                                                                                                                                                                         
           ^^^^^^^^^^^^^^^^                                                                                                                                                                                         
  File "/home/sam/flexget.venv/lib64/python3.12/site-packages/pendulum/datetime.py", line 103, in create                                                                                                            
    tz = pendulum._safe_timezone(tz)                                                                                                                                                                                
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^                                                                                                                                                                                
  File "/home/sam/flexget.venv/lib64/python3.12/site-packages/pendulum/__init__.py", line 112, in _safe_timezone                                                                                                    
    elif obj.tzname(None) == "UTC":                                                                                                                                                                                 
         ^^^^^^^^^^^^^^^^                                                                                                                                                                                           
  File "/home/sam/flexget.venv/lib64/python3.12/site-packages/dateutil/tz/tz.py", line 238, in tzname                                                                                                               
    return self._tznames[self._isdst(dt)]                                                                                                                                                                           
                         ^^^^^^^^^^^^^^^                                                                                                                                                                            
  File "/home/sam/flexget.venv/lib64/python3.12/site-packages/dateutil/tz/tz.py", line 291, in _isdst                                                                                                               
    dstval = self._naive_is_dst(dt)                                                                                                                                                                                 
             ^^^^^^^^^^^^^^^^^^^^^^                                                                                                                                                                                 
  File "/home/sam/flexget.venv/lib64/python3.12/site-packages/dateutil/tz/tz.py", line 259, in _naive_is_dst                                                                                                        
    timestamp = _datetime_to_timestamp(dt)                                                                                                                                                                          
                ^^^^^^^^^^^^^^^^^^^^^^^^^^                                                                                                                                                                          
  File "/home/sam/flexget.venv/lib64/python3.12/site-packages/dateutil/tz/tz.py", line 1814, in _datetime_to_timestamp                                                                                              
    return (dt.replace(tzinfo=None) - EPOCH).total_seconds()                                                                                                                                                        
            ^^^^^^^^^^                                                                                                                                                                                              
AttributeError: 'NoneType' object has no attribute 'replace'                                                                                                                                                        

Example of the good case:

>>> pendulum.parse('Tue, 02 Apr 2024 06:00:00 GMT', tz="UTC", strict=False)                                                                                                                                         
DateTime(2024, 4, 2, 6, 0, 0, tzinfo=Timezone('UTC'))          

This is affecting Flexget rss plugin, see: https://github.com/Flexget/Flexget/issues/4036

M117n commented 2 months ago

Im gonna try to work on this

M117n commented 2 months ago

I have tried to replicate the error using the same date and timezone configuration (Europe/London) in a Windows environment:

Operating System: Windows 11 Python: 3.9 Pendulum: 3.0.0 Date and time used: DateTime(2024, 8, 29, 16, 46, 14, 16970, tzinfo=Timezone('Europe/London')) Parsing result: 2024-03-02 06:00:00+00:00 without any errors.

This suggests that the issue might be specific to the Fedora 40 environment or related to differences in dependency configurations on that operating system.

ssssam commented 2 months ago

Thanks for confirming. Let me get a full ouptut of all package versions used in the venv and we can compare what is different. Here's output of pip3 freeze in the venv where I can reproduce this:

pendulum @ file:///home/sam/src/pendulum
python-dateutil==2.9.0.post0
six==1.16.0
time-machine==2.15.0
tzdata==2024.1

edit: I should also note the exact python version, which is this:

Name        : python3
Version     : 3.12.5
Release     : 1.fc40

It could also be a difference between Python 3.9 and Python 3.12 based on your results

ashirley commented 20 hours ago

Note that the TZ environment variable has an impact here. On debian bookworm I see the following:

root@48ff42b03f9d:/# unset TZ
root@48ff42b03f9d:/# python3 -c 'import pendulum; print(pendulum.parse("Tue, 02 Mar 2024 06:00:00 GMT", tz="UTC", strict=False))'
2024-03-02 06:00:00+00:00
root@48ff42b03f9d:/# TZ="UTC" python3 -c 'import pendulum; print(pendulum.parse("Tue, 02 Mar 2024 06:00:00 GMT", tz="UTC", strict=False))'
2024-03-02 06:00:00+00:00
root@48ff42b03f9d:/# TZ="Europe/London" python3 -c 'import pendulum; print(pendulum.parse("Tue, 02 Mar 2024 06:00:00 GMT", tz="UTC", strict=False))'
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/usr/local/lib/python3.11/dist-packages/pendulum/parser.py", line 30, in parse
    return _parse(text, **options)
           ^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/pendulum/parser.py", line 46, in _parse
    return pendulum.datetime(
           ^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/pendulum/__init__.py", line 143, in datetime
    return DateTime.create(
           ^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/pendulum/datetime.py", line 103, in create
    tz = pendulum._safe_timezone(tz)
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/pendulum/__init__.py", line 112, in _safe_timezone
    elif obj.tzname(None) == "UTC":
         ^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/dateutil/tz/tz.py", line 238, in tzname
    return self._tznames[self._isdst(dt)]
                         ^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/dateutil/tz/tz.py", line 291, in _isdst
    dstval = self._naive_is_dst(dt)
             ^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/dateutil/tz/tz.py", line 259, in _naive_is_dst
    timestamp = _datetime_to_timestamp(dt)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/dateutil/tz/tz.py", line 1814, in _datetime_to_timestamp
    return (dt.replace(tzinfo=None) - EPOCH).total_seconds()
            ^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'replace'