Repository: collective/icalendar

Issue #609: Transition from pytz to zoneinfo
Created: 2024-03-27T19:04:15Z
In EOL of Python 3.8 is 31st October 2024. Then, zoneinfo is the library that is shipped with Python. There are problems using pytz as timezone implementations have evolved. My proposal to solve this issue is the following:

 create icalendar.set_default_timezone_implementation(TimeZone) where TimeZone can be pytz.Timezone or zoneinfo.ZoneInfo or others, taking a string like "UTC" or Europe/Berlin.
 Allow a switch from zoneinfo to pytz by testing all timezone dependent tests with both implementations
 a version 6 release after October will then switch from pytz to zoneinfo by setting another default and removing pytz altogether as a dependency. Tracked here: #630

What are your thoughts? Who thinks this will break existing code? What is needed for a transition?
See also:

#595
#532

Possibly related:

#336
#321

Code that needs touching:
The Timezone class contains logic to parse and create timezones from icalendar specifications:

  
    
      icalendar/src/icalendar/cal.py
    
    
         Line 545
      in
      2b1cd4e
    
  
  
    

        
          
           class Timezone(Component):

Duplicate issue #619: RFE: use `zoneinfo` instead of `pytz`
Created: 2024-05-29T18:33:28Z
Switch to standard zoneinfo module.
Below may help  pydantic/pydantic-core@fd262933
[tkloczko@pers-jacek icalendar-5.0.12]$ grep -r pytz
CHANGES.rst:- Fix tests for latest ``pytz``. Don't set ``tzinfo`` directly on datetime
CHANGES.rst:  objects, but use pytz's ``localize`` function. Ref #138.
CHANGES.rst:- Since we use pytz for timezones, also use UTC tzinfo object from the pytz
CHANGES.rst:  with timezone information from Python datetimes with pytz based timezone
README.rst::Dependencies: `python-dateutil`_ and `pytz`_.
README.rst:.. _`pytz`: https://pypi.org/project/pytz/
docs/usage.rst:    >>> import pytz
docs/usage.rst:    ...                               tzinfo=pytz.timezone("Europe/Vienna")))
docs/usage.rst:  >>> import pytz
docs/usage.rst:  >>> event.add('dtstart', datetime(2005,4,4,8,0,0,tzinfo=pytz.utc))
docs/usage.rst:  >>> event.add('dtend', datetime(2005,4,4,10,0,0,tzinfo=pytz.utc))
docs/usage.rst:  >>> event.add('dtstamp', datetime(2005,4,4,0,10,0,tzinfo=pytz.utc))
setup.py:    'pytz',
src/icalendar/parser.py:        tzid = dt.tzinfo.zone  # pytz implementation
src/icalendar/tests/test_equality.py:import pytz
src/icalendar/tests/test_equality.py:    except pytz.UnknownTimeZoneError:
src/icalendar/tests/test_equality.py:    except pytz.UnknownTimeZoneError:
src/icalendar/tests/test_period.py:import pytz
src/icalendar/tests/test_period.py:    assert start == pytz.timezone("America/Vancouver").localize(datetime.datetime(2023, 12, 13, 12))
src/icalendar/tests/test_period.py:    assert end == pytz.timezone("America/Vancouver").localize(datetime.datetime(2023, 12, 13, 15))
src/icalendar/tests/test_timezoned.py:import pytz
src/icalendar/tests/test_timezoned.py:    def test_create_from_ical_pytz(self):
src/icalendar/tests/test_timezoned.py:            pytz.timezone('Europe/Vienna').localize(
src/icalendar/tests/test_timezoned.py:            pytz.utc.localize(
src/icalendar/tests/test_timezoned.py:    def test_create_to_ical_pytz(self):
src/icalendar/tests/test_timezoned.py:        tz = pytz.timezone("Europe/Vienna")
src/icalendar/tests/test_timezoned.py:        pytz_new_york = pytz.timezone('America/New_York')
src/icalendar/tests/test_timezoned.py:        for num, date in enumerate(pytz_new_york._utc_transition_times):
src/icalendar/tests/test_timezoned.py:                ny_transition_info.append(pytz_new_york._transition_info[num])
src/icalendar/tests/test_unit_prop.py:import pytz
src/icalendar/tests/test_unit_prop.py:                         pytz.utc.localize(datetime(2001, 1, 1, 12, 30)))
src/icalendar/tests/test_unit_prop.py:        dutc = pytz.utc.localize(datetime(2001, 1, 1, 12, 30, 0))
src/icalendar/tests/test_unit_prop.py:        dutc = pytz.utc.localize(datetime(1899, 1, 1, 12, 30, 0))
src/icalendar/tests/test_unit_prop.py:        dk = pytz.timezone('Europe/Copenhagen')
src/icalendar/tests/test_unit_prop.py:    vDDDTypes(pytz.timezone('EST').localize(datetime(year=2022, month=7, day=22, hour=12, minute=7))),
src/icalendar/tests/test_unit_prop.py:        at = pytz.timezone('Europe/Vienna')
src/icalendar/tests/test_unit_prop.py:            pytz.timezone('America/New_York').localize(datetime(2017, 5, 7, 18, 19, 20))
src/icalendar/tests/test_unit_prop.py:        """test if all mappings actually map to valid pytz tzids"""
src/icalendar/tests/test_unit_prop.py:            pytz.timezone(olson)
src/icalendar/tests/conftest.py:import pytz
src/icalendar/tests/conftest.py:    pytz.utc,
src/icalendar/tests/conftest.py:    pytz.timezone('UTC'),
src/icalendar/tests/conftest.py:    lambda dt, tzname: pytz.timezone(tzname).localize(dt),
src/icalendar/tests/test_unit_cal.py:import pytz
src/icalendar/tests/test_unit_cal.py:    vienna = pytz.timezone("Europe/Vienna")
src/icalendar/tests/test_unit_cal.py:    comp.add('last-modified', pytz.utc.localize(
src/icalendar/cal.py:import pytz
src/icalendar/cal.py:from pytz.tzinfo import DstTzInfo
src/icalendar/cal.py:                value = value.astimezone(pytz.utc)
src/icalendar/cal.py:                value = pytz.utc.localize(value)
src/icalendar/cal.py:                        component['TZID'] not in pytz.all_timezones and \
src/icalendar/cal.py:                # pytz.timezones don't know any transition dates after 2038
src/icalendar/cal.py:                rrule._until = datetime(2038, 12, 31, tzinfo=pytz.UTC)
src/icalendar/cal.py:            # constructing the pytz-timezone requires UTC transition times.
src/icalendar/cal.py:        """convert this VTIMEZONE component to a pytz.timezone object
src/icalendar/prop.py:import pytz
src/icalendar/prop.py:    vDatetime is timezone aware and uses the pytz library, an implementation of
src/icalendar/prop.py:    ical string, you can pass a valid pytz timezone identifier. When a
src/icalendar/prop.py:                tzinfo = pytz.timezone(timezone.strip('/'))
src/icalendar/prop.py:            except pytz.UnknownTimeZoneError:
src/icalendar/prop.py:                    tzinfo = pytz.timezone(
src/icalendar/prop.py:                return pytz.utc.localize(datetime(*timetuple))

Closing comment (2024-05-29T20:50:20Z): Thanks for the report, but please search for existing issues. Closing as duplicate of #609. If that is not correct, please reopen with a reason this issue is not a duplicate. Thank you!