diff -pruN 6.0.1-3/.github/FUNDING.yml 6.3.1-1/.github/FUNDING.yml
--- 6.0.1-3/.github/FUNDING.yml	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/.github/FUNDING.yml	2025-05-20 07:31:39.000000000 +0000
@@ -4,7 +4,7 @@ github: # Replace with up to 4 GitHub Sp
 patreon: # Replace with a single Patreon username
 open_collective: python-icalendar
 ko_fi: # Replace with a single Ko-fi username
-tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
+tidelift: pypi/icalendar # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
 community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
 liberapay: # Replace with a single Liberapay username
 issuehunt: # Replace with a single IssueHunt username
diff -pruN 6.0.1-3/.github/workflows/tests.yml 6.3.1-1/.github/workflows/tests.yml
--- 6.0.1-3/.github/workflows/tests.yml	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/.github/workflows/tests.yml	2025-05-20 07:31:39.000000000 +0000
@@ -25,6 +25,7 @@ jobs:
 #        - ["3.10",  "docs"]  # disable as readthedocs builds it
         - ["3.11",  "py311"]
         - ["3.12",  "py312"]
+        - ["3.13",  "py313"]
 
     runs-on: ubuntu-latest
     name: ${{ matrix.config[1] }}
@@ -79,7 +80,7 @@ jobs:
     - name: Set up Python
       uses: actions/setup-python@v5
       with:
-        python-version: "3.12"
+        python-version: "3.13"
     - name: Install dependencies
       run: |
         python -m pip install --upgrade pip
@@ -111,7 +112,7 @@ jobs:
     - name: Set up Python
       uses: actions/setup-python@v5
       with:
-        python-version: "3.12"
+        python-version: "3.13"
     - name: Install dependencies
       run: |
         python -m pip install --upgrade pip
diff -pruN 6.0.1-3/.pre-commit-config.yaml 6.3.1-1/.pre-commit-config.yaml
--- 6.0.1-3/.pre-commit-config.yaml	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/.pre-commit-config.yaml	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,13 @@
+repos:
+  - repo: https://github.com/pre-commit/pre-commit-hooks
+    rev: v5.0.0
+    hooks:
+      - id: debug-statements
+
+  - repo: https://github.com/astral-sh/ruff-pre-commit
+    rev: v0.11.9
+    hooks:
+      - id: ruff-check
+        args: [--config, "pyproject.toml", --fix]
+      - id: ruff-format
+        args: [--config, "pyproject.toml"]
diff -pruN 6.0.1-3/.readthedocs.yml 6.3.1-1/.readthedocs.yml
--- 6.0.1-3/.readthedocs.yml	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/.readthedocs.yml	2025-05-20 07:31:39.000000000 +0000
@@ -17,6 +17,9 @@ build:
   tools:
     python: "3.11"
   commands:
+    - git fetch --tags
+    - pip install build
+    - python -m build
     # Cancel building pull requests when there aren't changes in the docs directory or YAML file.
     # You can add any other files or directories that you'd like here as well,
     # like your docs requirements file, or other files that will change your docs build.
diff -pruN 6.0.1-3/CHANGES.rst 6.3.1-1/CHANGES.rst
--- 6.0.1-3/CHANGES.rst	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/CHANGES.rst	2025-05-20 07:31:39.000000000 +0000
@@ -1,18 +1,174 @@
 Changelog
 =========
 
+We use `Semantic Versioning <https://semver.org>`_.
+
+- Breaking changes increase the **major** version number.
+- New features increase the **minor** version number.
+- Minor changes and bug fixes increase the **patch** version number.
+
+6.3.1 (2025-05-20)
+------------------
+
+Bug fixes:
+
+- Remove forced quoting from parameters with space and single quote. See `Issue 836 <https://github.com/collective/icalendar/issues/836>`_.
+
+6.3.0 (2025-05-15)
+------------------
+
+Minor changes:
+
+- Deprecate ``icalendar.UIDGenerator``. See `Issue 816 <https://github.com/collective/icalendar/issues/816>`_.
+
+New features:
+
+- Add the ``uid`` property to ``Alarm``, ``Event``, ``Calendar``, ``Todo``, and ``Journal`` components. See `Issue 740 <https://github.com/collective/icalendar/issues/740>`_.
+
+Bug fixes:
+
+- Fix component equality where timezones differ for the datetimes but the times are actually equal. See `Issue 828 <https://github.com/collective/icalendar/issues/828>`_.
+- Test that we can add an RRULE as a string. See `Issue 301 <https://github.com/collective/icalendar/issues/301>`_.
+- Test that we support dateutil timezones as outlined in `Issue 336 <https://github.com/collective/icalendar/issues/336>`_.
+- Build documentation on Read the Docs with the version identifier. See `Issue 826 <https://github.com/collective/icalendar/issues/826>`_.
+
+6.2.0 (2025-05-07)
+------------------
+
+Minor changes:
+
+- Use ``ruff`` to format the source code.
+- Update project metadata to use License-Expression.
+- Use ``tzp.localize(dt, None)`` to remove the timezone from a datetime.
+- Remove the HTML documentation when building with ``tox`` to force rebuild.
+- Switch to PyData Sphinx Theme for documentation. See `Issue 803 <https://github.com/collective/icalendar/issues/804>`_.
+
+New features:
+
+- Add getters ``rrules``, ``rdates``, and ``exdates`` for unified and simple access to these properties. See `Issue 662`_.
+- Add attributes to the calendar for properties ``NAME``, ``DESCRIPTION``, and ``COLOR``. See `Issue 655 <https://github.com/collective/icalendar/issues/655>`_.
+- Add a ``color`` attribute to ``Event``, ``Todo``, and ``Journal`` components. See `Issue 655`_.
+- Add ``sequence`` attribute to ``Event``, ``Todo``, and ``Journal`` components. See `Issue 802 <https://github.com/collective/icalendar/issues/802>`_.
+- Add ``categories`` attribute to ``Calendar``, ``Event``, ``Todo``, and ``Journal`` components. See `Issue 655 <https://github.com/collective/icalendar/issues/655>`_.
+- Add compatibility to :rfc:`6868`. See `Issue 652 <https://github.com/collective/icalendar/issues/652>`_.
+- Add ``freebusy`` property to the ``Calendar`` to get this type of subcomponents easier.
+- Add parameters from :rfc:`5545` to properties ``ALTREP``, ``CN``, ``CUTYPE``, ``DELEGATED_FROM``, ``DELEGATED_TO``, ``DIR``, ``FBTYPE``, ``LANGUAGE``, ``MEMBER``, ``PARTSTAT``, ``RANGE``, ``RELATED``, ``ROLE``, ``RSVP``, ``SENT_BY``, ``TZID``, and ``RELTYPE``. See `Issue 798 <https://github.com/collective/icalendar/issues/798>`_.
+- New properties from :rfc:`7986` can occur multiple times in ``VCALENDAR``. See `PR 808`_.
+
+Bug fixes:
+
+- Fix ``STANDARD`` and ``DAYLIGHT`` components that have a date as ``DTSTART``. See `Issue 218 <https://github.com/collective/icalendar/issues/218>`_
+- Move import at the end of ``icalendar.parser`` into a function to mitigate import errors, see `Issue 781 <https://github.com/collective/icalendar/issues/781>`_.
+- ``ALTREP``, ``DELEGATED-FROM``, ``DELEGATED-TO``, ``DIR``, ``MEMBER``, and ``SENT-BY`` require double quotes. These are now always added.
+- Classify ``CATEGORIES`` as multiple in ``VEVENT``. See `PR 808 <https://github.com/collective/icalendar/pull/808>`_.
+
+6.1.3 (2025-03-19)
+------------------
+
+Bug fixes:
+
+- Fix to permit TZID forward references to VTIMEZONEs
+- Stabelize timezone id lookup, see `Issue 780 <https://github.com/collective/icalendar/issues/780>`_.
+
+6.1.2 (2025-03-19)
+------------------
+
+Minor changes:
+
+- Add funding link to Tidelift.
+- Link to related package.
+- Shorten first example in documentation.
+- Add ``name`` and ``email`` properties to ``vCalAddress``.
+- Add type hint for property ``params`` in ``icalendar.prop``.
+- Set default value for ``params`` as ``params={}`` in mulitple constructors in ``icalendar.prop`` to improve usability.
+- Improve object initialization performance in ``icalendar.prop``.
+- Add type hint for ``params`` in multiple constructors in ``icalendar.prop``.
+
+Bug fixes:
+
+- Restrict timezones tested, see `Issue 763 <https://github.com/collective/icalendar/issues/763>`_
+
+6.1.1 (2025-01-18)
+------------------
+
+Minor changes:
+
+- Add a ``weekday`` attribute to :class:`icalendar.prop.vWeekday` components. See `Issue 749 <https://github.com/collective/icalendar/issues/749>`_.
+- Document :class:`icalendar.prop.vRecur` property. See `Issue 758 <https://github.com/collective/icalendar/issues/758>`_.
+- Print failure of doctest to aid debugging.
+- Improve documentation of :class:`icalendar.prop.vGeo`
+- Fix tests, improve code readability, fix typing. See `Issue 766 <https://github.com/collective/icalendar/issues/766>`_ and `Issue 765 <https://github.com/collective/icalendar/issues/765>`_.
+
+Breaking changes:
+
+- The ``relative`` attribute of ``vWeekday`` components has the correct sign now. See `Issue 749 <https://github.com/collective/icalendar/issues/749>`_.
+
+New features:
+
+- Add :ref:`Security Policy`
+- Python types in documentation now link to their documentation pages using ``intersphinx``.
+
+6.1.0 (2024-11-22)
+------------------
+
+Minor changes:
+
+- Add ``end``, ``start``, ``duration``, ``DTSTART``, ``DUE``, and ``DURATION`` attributes to ``Todo`` components. See `Issue 662`_.
+- Add ``DTSTART``, ``TZOFFSETTO`` and ``TZOFFSETFROM`` properties to ``TimezoneStandard`` and ``TimezoneDaylight``. See `Issue 662`_.
+- Format test code with Ruff. See `Issue 672 <https://github.com/collective/icalendar/issues/672>`_.
+- Document the Debian package. See `Issue 701 <https://github.com/collective/icalendar/issues/701>`_.
+- Document ``vDatetime.from_ical``
+- Allow passing a ``datetime.date`` to ``TZP.localize_utc`` and ``TZP.localize`` methods.
+- Document component classes with description from :rfc:`5545`.
+- Merge "File Structure" and "Overview" sections in the docs. See `Issue 626 <https://github.com/collective/icalendar/issues/626>`_.
+- Update code blocks in ``usage.rst`` with the correct lexer.
+- Tidy up the docstring for ``icalendar.prop.vPeriod``.
+- Improve typing and fix typing issues
+
+
+New features:
+
+- Add ``VALARM`` properties for :rfc:`9074`. See `Issue 657 <https://github.com/collective/icalendar/issues/657>`_
+- Test compatibility with Python 3.13
+- Add ``Timezone.from_tzinfo()`` and ``Timezone.from_tzid()`` to create a ``Timezone`` component from a ``datetime.tzinfo`` timezone. See `Issue 722`_.
+- Add ``icalendar.prop.tzid_from_tzinfo``.
+- Add ``icalendar.alarms`` module to calculate alarm times. See `Issue 716 <https://github.com/collective/icalendar/issues/716>`_.
+- Add ``Event.alarms`` and ``Todo.alarms`` to access alarm calculation.
+- Add ``Component.DTSTAMP`` and ``Component.LAST_MODIFIED`` properties for datetime in UTC.
+- Add ``Component.is_thunderbird()`` to check if the component uses custom properties by Thunderbird.
+- Add ``X_MOZ_SNOOZE_TIME`` and ``X_MOZ_LASTACK`` properties to ``Event`` and ``Todo``.
+- Add ``Alarm.ACKNOWLEDGED``, ``Alarm.TRIGGER``, ``Alarm.REPEAT``, and ``Alarm.DURATION`` properties
+  as well as ``Alarm.triggers`` to calculate alarm triggers.
+- Add ``__doc__`` string documentation for ``vDate``, ``vBoolean``, ``vCalAddress``, ``vDuration``, ``vFloat``, ``vGeo``, ``vInt``, ``vPeriod``, ``vTime``, ``vUTCOffset`` and ``vUri``. See `Issue 742 <https://github.com/collective/icalendar/issues/742>`_.
+- Add ``DTSTART``, ``TZOFFSETTO``, and ``TZOFFSETFROM`` to ``TimezoneStandard`` and ``TimezoneDaylight``
+- Use ``example`` methods of components without arguments.
+- Add ``events``, ``timezones``, and ``todos`` property to ``Calendar`` for nicer access.
+- To calculate which timezones are in use and add them to the ``Calendar`` when needed these methods are added: ``get_used_tzids``, ``get_missing_tzids``, and ``add_missing_timezones``.
+- Identify the TZID of more timezones from dateutil.
+- Identify totally unknown timezones using a UTC offset lookup tree generated in ``icalendar.timezone.equivalent_timezone_ids`` and stored in ``icalendar.timezone.equivalent_timezone_ids``.
+- Add ``icalendar.timezone.tzid`` to identify a timezone's TZID.
+
+Bug fixes:
+
+- Add ``icalendar.timezone`` to the documentation.
+
+.. _`Issue 722`: https://github.com/collective/icalendar/issues/722
+
 6.0.1 (2024-10-13)
 ------------------
 
 New features:
 
-- Added ``Event.end``, ``Event.start``, ``Event.dtstart``, and ``Event.dtend`` attributes. See `Issue 662 <https://github.com/collective/icalendar/issues/662>`_.
+- Added ``end``, ``start``, ``duration``, ``DTSTART``, ``DUE``, and ``DURATION`` attributes to ``Event`` components. See `Issue 662`_.
+- Added ``end``, ``start``, ``duration``, and ``DTSTART`` attributes to ``Journal`` components. See `Issue 662`_.
 
 Bug fixes:
 
 - Fix a few ``__all__`` variables.
 - Added missing ``docs`` folder to distribution packages. See `Issue 712 <https://github.com/collective/icalendar/issues/712>`_.
 
+.. _`Issue 662`: https://github.com/collective/icalendar/issues/662
+
 6.0.0 (2024-09-28)
 ------------------
 
@@ -432,7 +588,6 @@ Bug fixes:
 
 - Use ``vText`` as default type, when convert recurrence definition to ical string. [kam193]
 
-
 4.0.5 (2020-03-21)
 ------------------
 
diff -pruN 6.0.1-3/CONTRIBUTING.rst 6.3.1-1/CONTRIBUTING.rst
--- 6.0.1-3/CONTRIBUTING.rst	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/CONTRIBUTING.rst	2025-05-20 07:31:39.000000000 +0000
@@ -18,12 +18,12 @@ For pull requests, keep this in mind
 
 - Add a test which proves your fix and make it pass.
 
-- Describe your change in CHANGES.rst
+- Describe your change in ``CHANGES.rst``
 
-- Add yourself to the docs/credits.rst
+- Add yourself to the ``docs/credits.rst``
 
-Development Setup
------------------
+Setup for Development
+---------------------
 
 If you would like to setup icalendar to
 contribute changes, the `Installation Section
diff -pruN 6.0.1-3/README.rst 6.3.1-1/README.rst
--- 6.0.1-3/README.rst	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/README.rst	2025-05-20 07:31:39.000000000 +0000
@@ -2,15 +2,16 @@
 Internet Calendaring and Scheduling (iCalendar) for Python
 ==========================================================
 
-The `icalendar`_ package is a `RFC 5545`_ compatible parser/generator for iCalendar
+The `icalendar`_ package is a :rfc:`5545` compatible parser/generator for iCalendar
 files.
 
 ----
 
 :Homepage: https://icalendar.readthedocs.io
+:Community Discussions: https://github.com/collective/icalendar/discussions
+:Issue Tracker: https://github.com/collective/icalendar/issues
 :Code: https://github.com/collective/icalendar
-:Mailing list: https://github.com/collective/icalendar/issues
-:Dependencies: `python-dateutil`_ and `pytz`_.
+:Dependencies: `python-dateutil`_ and `tzdata`_.
 :License: `BSD`_
 
 ----
@@ -41,9 +42,8 @@ files.
 
 
 .. _`icalendar`: https://pypi.org/project/icalendar/
-.. _`RFC 5545`: https://www.ietf.org/rfc/rfc5545.txt
 .. _`python-dateutil`: https://github.com/dateutil/dateutil/
-.. _`pytz`: https://pypi.org/project/pytz/
+.. _`tzdata`: https://pypi.org/project/tzdata/
 .. _`BSD`: https://github.com/collective/icalendar/issues/2
 
 Quick start guide
@@ -67,9 +67,8 @@ You can open an ``.ics`` file and see al
   >>> import icalendar
   >>> from pathlib import Path
   >>> ics_path = Path("src/icalendar/tests/calendars/example.ics")
-  >>> with ics_path.open() as f:
-  ...     calendar = icalendar.Calendar.from_ical(f.read())
-  >>> for event in calendar.walk('VEVENT'):
+  >>> calendar = icalendar.Calendar.from_ical(ics_path.read_bytes())
+  >>> for event in calendar.events:
   ...     print(event.get("SUMMARY"))
   New Year's Day
   Orthodox Christmas
@@ -82,21 +81,21 @@ Such a calendar can then be edited and s
 
 .. code:: python
 
-    >>> calendar["X-WR-CALNAME"] = "My Modified Calendar"  # modify
-    >>> print(calendar.to_ical()[:129])  # save modification
+    >>> calendar.calendar_name = "My Modified Calendar"  # modify
+    >>> print(calendar.to_ical()[:121])  # save modification
     BEGIN:VCALENDAR
     VERSION:2.0
     PRODID:collective/icalendar
     CALSCALE:GREGORIAN
     METHOD:PUBLISH
-    X-WR-CALNAME:My Modified Calendar
+    NAME:My Modified Calendar
 
 
 Create Events, TODOs, Journals, Alarms, ...
 -------------------------------------------
 
 ``icalendar`` supports the creation and parsing of all kinds of objects
-in the iCalendar (RFC 5545) standard.
+in the iCalendar (:rfc:`5545`) standard.
 
 .. code:: python
 
@@ -154,7 +153,7 @@ By default and since 6.0.0, ``zoneinfo``
 
 .. code:: python
 
-    >>> dt = icalendar.Calendar.example("timezoned").walk("VEVENT")[0]["DTSTART"].dt
+    >>> dt = icalendar.Calendar.example("timezoned").events[0].start
     >>> dt.tzinfo
     ZoneInfo(key='Europe/Vienna')
 
@@ -164,20 +163,22 @@ you can receive all the latest updates,
 .. code:: python
 
     >>> icalendar.use_pytz()
-    >>> dt = icalendar.Calendar.example("timezoned").walk("VEVENT")[0]["DTSTART"].dt
+    >>> dt = icalendar.Calendar.example("timezoned").events[0].start
     >>> dt.tzinfo
     <DstTzInfo 'Europe/Vienna' CET+1:00:00 STD>
 
 Version 6 is on `branch main <https://github.com/collective/icalendar/>`_.
-It is compatible with Python versions 3.8 - 3.12, and PyPy3.
+It is compatible with Python versions 3.8 - 3.13, and PyPy3.
 We expect the ``main`` branch with versions ``6+`` to receive the latest updates and features.
 
 Related projects
 ================
 
 * `icalevents <https://github.com/irgangla/icalevents>`_. It is built on top of icalendar and allows you to query iCal files and get the events happening on specific dates. It manages recurrent events as well.
-* `recurring-ical-events <https://pypi.org/project/recurring-ical-events/>`_. Library to query an ``ICalendar`` object for events happening at a certain date or within a certain time.
-* `x-wr-timezone <https://pypi.org/project/x-wr-timezone/>`_. Library to make ``ICalendar`` objects and files using the non-standard ``X-WR-TIMEZONE`` compliant with the standard (RFC 5545).
+* `recurring-ical-events <https://pypi.org/project/recurring-ical-events/>`_. Library to query an ``icalendar.Calendar`` object for events and other components happening at a certain date or within a certain time.
+* `x-wr-timezone <https://pypi.org/project/x-wr-timezone/>`_. Library and command line tool to make ``icalendar.Calendar`` objects and files from Google Calendar (using the non-standard ``X-WR-TIMEZONE`` property) compliant with the standard (:rfc:`5545`).
+* `ics-query <http://pypi.org/project/ics-query>`_. Command line tool to query iCalendar files for occurrences of events and other components.
+* `icalendar-compatibility <https://icalendar-compatibility.readthedocs.io/en/latest/>`_ - access to event data compatible with RFC5545 and different implementations
 
 Further Reading
 ===============
diff -pruN 6.0.1-3/SECURITY.md 6.3.1-1/SECURITY.md
--- 6.0.1-3/SECURITY.md	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/SECURITY.md	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,7 @@
+# Security Policy
+
+Please find our [security policy in the documentation](https://icalendar.readthedocs.io/en/latest/security.html).
+
+See also:
+
+- [docs/security.rst](docs/security.rst)
diff -pruN 6.0.1-3/bootstrap.py 6.3.1-1/bootstrap.py
--- 6.0.1-3/bootstrap.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/bootstrap.py	2025-05-20 07:31:39.000000000 +0000
@@ -27,7 +27,7 @@ from optparse import OptionParser
 
 tmpeggs = tempfile.mkdtemp()
 
-usage = '''\
+usage = """\
 [DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options]
 
 Bootstraps a buildout-based project.
@@ -37,28 +37,40 @@ Python that you want bin/buildout to use
 
 Note that by using --find-links to point to local resources, you can keep
 this script from going over the network.
-'''
+"""
 
 parser = OptionParser(usage=usage)
 parser.add_option("-v", "--version", help="use a specific zc.buildout version")
 
-parser.add_option("-t", "--accept-buildout-test-releases",
-                  dest='accept_buildout_test_releases',
-                  action="store_true", default=False,
-                  help=("Normally, if you do not specify a --version, the "
-                        "bootstrap script and buildout gets the newest "
-                        "*final* versions of zc.buildout and its recipes and "
-                        "extensions for you.  If you use this flag, "
-                        "bootstrap and buildout will get the newest releases "
-                        "even if they are alphas or betas."))
-parser.add_option("-c", "--config-file",
-                  help=("Specify the path to the buildout configuration "
-                        "file to be used."))
-parser.add_option("-f", "--find-links",
-                  help=("Specify a URL to search for buildout releases"))
-parser.add_option("--allow-site-packages",
-                  action="store_true", default=False,
-                  help=("Let bootstrap.py use existing site packages"))
+parser.add_option(
+    "-t",
+    "--accept-buildout-test-releases",
+    dest="accept_buildout_test_releases",
+    action="store_true",
+    default=False,
+    help=(
+        "Normally, if you do not specify a --version, the "
+        "bootstrap script and buildout gets the newest "
+        "*final* versions of zc.buildout and its recipes and "
+        "extensions for you.  If you use this flag, "
+        "bootstrap and buildout will get the newest releases "
+        "even if they are alphas or betas."
+    ),
+)
+parser.add_option(
+    "-c",
+    "--config-file",
+    help=("Specify the path to the buildout configuration " "file to be used."),
+)
+parser.add_option(
+    "-f", "--find-links", help=("Specify a URL to search for buildout releases")
+)
+parser.add_option(
+    "--allow-site-packages",
+    action="store_true",
+    default=False,
+    help=("Let bootstrap.py use existing site packages"),
+)
 
 
 options, args = parser.parse_args()
@@ -75,21 +87,22 @@ except ImportError:
     from urllib2 import urlopen
 
 ez = {}
-exec(urlopen('https://bootstrap.pypa.io/ez_setup.py').read(), ez)
+exec(urlopen("https://bootstrap.pypa.io/ez_setup.py").read(), ez)
 
 if not options.allow_site_packages:
     # ez_setup imports site, which adds site packages
     # this will remove them from the path to ensure that incompatible versions
     # of setuptools are not in the path
     import site
+
     # inside a virtualenv, there is no 'getsitepackages'.
     # We can't remove these reliably
-    if hasattr(site, 'getsitepackages'):
+    if hasattr(site, "getsitepackages"):
         for sitepackage_path in site.getsitepackages():
             sys.path[:] = [x for x in sys.path if sitepackage_path not in x]
 
-setup_args = {'to_dir': tmpeggs, 'download_delay': 0}
-ez['use_setuptools'](**setup_args)
+setup_args = {"to_dir": tmpeggs, "download_delay": 0}
+ez["use_setuptools"](**setup_args)
 import setuptools
 import pkg_resources
 
@@ -104,36 +117,43 @@ for path in sys.path:
 
 ws = pkg_resources.working_set
 
-cmd = [sys.executable, '-c',
-       'from setuptools.command.easy_install import main; main()',
-       '-mZqNxd', tmpeggs]
+cmd = [
+    sys.executable,
+    "-c",
+    "from setuptools.command.easy_install import main; main()",
+    "-mZqNxd",
+    tmpeggs,
+]
 
 find_links = os.environ.get(
-    'bootstrap-testing-find-links',
-    options.find_links or
-    ('https://downloads.buildout.org/'
-     if options.accept_buildout_test_releases else None)
-    )
+    "bootstrap-testing-find-links",
+    options.find_links
+    or (
+        "https://downloads.buildout.org/"
+        if options.accept_buildout_test_releases
+        else None
+    ),
+)
 if find_links:
-    cmd.extend(['-f', find_links])
+    cmd.extend(["-f", find_links])
 
-setuptools_path = ws.find(
-    pkg_resources.Requirement.parse('setuptools')).location
+setuptools_path = ws.find(pkg_resources.Requirement.parse("setuptools")).location
 
-requirement = 'zc.buildout'
+requirement = "zc.buildout"
 version = options.version
 if version is None and not options.accept_buildout_test_releases:
     # Figure out the most recent final version of zc.buildout.
     import setuptools.package_index
-    _final_parts = '*final-', '*final'
+
+    _final_parts = "*final-", "*final"
 
     def _final_version(parsed_version):
         for part in parsed_version:
-            if (part[:1] == '*') and (part not in _final_parts):
+            if (part.startswith("*")) and (part not in _final_parts):
                 return False
         return True
-    index = setuptools.package_index.PackageIndex(
-        search_path=[setuptools_path])
+
+    index = setuptools.package_index.PackageIndex(search_path=[setuptools_path])
     if find_links:
         index.add_find_links((find_links,))
     req = pkg_resources.Requirement.parse(requirement)
@@ -152,13 +172,13 @@ if version is None and not options.accep
             best.sort()
             version = best[-1].version
 if version:
-    requirement = '=='.join((requirement, version))
+    requirement = "==".join((requirement, version))
 cmd.append(requirement)
 
 import subprocess
+
 if subprocess.call(cmd, env=dict(os.environ, PYTHONPATH=setuptools_path)) != 0:
-    raise Exception(
-        "Failed to execute command:\n%s" % repr(cmd)[1:-1])
+    raise Exception("Failed to execute command:\n%s" % repr(cmd)[1:-1])
 
 ######################################################################
 # Import and run buildout
@@ -167,12 +187,12 @@ ws.add_entry(tmpeggs)
 ws.require(requirement)
 import zc.buildout.buildout
 
-if not [a for a in args if '=' not in a]:
-    args.append('bootstrap')
+if not [a for a in args if "=" not in a]:
+    args.append("bootstrap")
 
 # if -c was provided, we push it back into args for buildout' main function
 if options.config_file is not None:
-    args[0:0] = ['-c', options.config_file]
+    args[0:0] = ["-c", options.config_file]
 
 zc.buildout.buildout.main(args)
 shutil.rmtree(tmpeggs)
diff -pruN 6.0.1-3/debian/changelog 6.3.1-1/debian/changelog
--- 6.0.1-3/debian/changelog	2025-07-12 23:18:59.000000000 +0000
+++ 6.3.1-1/debian/changelog	2025-08-26 13:43:08.000000000 +0000
@@ -1,3 +1,10 @@
+python-icalendar (6.3.1-1) unstable; urgency=medium
+
+  * Team upload.
+  * New upstream release.
+
+ -- Colin Watson <cjwatson@debian.org>  Tue, 26 Aug 2025 14:43:08 +0100
+
 python-icalendar (6.0.1-3) unstable; urgency=medium
 
   * Team upload.
diff -pruN 6.0.1-3/debian/control 6.3.1-1/debian/control
--- 6.0.1-3/debian/control	2025-07-12 23:18:59.000000000 +0000
+++ 6.3.1-1/debian/control	2025-08-26 13:43:08.000000000 +0000
@@ -19,6 +19,7 @@ Build-Depends:
  python3-hatch-vcs,
  python3-hatchling,
  python3-hypothesis,
+ python3-pydata-sphinx-theme,
  python3-pytest,
  python3-pytz,
  python3-sphinx,
diff -pruN 6.0.1-3/debian/patches/2001_privacy.patch 6.3.1-1/debian/patches/2001_privacy.patch
--- 6.0.1-3/debian/patches/2001_privacy.patch	2025-07-12 23:18:59.000000000 +0000
+++ 6.3.1-1/debian/patches/2001_privacy.patch	2025-08-26 13:43:08.000000000 +0000
@@ -9,10 +9,10 @@ Last-Update: 2024-10-30
  1 file changed, 25 deletions(-)
 
 diff --git a/README.rst b/README.rst
-index 370ba27..0c30ff9 100644
+index 5d3c01c..5efc3a9 100644
 --- a/README.rst
 +++ b/README.rst
-@@ -15,31 +15,6 @@ files.
+@@ -16,31 +16,6 @@ files.
  
  ----
  
@@ -42,5 +42,5 @@ index 370ba27..0c30ff9 100644
 -
 -
  .. _`icalendar`: https://pypi.org/project/icalendar/
- .. _`RFC 5545`: https://www.ietf.org/rfc/rfc5545.txt
  .. _`python-dateutil`: https://github.com/dateutil/dateutil/
+ .. _`tzdata`: https://pypi.org/project/tzdata/
diff -pruN 6.0.1-3/debian/patches/build-uninstalled-docs.patch 6.3.1-1/debian/patches/build-uninstalled-docs.patch
--- 6.0.1-3/debian/patches/build-uninstalled-docs.patch	2025-07-12 23:18:59.000000000 +0000
+++ 6.3.1-1/debian/patches/build-uninstalled-docs.patch	2025-08-26 13:43:08.000000000 +0000
@@ -3,24 +3,25 @@ Date: Wed, 30 Oct 2024 14:12:22 +0000
 Subject: Handle building docs without installation
 
 Forwarded: not-needed
-Last-Update: 2024-10-30
+Last-Update: 2025-08-26
 ---
- docs/conf.py | 5 ++++-
- 1 file changed, 4 insertions(+), 1 deletion(-)
+ docs/conf.py | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
 
 diff --git a/docs/conf.py b/docs/conf.py
-index d3a67d1..500d967 100644
+index 351f842..7d147bd 100644
 --- a/docs/conf.py
 +++ b/docs/conf.py
-@@ -29,7 +29,10 @@ master_doc = 'index'
- project = 'icalendar'
+@@ -18,7 +18,11 @@ master_doc = "index"
+ project = "icalendar"
  this_year = datetime.date.today().year
- copyright = f'{this_year}, Plone Foundation'
--version = importlib.metadata.version('icalendar')
-+if 'DEB_VERSION_UPSTREAM' in os.environ:
-+    version = os.environ['DEB_VERSION_UPSTREAM']
+ copyright = f"{this_year}, Plone Foundation"
+-release = version = importlib.metadata.version("icalendar")
++if "DEB_VERSION_UPSTREAM" in os.environ:
++    version = os.environ["DEB_VERSION_UPSTREAM"]
 +else:
-+    version = importlib.metadata.version('icalendar')
- release = version
++    version = importlib.metadata.version("icalendar")
++release = version
  
- exclude_patterns = ['_build', 'lib', 'bin', 'include', 'local']
+ 
+ # -- Options for HTML output -------------------------------------------------
diff -pruN 6.0.1-3/debian/patches/remove-source-archive-url.patch 6.3.1-1/debian/patches/remove-source-archive-url.patch
--- 6.0.1-3/debian/patches/remove-source-archive-url.patch	2025-07-12 23:18:59.000000000 +0000
+++ 6.3.1-1/debian/patches/remove-source-archive-url.patch	2025-08-26 13:43:08.000000000 +0000
@@ -12,10 +12,10 @@ Last-Update: 2024-10-30
  1 file changed, 1 deletion(-)
 
 diff --git a/pyproject.toml b/pyproject.toml
-index af50f84..2052d3d 100644
+index cf80e43..d58fdf8 100644
 --- a/pyproject.toml
 +++ b/pyproject.toml
-@@ -102,7 +102,6 @@ exclude = [
+@@ -103,7 +103,6 @@ exclude = [
  # This is a dynamic generation of [project.urls]
  Homepage = "https://icalendar.readthedocs.io/"
  Repository = "https://github.com/collective/icalendar/"
diff -pruN 6.0.1-3/docs/Makefile 6.3.1-1/docs/Makefile
--- 6.0.1-3/docs/Makefile	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/docs/Makefile	2025-05-20 07:31:39.000000000 +0000
@@ -21,6 +21,7 @@ I18NSPHINXOPTS  = $(PAPEROPT_$(PAPER)) $
 help:
 	@echo "Please use \`make <target>' where <target> is one of"
 	@echo "  html       to make standalone HTML files"
+	@echo "  livehtml   to view a live preview of standalone HTML files"
 	@echo "  dirhtml    to make HTML files named index.html in directories"
 	@echo "  singlehtml to make a single large HTML file"
 	@echo "  pickle     to make pickle files"
@@ -163,6 +164,7 @@ doctest:
 
 livehtml:
 	$(SPHINXAUTOBUILD) \
+	--watch ../src \
 	--ignore "*.swp" \
 	--port 8050 \
 	-b html . "$(BUILDDIR)/html" $(SPHINXOPTS) $(O)
diff -pruN 6.0.1-3/docs/about.rst 6.3.1-1/docs/about.rst
--- 6.0.1-3/docs/about.rst	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/docs/about.rst	2025-05-20 07:31:39.000000000 +0000
@@ -7,7 +7,6 @@ iCalendar package for Python. The inspir
 in the standard lib, which he thinks is pretty simple, yet efficient and
 powerful.
 
-The ``icalendar`` package is an `RFC 5545 <https://tools.ietf.org/html/rfc5545>`
-compatible parser/generator for iCalendar files.
+The ``icalendar`` package is an :rfc:`5545` compatible parser/generator for iCalendar files.
 
 .. _`Max M`: http://www.mxm.dk
diff -pruN 6.0.1-3/docs/api.rst 6.3.1-1/docs/api.rst
--- 6.0.1-3/docs/api.rst	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/docs/api.rst	2025-05-20 07:31:39.000000000 +0000
@@ -1,6 +1,18 @@
 API Reference
 -------------
 
+icalendar.attr
+++++++++++++++
+
+.. automodule:: icalendar.attr
+   :members:
+
+icalendar.alarms
+++++++++++++++++
+
+.. automodule:: icalendar.alarms
+   :members:
+
 icalendar.cal
 +++++++++++++
 
@@ -19,6 +31,24 @@ icalendar.cli
 .. automodule:: icalendar.cli
    :members:
 
+icalendar.enums
++++++++++++++++
+
+.. automodule:: icalendar.enums
+   :members:
+
+icalendar.error
++++++++++++++++
+
+.. automodule:: icalendar.error
+   :members:
+
+icalendar.param
++++++++++++++++
+
+.. automodule:: icalendar.param
+   :members:
+
 icalendar.parser
 ++++++++++++++++
 
@@ -42,3 +72,21 @@ icalendar.tools
 
 .. automodule:: icalendar.tools
    :members:
+
+icalendar.timezone
+++++++++++++++++++
+
+.. automodule:: icalendar.timezone
+   :members:
+
+.. automodule:: icalendar.timezone.tzid
+   :members:
+
+.. automodule:: icalendar.timezone.tzp
+   :members:
+
+icalendar.version
++++++++++++++++++
+
+.. automodule:: icalendar.version
+   :members:
diff -pruN 6.0.1-3/docs/conf.py 6.3.1-1/docs/conf.py
--- 6.0.1-3/docs/conf.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/docs/conf.py	2025-05-20 07:31:39.000000000 +0000
@@ -3,41 +3,86 @@ import importlib.metadata
 import datetime
 import os
 
-on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
-
-try:
-    import sphinx_rtd_theme
-    html_theme = 'sphinx_rtd_theme'
-    html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
-except ImportError:
-    html_theme = 'default'
-    if not on_rtd:
-        print('-' * 74)
-        print('Warning: sphinx-rtd-theme not installed, building with default '
-              'theme.')
-        print('-' * 74)
-
 extensions = [
-    'sphinx.ext.autodoc',
-    'sphinx.ext.coverage',
-    'sphinx.ext.viewcode',
-    'sphinx_copybutton'
+    "sphinx.ext.autodoc",
+    "sphinx.ext.coverage",
+    "sphinx.ext.viewcode",
+    "sphinx_copybutton",
+    "sphinx.ext.intersphinx",
+    "sphinx.ext.autosectionlabel",
+    "sphinx.ext.napoleon",
 ]
-source_suffix = '.rst'
-master_doc = 'index'
+source_suffix = ".rst"
+master_doc = "index"
 
-project = 'icalendar'
+project = "icalendar"
 this_year = datetime.date.today().year
-copyright = f'{this_year}, Plone Foundation'
-version = importlib.metadata.version('icalendar')
-release = version
-
-exclude_patterns = ['_build', 'lib', 'bin', 'include', 'local']
-pygments_style = 'sphinx'
-
-htmlhelp_basename = 'icalendardoc'
-
-man_pages = [
-    ('index', 'icalendar', 'icalendar Documentation',
-     ['Plone Foundation'], 1)
-]
+copyright = f"{this_year}, Plone Foundation"
+release = version = importlib.metadata.version("icalendar")
+
+
+# -- Options for HTML output -------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages.  See the documentation for
+# a list of builtin themes.
+html_theme = "pydata_sphinx_theme"
+html_theme_options = {
+    "icon_links": [
+        {
+            "name": "GitHub",
+            "url": "https://github.com/collective/icalendar",
+            "icon": "fa-brands fa-square-github",
+            "type": "fontawesome",
+            "attributes": {
+                "target": "_blank",
+                "rel": "noopener me",
+                "class": "nav-link custom-fancy-css"
+            }
+        },
+        {
+            "name": "PyPI",
+            "url": "https://pypi.org/project/icalendar",
+            "icon": "fa-custom fa-pypi",
+            "type": "fontawesome",
+            "attributes": {
+                "target": "_blank",
+                "rel": "noopener me",
+                "class": "nav-link custom-fancy-css"
+            }
+        },
+    ],
+    "navigation_with_keys": True,
+    "search_bar_text": "Search",
+    "show_nav_level": 2,
+    "show_toc_level": 2,
+    "use_edit_page_button": True,
+}
+pygments_style = "sphinx"
+html_context = {
+#     "github_url": "https://github.com", # or your GitHub Enterprise site
+    "github_user": "collective",
+    "github_repo": "icalendar",
+    "github_version": "main",
+    "doc_path": "docs",
+}
+htmlhelp_basename = "icalendardoc"
+
+
+# -- Intersphinx configuration ----------------------------------
+
+# This extension can generate automatic links to the documentation of objects
+# in other projects. Usage is simple: whenever Sphinx encounters a
+# cross-reference that has no matching target in the current documentation set,
+# it looks for targets in the documentation sets configured in
+# intersphinx_mapping. A reference like :py:class:`zipfile.ZipFile` can then
+# linkto the Python documentation for the ZipFile class, without you having to
+# specify where it is located exactly.
+#
+# https://www.sphinx-doc.org/en/master/usage/extensions/intersphinx.html
+intersphinx_mapping = {
+    "python": ("https://docs.python.org/3", None),
+}
+
+
+man_pages = [("index", "icalendar", "icalendar Documentation", ["Plone Foundation"], 1)]
+
diff -pruN 6.0.1-3/docs/contributing.rst 6.3.1-1/docs/contributing.rst
--- 6.0.1-3/docs/contributing.rst	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/docs/contributing.rst	2025-05-20 07:31:39.000000000 +0000
@@ -1,5 +1,3 @@
-.. _contributing:
-
 ------------------
 Contributing
 ------------------
diff -pruN 6.0.1-3/docs/credits.rst 6.3.1-1/docs/credits.rst
--- 6.0.1-3/docs/credits.rst	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/docs/credits.rst	2025-05-20 07:31:39.000000000 +0000
@@ -76,6 +76,9 @@ icalendar contributors
 - `Steve Piercy <https://github.com/stevepiercy>`_
 - Jeffrey Whewhetu <jeffwhewhetu@gmail.com>
 - `Soham Dutta <https://github.com/NP-compete>`_
+- `Serif OZ  <https://github.com/SerifOZ>`_
+- David Venhoff <https://github.com/david-venhoff>
+- `Tariq <https://github.com/Horisyre>`_
 
 Find out who contributed::
 
diff -pruN 6.0.1-3/docs/index.rst 6.3.1-1/docs/index.rst
--- 6.0.1-3/docs/index.rst	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/docs/index.rst	2025-05-20 07:31:39.000000000 +0000
@@ -21,3 +21,4 @@ Contents
     :titlesonly:
 
     contributing
+    security
diff -pruN 6.0.1-3/docs/install.rst 6.3.1-1/docs/install.rst
--- 6.0.1-3/docs/install.rst	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/docs/install.rst	2025-05-20 07:31:39.000000000 +0000
@@ -1,6 +1,11 @@
 Installing iCalendar
 ====================
 
+You can install ``icalendar`` in several ways.
+
+Python Package with ``pip``
+---------------------------
+
 To install the icalendar package, use:
 
 .. code-block:: shell
@@ -14,6 +19,16 @@ package, like this:
 
     >>> import icalendar
 
+Debian or Ubuntu
+----------------
+
+You can install the `python-icalendar package <https://tracker.debian.org/pkg/python-icalendar>`_
+for Debian or its derivatives.
+
+.. code-block:: shell
+
+    sudo apt-get install python3-icalendar
+
 Development Setup
 -----------------
 
diff -pruN 6.0.1-3/docs/maintenance.rst 6.3.1-1/docs/maintenance.rst
--- 6.0.1-3/docs/maintenance.rst	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/docs/maintenance.rst	2025-05-20 07:31:39.000000000 +0000
@@ -62,6 +62,11 @@ However, only people with ``PyPI environ
 
 1. Check that the ``CHANGES.rst`` is up to date with the `latest merged pull requests <https://github.com/collective/icalendar/pulls?q=is%3Apr+is%3Amerged>`__
    and the version you want to release is correctly named.
+
+   .. code-block:: bash
+
+       export VERSION=6.3.0
+
 2. Create a commit on the ``release`` branch (or equivalent) to release this version.
 
    .. code-block:: bash
@@ -70,7 +75,7 @@ However, only people with ``PyPI environ
        git pull
        git checkout -b release main
        git add CHANGES.rst
-       git commit -m"version 6.0.0"
+       git commit -m"version $VERSION"
 
 3. Push the commit and `create a pull request <https://github.com/collective/icalendar/compare?expand=1>`__
    Here is an `example pull request #457 <https://github.com/collective/icalendar/pull/457>`__.
@@ -97,8 +102,8 @@ However, only people with ``PyPI environ
 
        git checkout main
        git pull
-       git tag v6.0.0
-       git push upstream v6.0.0 # could be origin or whatever reference
+       git tag "v$VERSION"
+       git push upstream "v$VERSION" # could be origin or whatever reference
 
 7. Once the tag is pushed and its `CI-tests`_ are passing, maintainers will get an e-mail::
 
@@ -110,7 +115,7 @@ However, only people with ``PyPI environ
    If that happens, notify the issues that were fixed about this release.
 9. Copy this to the start of ``CHANGES.rst``::
 
-       5.0.2 (unreleased)
+       6.3.1 (unreleased)
        ------------------
 
        Minor changes:
@@ -131,7 +136,7 @@ However, only people with ``PyPI environ
 
 10. Push the new CHANGELOG so it is used for future changes.
 
-   .. code-block:: bash
+    .. code-block:: bash
 
        git checkout main
        git pull
@@ -148,3 +153,16 @@ This section contains useful links for m
 
 - `Future of icalendar, looking for maintainer #360 <https://github.com/collective/icalendar/discussions/360>`__
 - `Comment on the Plone tests running with icalendar <https://github.com/collective/icalendar/pull/447#issuecomment-1277643634>`__
+
+Updating Python Versions
+------------------------
+
+When adding support for a new Python version or removing support for an old one, the following files need to be updated:
+
+1. ``.github/workflows/tests.yml``: Add or remove the Python version from the test matrix.
+2. ``tox.ini``: Update the ``envlist`` to include or remove the Python version.
+3. ``pyproject.toml``: Update the ``requires-python`` line and the ``classifiers`` list.
+4. ``README.rst``: Update the compatibility information.
+5. ``docs/maintenance.rst``: Update this list if any new files need to be modified.
+
+Remember to test the changes thoroughly and update any documentation that mentions supported Python versions.
diff -pruN 6.0.1-3/docs/security.rst 6.3.1-1/docs/security.rst
--- 6.0.1-3/docs/security.rst	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/docs/security.rst	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,58 @@
+Security Policy
+===============
+
+This documents the security policy and actions to take to secure the package and its deployment and use.
+
+Supported Versions
+------------------
+
+Security vulnerabilities are fixed only for the latest version of ``icalendar``.
+
+.. list-table:: Versions to receive security updates
+   :widths: 25 25
+   :header-rows: 1
+
+   * - Version
+     - Supported
+   * - 6.*
+     - YES
+   * - 5.*
+     - no
+   * - 4.*
+     - no
+   * - before 4.*
+     - no
+
+
+Reporting a Vulnerability
+-------------------------
+
+To report security issues of ``collective/icalendar``, use the ``Report a vulnerability`` button on the project's `Security Page <https://github.com/collective/icalendar/security>`_.
+If you cannot do this, please contact one of the :ref:`maintainers` directly.
+
+The maintainers of ``icalendar`` will then notify `Plone's security team <https://plone.org/security/report>`_.
+
+If we determine that your report may be a security issue with the project, we may contact you for further information.
+We volunteers ask that you delay public disclosure of your report for at least ninety (90) days from the date you report it to us.
+This will allow sufficient time for us to process your report and coordinate disclosure with you.
+
+Once verified and fixed, the following steps will be taken:
+
+-   We will use GitHub's Security Advisory tool to report the issue.
+-   GitHub will review our Security Advisory report for compliance with Common Vulnerabilities and Exposures (CVE) rules.
+    If it is compliant, they will submit it to the MITRE Corporation to generate a `CVE <https://www.cve.org/>`_.
+    This in turn submits the CVE to the `National Vulnerability Database (NVD) <https://nvd.nist.gov/vuln/search>`_.
+    GitHub notifies us of their decision.
+-   Assuming it is compliant, we then publish `our Security Advisory <https://github.com/collective/icalendar/security/advisories>`_ on GitHub, which triggers the next steps.
+-   GitHub will publish the CVE to the CVE List.
+-   GitHub will broadcast our Security Advisory via the `GitHub Advisory Database <https://github.com/advisories>`_.
+-   GitHub will send `security alerts <https://docs.github.com/en/code-security/supply-chain-security/managing-vulnerabilities-in-your-projects-dependencies/about-alerts-for-vulnerable-dependencies>`_ to all repositories that use our package (and have opted into security alerts).
+    This includes Dependabot alerts.
+-   We will make a bug-fix release.
+-   We will send an announcement through our usual channels:
+
+    - The :ref:`Changelog`
+    - The GitHub releases of ``icalendar``
+    - If possible also `Plone's Security Announcements <https://plone.org/security/announcements>`_
+
+-   We will provide credit to the reporter or researcher in the vulnerability notice.
diff -pruN 6.0.1-3/docs/usage.rst 6.3.1-1/docs/usage.rst
--- 6.0.1-3/docs/usage.rst	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/docs/usage.rst	2025-05-20 07:31:39.000000000 +0000
@@ -12,138 +12,152 @@ Compatibility
 
 This package is compatible with the following standards:
 
-- :rfc:`5545`
-- :rfc:`7529`
+- :rfc:`2445` - obsoleted by :rfc:`5545`
+- :rfc:`5545` - Internet Calendaring and Scheduling Core Object Specification (iCalendar)
+- :rfc:`6868` - Parameter Value Encoding in iCalendar and vCard
+- :rfc:`7529` - Non-Gregorian Recurrence Rules in the Internet Calendaring and Scheduling Core Object Specification (iCalendar)
+- :rfc:`9074` - "VALARM" Extensions for iCalendar
 
-We do not claim compatibility to:
+We do not claim compatibility to the following RFCs. They might work though.
 
-- :rfc:`2445` - which is obsoleted by :rfc:`5545`
-- :rfc:`6886`
-- :rfc:`7953`
-- :rfc:`7986`
-- :rfc:`9073`
-- :rfc:`9074`
-- :rfc:`9253`
+- :rfc:`7953` - Calendar Availability
+- :rfc:`7986` - New Properties for iCalendar
+- :rfc:`9073` - Event Publishing Extensions to iCalendar
+- :rfc:`9253` - Support for iCalendar Relationships
 
-File structure
---------------
+iCalendar file structure
+------------------------
 
-An iCalendar file is a text file (utf-8) with a special format. Basically it
-consists of content lines.
+An iCalendar file is a text file with UTF-8 character encoding in a special format.
 
-Each content line defines a property that has 3 parts (name, parameters,
-values). Parameters are optional.
+It consists of **content lines**,
+with each content line defining a property that has 3 parts: name, parameters, and values. Parameters are optional.
 
-A simple content line with only name and value could look like this::
+Example 1: a simple content line, with only name and value.
 
-  BEGIN:VCALENDAR
+.. code-block:: text
 
-A content line with parameters can look like this::
+    BEGIN:VCALENDAR
 
-  ATTENDEE;CN=Max Rasmussen;ROLE=REQ-PARTICIPANT:MAILTO:example@example.com
+Example 2: a content line with parameters.
 
-And the parts are::
+.. code-block:: text
 
-  Name:   ATTENDEE
-  Params: CN=Max Rasmussen;ROLE=REQ-PARTICIPANT
-  Value:  MAILTO:example@example.com
+    ATTENDEE;CN=Max Rasmussen;ROLE=REQ-PARTICIPANT:MAILTO:example@example.com
 
-Long content lines are usually "folded" to less than 75 character, but the
-package takes care of that.
+The parts in this example are the following.
 
+.. code-block:: text
 
-Overview
---------
+    Name:   ATTENDEE
+    Params: CN=Max Rasmussen;ROLE=REQ-PARTICIPANT
+    Value:  MAILTO:example@example.com
 
-On a higher level iCalendar files consists of components. Components can have
-sub components.
+For long content lines, iCalendar usually "folds" them to less than 75 characters.
 
-The root component is the VCALENDAR::
+On a higher level, you can think of iCalendar files' structure as having components and subcomponents.
 
-  BEGIN:VCALENDAR
-  ... vcalendar properties ...
-  END:VCALENDAR
+A component will have properties with values. The values
+have special types, like integer, text, and datetime. These values are
+encoded in a special text format in an iCalendar file. This package contains methods for converting to and from these encodings.
 
-The most frequent subcomponent to a VCALENDAR is a VEVENT. They are
-nested like this::
+Example 1: this is a VCALENDAR component representing a calendar.
 
-  BEGIN:VCALENDAR
-  ... vcalendar properties ...
-  BEGIN:VEVENT
-  ... vevent properties ...
-  END:VEVENT
-    END:VCALENDAR
+.. code-block:: text
 
-Inside the components there are properties with values. The values
-have special types. Like integer, text, datetime etc. these values are
-encoded in a special text format in an iCalendar file.
+    BEGIN:VCALENDAR
+    ... vcalendar properties ...
+    END:VCALENDAR
 
-There are methods for converting to and from these encodings in the package.
+Example 2: The most frequent subcomponent to a VCALENDAR component is a VEVENT. This is a VCALENDAR component with a nested VEVENT subcomponent.
 
-These are the most important imports::
+.. code-block:: text
 
-  >>> from icalendar import Calendar, Event
+    BEGIN:VCALENDAR
+    ... vcalendar properties ...
+    BEGIN:VEVENT
+    ... vevent properties ...
+    END:VEVENT
+    END:VCALENDAR
 
 
 Components
 ----------
 
+The remaining code snippets in the documentation will use the following important imports.
+
+.. code-block:: pycon
+
+    >>> from icalendar import Calendar, Event
+
 Components are like (Case Insensitive) dicts. So if you want to set a property
-you do it like this. The calendar is a component::
+you do it like this. The calendar is a component.
+
+.. code-block:: pycon
+
+    >>> cal = Calendar()
+    >>> cal['dtstart'] = '20050404T080000'
+    >>> cal['summary'] = 'Python meeting about calendaring'
+    >>> for k,v in cal.items():
+    ...     k,v
+    ('DTSTART', '20050404T080000')
+    ('SUMMARY', 'Python meeting about calendaring')
 
-  >>> cal = Calendar()
-  >>> cal['dtstart'] = '20050404T080000'
-  >>> cal['summary'] = 'Python meeting about calendaring'
-  >>> for k,v in cal.items():
-  ...     k,v
-  ('DTSTART', '20050404T080000')
-  ('SUMMARY', 'Python meeting about calendaring')
+NOTE: the recommended way to add components to the calendar is to
+create the subcomponent and add it via ``Calendar.add``! The example above adds a
+string, but not a ``vText`` component.
 
-NOTE: the recommended way to add components to the calendar is to use
-create the subcomponent and add it via Calendar.add! The example above adds a
-string, but not a vText component.
 
+You can generate a string for a file with the ``to_ical()`` method.
 
-You can generate a string for a file with the to_ical() method::
+.. code-block:: pycon
 
-  >>> cal.to_ical()
-  b'BEGIN:VCALENDAR\r\nDTSTART:20050404T080000\r\nSUMMARY:Python meeting about calendaring\r\nEND:VCALENDAR\r\n'
+    >>> cal.to_ical()
+    b'BEGIN:VCALENDAR\r\nDTSTART:20050404T080000\r\nSUMMARY:Python meeting about calendaring\r\nEND:VCALENDAR\r\n'
 
-The rendered view is easier to read::
+The rendered view is easier to read.
 
-  BEGIN:VCALENDAR
-  DTSTART:20050404T080000
-  SUMMARY:Python meeting about calendaring
-  END:VCALENDAR
+.. code-block:: pycon
+
+    BEGIN:VCALENDAR
+    DTSTART:20050404T080000
+    SUMMARY:Python meeting about calendaring
+    END:VCALENDAR
 
-So, let's define a function so we can easily display to_ical() output::
+So, let's define a function so we can easily display to_ical() output.
 
-  >>> def display(cal):
-  ...    return cal.to_ical().decode("utf-8").replace('\r\n', '\n').strip()
+.. code-block:: pycon
 
-You can set multiple properties like this::
+    >>> def display(cal):
+    ...    return cal.to_ical().decode("utf-8").replace('\r\n', '\n').strip()
 
-  >>> cal = Calendar()
-  >>> cal['attendee'] = ['MAILTO:maxm@mxm.dk','MAILTO:test@example.com']
-  >>> print(display(cal))
-  BEGIN:VCALENDAR
-  ATTENDEE:MAILTO:maxm@mxm.dk
-  ATTENDEE:MAILTO:test@example.com
-  END:VCALENDAR
+You can set multiple properties like this.
+
+.. code-block:: pycon
+
+    >>> cal = Calendar()
+    >>> cal['attendee'] = ['MAILTO:maxm@mxm.dk','MAILTO:test@example.com']
+    >>> print(display(cal))
+    BEGIN:VCALENDAR
+    ATTENDEE:MAILTO:maxm@mxm.dk
+    ATTENDEE:MAILTO:test@example.com
+    END:VCALENDAR
 
 If you don't want to care about whether a property value is a list or
 a single value, just use the add() method. It will automatically
 convert the property to a list of values if more than one value is
-added. Here is an example::
+added. Here is an example.
 
-  >>> cal = Calendar()
-  >>> cal.add('attendee', 'MAILTO:maxm@mxm.dk')
-  >>> cal.add('attendee', 'MAILTO:test@example.com')
-  >>> print(display(cal))
-  BEGIN:VCALENDAR
-  ATTENDEE:MAILTO:maxm@mxm.dk
-  ATTENDEE:MAILTO:test@example.com
-  END:VCALENDAR
+.. code-block:: pycon
+
+    >>> cal = Calendar()
+    >>> cal.add('attendee', 'MAILTO:maxm@mxm.dk')
+    >>> cal.add('attendee', 'MAILTO:test@example.com')
+    >>> print(display(cal))
+    BEGIN:VCALENDAR
+    ATTENDEE:MAILTO:maxm@mxm.dk
+    ATTENDEE:MAILTO:test@example.com
+    END:VCALENDAR
 
 Note: this version doesn't check for compliance, so you should look in
 the RFC 5545 spec for legal properties for each component, or look in
@@ -156,29 +170,35 @@ Subcomponents
 
 Any component can have subcomponents. Eg. inside a calendar there can
 be events.  They can be arbitrarily nested. First by making a new
-component::
+component.
+
+.. code-block:: pycon
 
-  >>> event = Event()
-  >>> event['uid'] = '42'
-  >>> event['dtstart'] = '20050404T080000'
-
-And then appending it to a "parent"::
-
-  >>> cal.add_component(event)
-  >>> print(display(cal))
-  BEGIN:VCALENDAR
-  ATTENDEE:MAILTO:maxm@mxm.dk
-  ATTENDEE:MAILTO:test@example.com
-  BEGIN:VEVENT
-  DTSTART:20050404T080000
-  UID:42
-  END:VEVENT
-  END:VCALENDAR
+    >>> event = Event()
+    >>> event['uid'] = '42'
+    >>> event['dtstart'] = '20050404T080000'
 
-Subcomponents are appended to the subcomponents property on the component::
+And then appending it to a "parent".
 
-  >>> cal.subcomponents
-  [VEVENT({'UID': '42', 'DTSTART': '20050404T080000'})]
+.. code-block:: pycon
+
+    >>> cal.add_component(event)
+    >>> print(display(cal))
+    BEGIN:VCALENDAR
+    ATTENDEE:MAILTO:maxm@mxm.dk
+    ATTENDEE:MAILTO:test@example.com
+    BEGIN:VEVENT
+    DTSTART:20050404T080000
+    UID:42
+    END:VEVENT
+    END:VCALENDAR
+
+Subcomponents are appended to the subcomponents property on the component.
+
+.. code-block:: pycon
+
+    >>> cal.subcomponents
+    [VEVENT({'UID': '42', 'DTSTART': '20050404T080000'})]
 
 
 Value types
@@ -196,12 +216,14 @@ yourself.
 
 To add a datetime value, you can use Pythons built in datetime types,
 and the set the encode parameter to true, and it will convert to the
-type defined in the spec::
+type defined in the spec.
+
+.. code-block:: pycon
 
-  >>> from datetime import datetime
-  >>> cal.add('dtstart', datetime(2005,4,4,8,0,0))
-  >>> cal['dtstart'].to_ical()
-  b'20050404T080000'
+    >>> from datetime import datetime
+    >>> cal.add('dtstart', datetime(2005,4,4,8,0,0))
+    >>> cal['dtstart'].to_ical()
+    b'20050404T080000'
 
 If that doesn't work satisfactorily for some reason, you can also do it
 manually.
@@ -209,12 +231,14 @@ manually.
 In 'icalendar.prop', all the iCalendar data types are defined. Each
 type has a class that can parse and encode the type.
 
-So if you want to do it manually::
+So if you want to do it manually.
 
-  >>> from icalendar import vDatetime
-  >>> now = datetime(2005,4,4,8,0,0)
-  >>> vDatetime(now).to_ical()
-  b'20050404T080000'
+.. code-block:: pycon
+
+    >>> from icalendar import vDatetime
+    >>> now = datetime(2005,4,4,8,0,0)
+    >>> vDatetime(now).to_ical()
+    b'20050404T080000'
 
 So the drill is to initialise the object with a python built in type,
 and then call the "to_ical()" method on the object. That will return an
@@ -222,23 +246,27 @@ ical encoded string.
 
 You can do it the other way around too. To parse an encoded string, just call
 the "from_ical()" method, and it will return an instance of the corresponding
-Python type::
+Python type.
+
+.. code-block:: pycon
 
-  >>> vDatetime.from_ical('20050404T080000')
-  datetime.datetime(2005, 4, 4, 8, 0)
+    >>> vDatetime.from_ical('20050404T080000')
+    datetime.datetime(2005, 4, 4, 8, 0)
 
-  >>> vDatetime.from_ical('20050404T080000Z')
-  datetime.datetime(2005, 4, 4, 8, 0, tzinfo=ZoneInfo(key='UTC'))
+    >>> vDatetime.from_ical('20050404T080000Z')
+    datetime.datetime(2005, 4, 4, 8, 0, tzinfo=ZoneInfo(key='UTC'))
 
 You can also choose to use the decoded() method, which will return a decoded
-value directly::
+value directly.
 
-  >>> cal = Calendar()
-  >>> cal.add('dtstart', datetime(2005,4,4,8,0,0))
-  >>> cal['dtstart'].to_ical()
-  b'20050404T080000'
-  >>> cal.decoded('dtstart')
-  datetime.datetime(2005, 4, 4, 8, 0)
+.. code-block:: pycon
+
+    >>> cal = Calendar()
+    >>> cal.add('dtstart', datetime(2005,4,4,8,0,0))
+    >>> cal['dtstart'].to_ical()
+    b'20050404T080000'
+    >>> cal.decoded('dtstart')
+    datetime.datetime(2005, 4, 4, 8, 0)
 
 
 Property parameters
@@ -246,7 +274,9 @@ Property parameters
 
 Property parameters are automatically added, depending on the input value. For
 example, for date/time related properties, the value type and timezone
-identifier (if applicable) are automatically added here::
+identifier (if applicable) are automatically added here.
+
+.. code-block:: pycon
 
     >>> import zoneinfo
     >>> event = Event()
@@ -260,7 +290,9 @@ identifier (if applicable) are automatic
 
 
 You can also add arbitrary property parameters by passing a parameters
-dictionary to the add method like so::
+dictionary to the add method like so.
+
+.. code-block:: pycon
 
     >>> event = Event()
     >>> event.add('X-TEST-PROP', 'tryout.',
@@ -275,116 +307,138 @@ Example
 Here is an example generating a complete iCal calendar file with a
 single event that can be loaded into the Mozilla calendar.
 
-Init the calendar::
+Initialize the calendar.
+
+.. code-block:: pycon
 
-  >>> cal = Calendar()
-  >>> from datetime import datetime
-  >>> import zoneinfo
+    >>> cal = Calendar()
+    >>> from datetime import datetime
+    >>> import zoneinfo
 
-Some properties are required to be compliant::
+Some properties are required to be compliant.
 
-  >>> cal.add('prodid', '-//My calendar product//mxm.dk//')
-  >>> cal.add('version', '2.0')
+.. code-block:: pycon
 
-We need at least one subcomponent for a calendar to be compliant::
+    >>> cal.add('prodid', '-//My calendar product//mxm.dk//')
+    >>> cal.add('version', '2.0')
 
-  >>> event = Event()
-  >>> event.add('summary', 'Python meeting about calendaring')
-  >>> event.add('dtstart', datetime(2005,4,4,8,0,0,tzinfo=zoneinfo.ZoneInfo("UTC")))
-  >>> event.add('dtend', datetime(2005,4,4,10,0,0,tzinfo=zoneinfo.ZoneInfo("UTC")))
-  >>> event.add('dtstamp', datetime(2005,4,4,0,10,0,tzinfo=zoneinfo.ZoneInfo("UTC")))
+We need at least one subcomponent for a calendar to be compliant.
 
-A property with parameters. Notice that they are an attribute on the value::
+.. code-block:: pycon
+
+    >>> event = Event()
+    >>> event.add('summary', 'Python meeting about calendaring')
+    >>> event.add('dtstart', datetime(2005,4,4,8,0,0,tzinfo=zoneinfo.ZoneInfo("UTC")))
+    >>> event.add('dtend', datetime(2005,4,4,10,0,0,tzinfo=zoneinfo.ZoneInfo("UTC")))
+    >>> event.add('dtstamp', datetime(2005,4,4,0,10,0,tzinfo=zoneinfo.ZoneInfo("UTC")))
 
-  >>> from icalendar import vCalAddress, vText
-  >>> organizer = vCalAddress('MAILTO:noone@example.com')
+A property with parameters. Notice that they are an attribute on the value.
+
+.. code-block:: pycon
+
+    >>> from icalendar import vCalAddress, vText
+    >>> organizer = vCalAddress('MAILTO:noone@example.com')
 
 Automatic encoding is not yet implemented for parameter values, so you
 must use the 'v*' types you can import from the icalendar package
-(they're defined in ``icalendar.prop``)::
+(they're defined in ``icalendar.prop``).
 
-  >>> organizer.params['cn'] = vText('Max Rasmussen')
-  >>> organizer.params['role'] = vText('CHAIR')
-  >>> event['organizer'] = organizer
-  >>> event['location'] = vText('Odense, Denmark')
-
-  >>> event['uid'] = '20050115T101010/27346262376@mxm.dk'
-  >>> event.add('priority', 5)
-
-  >>> attendee = vCalAddress('MAILTO:maxm@example.com')
-  >>> attendee.params['cn'] = vText('Max Rasmussen')
-  >>> attendee.params['ROLE'] = vText('REQ-PARTICIPANT')
-  >>> event.add('attendee', attendee, encode=0)
-
-  >>> attendee = vCalAddress('MAILTO:the-dude@example.com')
-  >>> attendee.params['cn'] = vText('The Dude')
-  >>> attendee.params['ROLE'] = vText('REQ-PARTICIPANT')
-  >>> event.add('attendee', attendee, encode=0)
-
-Add the event to the calendar::
-
-  >>> cal.add_component(event)
-
-By extending the event with subcomponents, you can create multiple alarms::
-
-  >>> from icalendar import Alarm
-  >>> from datetime import timedelta
-  >>> alarm_1h_before = Alarm()
-  >>> alarm_1h_before.add('action', 'DISPLAY')
-  >>> alarm_1h_before.add('trigger', timedelta(hours=-1))
-  >>> alarm_1h_before.add('description', 'Reminder: Event in 1 hour')
-  >>> event.add_component(alarm_1h_before)
-
-  >>> alarm_24h_before = Alarm()
-  >>> alarm_24h_before.add('action', 'DISPLAY')
-  >>> alarm_24h_before.add('trigger', timedelta(hours=-24))
-  >>> alarm_24h_before.add('description', 'Reminder: Event in 24 hours')
-  >>> event.add_component(alarm_24h_before)
-
-Or even recurrence::
-
-  >>> event.add('rrule', {'freq': 'daily'})
-
-Write to disk::
-
-  >>> import tempfile, os
-  >>> directory = tempfile.mkdtemp()
-  >>> f = open(os.path.join(directory, 'example.ics'), 'wb')
-  >>> f.write(cal.to_ical())
-  733
-  >>> f.close()
-
-Print out the calendar::
-
-  >>> print(cal.to_ical().decode('utf-8')) # doctest: +NORMALIZE_WHITESPACE
-  BEGIN:VCALENDAR
-  VERSION:2.0
-  PRODID:-//My calendar product//mxm.dk//
-  BEGIN:VEVENT
-  SUMMARY:Python meeting about calendaring
-  DTSTART:20050404T080000Z
-  DTEND:20050404T100000Z
-  DTSTAMP:20050404T001000Z
-  UID:20050115T101010/27346262376@mxm.dk
-  RRULE:FREQ=DAILY
-  ATTENDEE;CN="Max Rasmussen";ROLE=REQ-PARTICIPANT:MAILTO:maxm@example.com
-  ATTENDEE;CN="The Dude";ROLE=REQ-PARTICIPANT:MAILTO:the-dude@example.com
-  LOCATION:Odense\, Denmark
-  ORGANIZER;CN="Max Rasmussen";ROLE=CHAIR:MAILTO:noone@example.com
-  PRIORITY:5
-  BEGIN:VALARM
-  ACTION:DISPLAY
-  DESCRIPTION:Reminder: Event in 1 hour
-  TRIGGER:-PT1H
-  END:VALARM
-  BEGIN:VALARM
-  ACTION:DISPLAY
-  DESCRIPTION:Reminder: Event in 24 hours
-  TRIGGER:-P1D
-  END:VALARM
-  END:VEVENT
-  END:VCALENDAR
-  <BLANKLINE>
+.. code-block:: pycon
+
+    >>> organizer.params['cn'] = vText('Max Rasmussen')
+    >>> organizer.params['role'] = vText('CHAIR')
+    >>> event['organizer'] = organizer
+    >>> event['location'] = vText('Odense, Denmark')
+
+    >>> event['uid'] = '20050115T101010/27346262376@mxm.dk'
+    >>> event.add('priority', 5)
+
+    >>> attendee = vCalAddress('MAILTO:maxm@example.com')
+    >>> attendee.params['cn'] = vText('Max Rasmussen')
+    >>> attendee.params['ROLE'] = vText('REQ-PARTICIPANT')
+    >>> event.add('attendee', attendee, encode=0)
+
+    >>> attendee = vCalAddress('MAILTO:the-dude@example.com')
+    >>> attendee.params['cn'] = vText('The Dude')
+    >>> attendee.params['ROLE'] = vText('REQ-PARTICIPANT')
+    >>> event.add('attendee', attendee, encode=0)
+
+Add the event to the calendar.
+
+.. code-block:: pycon
+
+    >>> cal.add_component(event)
+
+By extending the event with subcomponents, you can create multiple alarms.
+
+.. code-block:: pycon
+
+    >>> from icalendar import Alarm
+    >>> from datetime import timedelta
+    >>> alarm_1h_before = Alarm()
+    >>> alarm_1h_before.add('action', 'DISPLAY')
+    >>> alarm_1h_before.add('trigger', timedelta(hours=-1))
+    >>> alarm_1h_before.add('description', 'Reminder: Event in 1 hour')
+    >>> event.add_component(alarm_1h_before)
+
+    >>> alarm_24h_before = Alarm()
+    >>> alarm_24h_before.add('action', 'DISPLAY')
+    >>> alarm_24h_before.add('trigger', timedelta(hours=-24))
+    >>> alarm_24h_before.add('description', 'Reminder: Event in 24 hours')
+    >>> event.add_component(alarm_24h_before)
+
+Or even recurrence, either from a dictionary or a string.
+Note that if you want to add the reccurence rule from a string, you must use the ``vRecur`` property.
+Otherwise the rule will be escaped, making it invalid.
+
+.. code-block:: pycon
+
+    >>> event.add('rrule', {'freq': 'daily'})
+
+Write to disk.
+
+.. code-block:: pycon
+
+    >>> import tempfile, os
+    >>> directory = tempfile.mkdtemp()
+    >>> f = open(os.path.join(directory, 'example.ics'), 'wb')
+    >>> f.write(cal.to_ical())
+    733
+    >>> f.close()
+
+Print out the calendar.
+
+.. code-block:: pycon
+
+    >>> print(cal.to_ical().decode('utf-8')) # doctest: +NORMALIZE_WHITESPACE
+    BEGIN:VCALENDAR
+    VERSION:2.0
+    PRODID:-//My calendar product//mxm.dk//
+    BEGIN:VEVENT
+    SUMMARY:Python meeting about calendaring
+    DTSTART:20050404T080000Z
+    DTEND:20050404T100000Z
+    DTSTAMP:20050404T001000Z
+    UID:20050115T101010/27346262376@mxm.dk
+    RRULE:FREQ=DAILY
+    ATTENDEE;CN="Max Rasmussen";ROLE=REQ-PARTICIPANT:MAILTO:maxm@example.com
+    ATTENDEE;CN="The Dude";ROLE=REQ-PARTICIPANT:MAILTO:the-dude@example.com
+    LOCATION:Odense\, Denmark
+    ORGANIZER;CN="Max Rasmussen";ROLE=CHAIR:MAILTO:noone@example.com
+    PRIORITY:5
+    BEGIN:VALARM
+    ACTION:DISPLAY
+    DESCRIPTION:Reminder: Event in 1 hour
+    TRIGGER:-PT1H
+    END:VALARM
+    BEGIN:VALARM
+    ACTION:DISPLAY
+    DESCRIPTION:Reminder: Event in 24 hours
+    TRIGGER:-P1D
+    END:VALARM
+    END:VEVENT
+    END:VCALENDAR
+    <BLANKLINE>
 
 More documentation
 ==================
diff -pruN 6.0.1-3/pyproject.toml 6.3.1-1/pyproject.toml
--- 6.0.1-3/pyproject.toml	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/pyproject.toml	2025-05-20 07:31:39.000000000 +0000
@@ -6,13 +6,13 @@
 #
 
 [build-system]
-requires = ["hatchling", "hatch-vcs"]
+requires = ["hatchling>=1.27.0", "hatch-vcs"]
 build-backend = "hatchling.build"
 
 [project]
 name = "icalendar"
-license = { file = "LICENSE.rst", name = "BSD-2-Clause" }
-#    name = "BSD-2-Clause", # TODO: is this the right short key
+license = "BSD-2-Clause"
+license-files = ["LICENSE.rst"]
 keywords = [
     "calendar",
     "calendaring",
@@ -65,6 +65,7 @@ classifiers = [
     "Programming Language :: Python :: 3.10",
     "Programming Language :: Python :: 3.11",
     "Programming Language :: Python :: 3.12",
+    "Programming Language :: Python :: 3.13",
     "Programming Language :: Python :: Implementation :: CPython",
     "Programming Language :: Python :: Implementation :: PyPy",
 ]
@@ -188,4 +189,14 @@ norecursedirs = [
     "src/icalendar/tests/hypothesis",
     "build",
 ]
+filterwarnings = [
+    "ignore::DeprecationWarning",
+]
+
+[dependency-groups]
+dev = [
+    "pydata-sphinx-theme>=0.14.4",
+    "sphinx-autobuild>=2021.3.14",
+    "sphinx-copybutton>=0.5.2",
+]
 
diff -pruN 6.0.1-3/requirements_docs.txt 6.3.1-1/requirements_docs.txt
--- 6.0.1-3/requirements_docs.txt	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/requirements_docs.txt	2025-05-20 07:31:39.000000000 +0000
@@ -1,5 +1,5 @@
-Sphinx>=1.2.3
-sphinx_rtd_theme
+Sphinx>=7
+pydata-sphinx-theme
 sphinx-autobuild
 sphinx-copybutton
 .
diff -pruN 6.0.1-3/src/icalendar/__init__.py 6.3.1-1/src/icalendar/__init__.py
--- 6.0.1-3/src/icalendar/__init__.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/__init__.py	2025-05-20 07:31:39.000000000 +0000
@@ -1,3 +1,7 @@
+from icalendar.alarms import (
+    Alarms,
+    AlarmTime,
+)
 from icalendar.cal import (
     Alarm,
     Calendar,
@@ -5,14 +9,22 @@ from icalendar.cal import (
     ComponentFactory,
     Event,
     FreeBusy,
-    IncompleteComponent,
-    InvalidCalendar,
     Journal,
     Timezone,
     TimezoneDaylight,
     TimezoneStandard,
     Todo,
 )
+from icalendar.enums import CUTYPE, FBTYPE, PARTSTAT, RANGE, RELATED, RELTYPE, ROLE
+from icalendar.error import (
+    ComponentEndMissing,
+    ComponentStartMissing,
+    FeatureWillBeRemovedInFutureVersion,
+    IncompleteAlarmInformation,
+    IncompleteComponent,
+    InvalidCalendar,
+    LocalTimezoneMissing,
+)
 
 # Parameters and helper methods for splitting and joining string with escaped
 # chars.
@@ -30,6 +42,7 @@ from icalendar.prop import (
     vCalAddress,
     vDate,
     vDatetime,
+    vDDDLists,
     vDDDTypes,
     vDuration,
     vFloat,
@@ -39,6 +52,7 @@ from icalendar.prop import (
     vMonth,
     vPeriod,
     vRecur,
+    vSkip,
     vText,
     vTime,
     vUri,
@@ -67,6 +81,7 @@ __all__ = [
     "vCalAddress",
     "vDatetime",
     "vDate",
+    "vDDDLists",
     "vDDDTypes",
     "vDuration",
     "vFloat",
@@ -94,4 +109,20 @@ __all__ = [
     "vMonth",
     "IncompleteComponent",
     "InvalidCalendar",
+    "Alarms",
+    "AlarmTime",
+    "ComponentEndMissing",
+    "ComponentStartMissing",
+    "IncompleteAlarmInformation",
+    "LocalTimezoneMissing",
+    "CUTYPE",
+    "FBTYPE",
+    "PARTSTAT",
+    "RANGE",
+    "vSkip",
+    "RELATED",
+    "vSkip",
+    "RELTYPE",
+    "ROLE",
+    "FeatureWillBeRemovedInFutureVersion"
 ]
diff -pruN 6.0.1-3/src/icalendar/alarms.py 6.3.1-1/src/icalendar/alarms.py
--- 6.0.1-3/src/icalendar/alarms.py	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/alarms.py	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,378 @@
+"""Compute the times and states of alarms.
+
+This takes different calendar software into account and the RFC 9074 (Alarm Extension).
+
+- RFC 9074 defines an ACKNOWLEDGED property in the VALARM.
+- Outlook does not export VALARM information.
+- Google Calendar uses the DTSTAMP to acknowledge the alarms.
+- Thunderbird snoozes the alarms with a X-MOZ-SNOOZE-TIME attribute in the event.
+- Thunderbird acknowledges the alarms with a X-MOZ-LASTACK attribute in the event.
+- Etar deletes alarms that are acknowledged.
+- Nextcloud's Webinterface does not do anything with the alarms when the time passes.
+"""
+
+from __future__ import annotations
+
+from datetime import date, timedelta, tzinfo
+from typing import TYPE_CHECKING, Generator, Optional, Union
+
+from icalendar.cal import Alarm, Event, Todo
+from icalendar.error import (
+    ComponentEndMissing,
+    ComponentStartMissing,
+    IncompleteAlarmInformation,
+    LocalTimezoneMissing,
+)
+from icalendar.timezone import tzp
+from icalendar.tools import is_date, normalize_pytz, to_datetime
+
+if TYPE_CHECKING:
+    from datetime import datetime
+
+Parent = Union[Event, Todo]
+
+
+class AlarmTime:
+    """An alarm time with all the information."""
+
+    def __init__(
+        self,
+        alarm: Alarm,
+        trigger: datetime,
+        acknowledged_until: Optional[datetime] = None,
+        snoozed_until: Optional[datetime] = None,
+        parent: Optional[Parent] = None,
+    ):
+        """Create a new AlarmTime.
+
+        alarm
+            the Alarm component
+
+        trigger
+            a date or datetime at which to trigger the alarm
+
+        acknowledged_until
+            an optional datetime in UTC until when all alarms
+            have been acknowledged
+
+        snoozed_until
+            an optional datetime in UTC until which all alarms of
+            the same parent are snoozed
+
+        parent
+            the optional parent component the alarm refers to
+
+        local_tzinfo
+            the local timezone that events without tzinfo should have
+        """
+        self._alarm = alarm
+        self._parent = parent
+        self._trigger = trigger
+        self._last_ack = acknowledged_until
+        self._snooze_until = snoozed_until
+
+    @property
+    def acknowledged(self) -> Optional[datetime]:
+        """The time in UTC at which this alarm was last acknowledged.
+
+        If the alarm was not acknowledged (dismissed), then this is None.
+        """
+        ack = self.alarm.ACKNOWLEDGED
+        if ack is None:
+            return self._last_ack
+        if self._last_ack is None:
+            return ack
+        return max(ack, self._last_ack)
+
+    @property
+    def alarm(self) -> Alarm:
+        """The alarm component."""
+        return self._alarm
+
+    @property
+    def parent(self) -> Optional[Parent]:
+        """This is the component that contains the alarm.
+
+        This is None if you did not use Alarms.set_component().
+        """
+        return self._parent
+
+    def is_active(self) -> bool:
+        """Whether this alarm is active (True) or acknowledged (False).
+
+        For example, in some calendar software, this is True until the user looks
+        at the alarm message and clicked the dismiss button.
+
+        Alarms can be in local time (without a timezone).
+        To calculate if the alarm really happened, we need it to be in a timezone.
+        If a timezone is required but not given, we throw an IncompleteAlarmInformation.
+        """
+        acknowledged = self.acknowledged
+        if not acknowledged:
+            # if nothing is acknowledged, this alarm counts
+            return True
+        if self._snooze_until is not None and self._snooze_until > acknowledged:
+            return True
+        trigger = self.trigger
+        if trigger.tzinfo is None:
+            raise LocalTimezoneMissing(
+                "A local timezone is required to check if the alarm is still active. "
+                "Use Alarms.set_local_timezone()."
+            )
+        return trigger > acknowledged
+
+    @property
+    def trigger(self) -> date:
+        """This is the time to trigger the alarm.
+
+        If the alarm has been snoozed, this can differ from the TRIGGER property.
+        """
+        if self._snooze_until is not None and self._snooze_until > self._trigger:
+            return self._snooze_until
+        return self._trigger
+
+
+class Alarms:
+    """Compute the times and states of alarms.
+
+    This is an example using RFC 9074.
+    One alarm is 30 minutes before the event and acknowledged.
+    Another alarm is 15 minutes before the event and still active.
+
+    >>> from icalendar import Event, Alarms
+    >>> event = Event.from_ical(
+    ... '''BEGIN:VEVENT
+    ... CREATED:20210301T151004Z
+    ... UID:AC67C078-CED3-4BF5-9726-832C3749F627
+    ... DTSTAMP:20210301T151004Z
+    ... DTSTART;TZID=America/New_York:20210302T103000
+    ... DTEND;TZID=America/New_York:20210302T113000
+    ... SUMMARY:Meeting
+    ... BEGIN:VALARM
+    ... UID:8297C37D-BA2D-4476-91AE-C1EAA364F8E1
+    ... TRIGGER:-PT30M
+    ... ACKNOWLEDGED:20210302T150004Z
+    ... DESCRIPTION:Event reminder
+    ... ACTION:DISPLAY
+    ... END:VALARM
+    ... BEGIN:VALARM
+    ... UID:8297C37D-BA2D-4476-91AE-C1EAA364F8E1
+    ... TRIGGER:-PT15M
+    ... DESCRIPTION:Event reminder
+    ... ACTION:DISPLAY
+    ... END:VALARM
+    ... END:VEVENT
+    ... ''')
+    >>> alarms = Alarms(event)
+    >>> len(alarms.times)   # all alarms including those acknowledged
+    2
+    >>> len(alarms.active)  # the alarms that are not acknowledged, yet
+    1
+    >>> alarms.active[0].trigger  # this alarm triggers 15 minutes before 10:30
+    datetime.datetime(2021, 3, 2, 10, 15, tzinfo=ZoneInfo(key='America/New_York'))
+
+    RFC 9074 specifies that alarms can also be triggered by proximity.
+    This is not implemented yet.
+    """
+
+    def __init__(self, component: Optional[Alarm | Event | Todo] = None):
+        """Start computing alarm times."""
+        self._absolute_alarms: list[Alarm] = []
+        self._start_alarms: list[Alarm] = []
+        self._end_alarms: list[Alarm] = []
+        self._start: Optional[date] = None
+        self._end: Optional[date] = None
+        self._parent: Optional[Parent] = None
+        self._last_ack: Optional[datetime] = None
+        self._snooze_until: Optional[datetime] = None
+        self._local_tzinfo: Optional[tzinfo] = None
+
+        if component is not None:
+            self.add_component(component)
+
+    def add_component(self, component: Alarm | Parent):
+        """Add a component.
+
+        If this is an alarm, it is added.
+        Events and Todos are added as a parent and all
+        their alarms are added, too.
+        """
+        if isinstance(component, (Event, Todo)):
+            self.set_parent(component)
+            self.set_start(component.start)
+            self.set_end(component.end)
+            if component.is_thunderbird():
+                self.acknowledge_until(component.X_MOZ_LASTACK)
+                self.snooze_until(component.X_MOZ_SNOOZE_TIME)
+            else:
+                self.acknowledge_until(component.DTSTAMP)
+
+        for alarm in component.walk("VALARM"):
+            self.add_alarm(alarm)
+
+    def set_parent(self, parent: Parent):
+        """Set the parent of all the alarms.
+
+        If you would like to collect alarms from a component, use add_component
+        """
+        if self._parent is not None and self._parent is not parent:
+            raise ValueError("You can only set one parent for this alarm calculation.")
+        self._parent = parent
+
+    def add_alarm(self, alarm: Alarm) -> None:
+        """Optional: Add an alarm component."""
+        trigger = alarm.TRIGGER
+        if trigger is None:
+            return
+        if isinstance(trigger, date):
+            self._absolute_alarms.append(alarm)
+        elif alarm.TRIGGER_RELATED == "START":
+            self._start_alarms.append(alarm)
+        else:
+            self._end_alarms.append(alarm)
+
+    def set_start(self, dt: Optional[date]):
+        """Set the start of the component.
+
+        If you have only absolute alarms, this is not required.
+        If you have alarms relative to the start of a compoment, set the start here.
+        """
+        self._start = dt
+
+    def set_end(self, dt: Optional[date]):
+        """Set the end of the component.
+
+        If you have only absolute alarms, this is not required.
+        If you have alarms relative to the end of a compoment, set the end here.
+        """
+        self._end = dt
+
+    def _add(self, dt: date, td: timedelta):
+        """Add a timedelta to a datetime."""
+        if is_date(dt):
+            if td.seconds == 0:
+                return dt + td
+            dt = to_datetime(dt)
+        return normalize_pytz(dt + td)
+
+    def acknowledge_until(self, dt: Optional[date]) -> None:
+        """This is the time in UTC when all the alarms of this component were acknowledged.
+
+        Only the last call counts.
+
+        Since RFC 9074 (Alarm Extension) was created later,
+        calendar implementations differ in how they acknowledge alarms.
+        For example, Thunderbird and Google Calendar store the last time
+        an event has been acknowledged because of an alarm.
+        All alarms that happen before this time count as acknowledged.
+        """
+        self._last_ack = tzp.localize_utc(dt) if dt is not None else None
+
+    def snooze_until(self, dt: Optional[date]) -> None:
+        """This is the time in UTC when all the alarms of this component were snoozed.
+
+        Only the last call counts.
+
+        The alarms are supposed to turn up again at dt when they are not acknowledged
+        but snoozed.
+        """
+        self._snooze_until = tzp.localize_utc(dt) if dt is not None else None
+
+    def set_local_timezone(self, tzinfo: Optional[tzinfo | str]):
+        """Set the local timezone.
+
+        Events are sometimes in local time.
+        In order to compute the exact time of the alarm, some
+        alarms without timezone are considered local.
+
+        Some computations work without setting this, others don't.
+        If they need this information, expect a LocalTimezoneMissing exception
+        somewhere down the line.
+        """
+        self._local_tzinfo = tzp.timezone(tzinfo) if isinstance(tzinfo, str) else tzinfo
+
+    @property
+    def times(self) -> list[AlarmTime]:
+        """Compute and return the times of the alarms given.
+
+        If the information for calculation is incomplete, this will raise a
+        IncompleteAlarmInformation exception.
+
+        Please make sure to set all the required parameters before calculating.
+        If you forget to set the acknowledged times, that is not problem.
+        """
+        return (
+            self._get_end_alarm_times()
+            + self._get_start_alarm_times()
+            + self._get_absolute_alarm_times()
+        )
+
+    def _repeat(self, first: datetime, alarm: Alarm) -> Generator[datetime]:
+        """The times when the alarm is triggered relative to start."""
+        yield first  # we trigger at the start
+        repeat = alarm.REPEAT
+        duration = alarm.DURATION
+        if repeat and duration:
+            for i in range(1, repeat + 1):
+                yield self._add(first, duration * i)
+
+    def _alarm_time(self, alarm: Alarm, trigger: date):
+        """Create an alarm time with the additional attributes."""
+        if getattr(trigger, "tzinfo", None) is None and self._local_tzinfo is not None:
+            trigger = normalize_pytz(trigger.replace(tzinfo=self._local_tzinfo))
+        return AlarmTime(
+            alarm, trigger, self._last_ack, self._snooze_until, self._parent
+        )
+
+    def _get_absolute_alarm_times(self) -> list[AlarmTime]:
+        """Return a list of absolute alarm times."""
+        return [
+            self._alarm_time(alarm, trigger)
+            for alarm in self._absolute_alarms
+            for trigger in self._repeat(alarm.TRIGGER, alarm)
+        ]
+
+    def _get_start_alarm_times(self) -> list[AlarmTime]:
+        """Return a list of alarm times relative to the start of the component."""
+        if self._start is None and self._start_alarms:
+            raise ComponentStartMissing(
+                "Use Alarms.set_start because at least one alarm is relative to the start of a component."
+            )
+        return [
+            self._alarm_time(alarm, trigger)
+            for alarm in self._start_alarms
+            for trigger in self._repeat(self._add(self._start, alarm.TRIGGER), alarm)
+        ]
+
+    def _get_end_alarm_times(self) -> list[AlarmTime]:
+        """Return a list of alarm times relative to the start of the component."""
+        if self._end is None and self._end_alarms:
+            raise ComponentEndMissing(
+                "Use Alarms.set_end because at least one alarm is relative to the end of a component."
+            )
+        return [
+            self._alarm_time(alarm, trigger)
+            for alarm in self._end_alarms
+            for trigger in self._repeat(self._add(self._end, alarm.TRIGGER), alarm)
+        ]
+
+    @property
+    def active(self) -> list[AlarmTime]:
+        """The alarm times that are still active and not acknowledged.
+
+        This considers snoozed alarms.
+
+        Alarms can be in local time (without a timezone).
+        To calculate if the alarm really happened, we need it to be in a timezone.
+        If a timezone is required but not given, we throw an IncompleteAlarmInformation.
+        """
+        return [alarm_time for alarm_time in self.times if alarm_time.is_active()]
+
+
+__all__ = [
+    "Alarms",
+    "AlarmTime",
+    "IncompleteAlarmInformation",
+    "ComponentEndMissing",
+    "ComponentStartMissing",
+]
diff -pruN 6.0.1-3/src/icalendar/attr.py 6.3.1-1/src/icalendar/attr.py
--- 6.0.1-3/src/icalendar/attr.py	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/attr.py	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,700 @@
+"""Attributes of Components and properties."""
+from __future__ import annotations
+
+import itertools
+from datetime import date, datetime, timedelta
+from typing import TYPE_CHECKING, Optional, Union
+
+from icalendar.error import InvalidCalendar
+from icalendar.prop import vCategory, vDDDTypes, vRecur, vText
+from icalendar.timezone import tzp
+
+if TYPE_CHECKING:
+    from icalendar.cal import Component
+
+
+def _get_rdates(self: Component) -> list[
+        Union[tuple[date, None],
+              tuple[datetime, None],
+              tuple[datetime, datetime]]]:
+    """The RDATE property defines the list of DATE-TIME values for recurring components.
+
+    RDATE is defined in :rfc:`5545`.
+    The return value is a list of tuples ``(start, end)``.
+
+    ``start`` can be a :class:`datetime.date` or a :class:`datetime.datetime`,
+    with and without timezone.
+
+    ``end`` is :obj:`None` if the end is not specified and a :class:`datetime.datetime`
+    if the end is specified.
+
+    Value Type:
+        The default value type for this property is DATE-TIME.
+        The value type can be set to DATE or PERIOD.
+
+    Property Parameters:
+        IANA, non-standard, value data type, and time
+        zone identifier property parameters can be specified on this
+        property.
+
+    Conformance:
+        This property can be specified in recurring "VEVENT",
+        "VTODO", and "VJOURNAL" calendar components as well as in the
+        "STANDARD" and "DAYLIGHT" sub-components of the "VTIMEZONE"
+        calendar component.
+
+    Description:
+        This property can appear along with the "RRULE"
+        property to define an aggregate set of repeating occurrences.
+        When they both appear in a recurring component, the recurrence
+        instances are defined by the union of occurrences defined by both
+        the "RDATE" and "RRULE".
+
+        The recurrence dates, if specified, are used in computing the
+        recurrence set.  The recurrence set is the complete set of
+        recurrence instances for a calendar component.  The recurrence set
+        is generated by considering the initial "DTSTART" property along
+        with the "RRULE", "RDATE", and "EXDATE" properties contained
+        within the recurring component.  The "DTSTART" property defines
+        the first instance in the recurrence set.  The "DTSTART" property
+        value SHOULD match the pattern of the recurrence rule, if
+        specified.  The recurrence set generated with a "DTSTART" property
+        value that doesn't match the pattern of the rule is undefined.
+        The final recurrence set is generated by gathering all of the
+        start DATE-TIME values generated by any of the specified "RRULE"
+        and "RDATE" properties, and then excluding any start DATE-TIME
+        values specified by "EXDATE" properties.  This implies that start
+        DATE-TIME values specified by "EXDATE" properties take precedence
+        over those specified by inclusion properties (i.e., "RDATE" and
+        "RRULE").  Where duplicate instances are generated by the "RRULE"
+        and "RDATE" properties, only one recurrence is considered.
+        Duplicate instances are ignored.
+
+    Example:
+        Below, we set one RDATE in a list and get the resulting tuple of start and end.
+
+        .. code-block:: pycon
+
+            >>> from icalendar import Event
+            >>> from datetime import datetime
+            >>> event = Event()
+
+            # Add a list of recurrence dates
+            >>> event.add("RDATE", [datetime(2025, 4, 28, 16, 5)])
+            >>> event.rdates
+            [(datetime.datetime(2025, 4, 28, 16, 5), None)]
+
+    .. note::
+
+        You cannot modify the RDATE value by modifying the result.
+        Use :func:`icalendar.cal.Component.add` to add values.
+
+        If you want to compute recurrences, have a look at :ref:`Related projects`.
+
+    """
+    result = []
+    rdates = self.get("RDATE", [])
+    for rdates in (rdates,) if not isinstance(rdates, list) else rdates:
+        for dts in rdates.dts:
+            rdate = dts.dt
+            if isinstance(rdate, tuple):
+                # we have a period as rdate
+                if isinstance(rdate[1], timedelta):
+                    result.append((rdate[0], rdate[0] + rdate[1]))
+                else:
+                    result.append(rdate)
+            else:
+                # we have a date/datetime
+                result.append((rdate, None))
+    return result
+
+
+rdates_property = property(_get_rdates)
+
+
+def _get_exdates(self: Component) -> list[date|datetime]:
+    """EXDATE defines the list of DATE-TIME exceptions for recurring components.
+
+    EXDATE is defined in :rfc:`5545`.
+
+    Value Type:
+        The default value type for this property is DATE-TIME.
+        The value type can be set to DATE.
+
+    Property Parameters:
+        IANA, non-standard, value data type, and time
+        zone identifier property parameters can be specified on this
+        property.
+
+    Conformance:
+        This property can be specified in recurring "VEVENT",
+        "VTODO", and "VJOURNAL" calendar components as well as in the
+        "STANDARD" and "DAYLIGHT" sub-components of the "VTIMEZONE"
+        calendar component.
+
+    Description:
+        The exception dates, if specified, are used in
+        computing the recurrence set.  The recurrence set is the complete
+        set of recurrence instances for a calendar component.  The
+        recurrence set is generated by considering the initial "DTSTART"
+        property along with the "RRULE", "RDATE", and "EXDATE" properties
+        contained within the recurring component.  The "DTSTART" property
+        defines the first instance in the recurrence set.  The "DTSTART"
+        property value SHOULD match the pattern of the recurrence rule, if
+        specified.  The recurrence set generated with a "DTSTART" property
+        value that doesn't match the pattern of the rule is undefined.
+        The final recurrence set is generated by gathering all of the
+        start DATE-TIME values generated by any of the specified "RRULE"
+        and "RDATE" properties, and then excluding any start DATE-TIME
+        values specified by "EXDATE" properties.  This implies that start
+        DATE-TIME values specified by "EXDATE" properties take precedence
+        over those specified by inclusion properties (i.e., "RDATE" and
+        "RRULE").  When duplicate instances are generated by the "RRULE"
+        and "RDATE" properties, only one recurrence is considered.
+        Duplicate instances are ignored.
+
+        The "EXDATE" property can be used to exclude the value specified
+        in "DTSTART".  However, in such cases, the original "DTSTART" date
+        MUST still be maintained by the calendaring and scheduling system
+        because the original "DTSTART" value has inherent usage
+        dependencies by other properties such as the "RECURRENCE-ID".
+
+    Example:
+        Below, we add an exdate in a list and get the resulting list of exdates.
+
+        .. code-block:: pycon
+
+            >>> from icalendar import Event
+            >>> from datetime import datetime
+            >>> event = Event()
+
+            # Add a list of excluded dates
+            >>> event.add("EXDATE", [datetime(2025, 4, 28, 16, 5)])
+            >>> event.exdates
+            [datetime.datetime(2025, 4, 28, 16, 5)]
+
+    .. note::
+
+        You cannot modify the EXDATE value by modifying the result.
+        Use :func:`icalendar.cal.Component.add` to add values.
+
+        If you want to compute recurrences, have a look at :ref:`Related projects`.
+
+    """
+    result = []
+    exdates = self.get("EXDATE", [])
+    for exdates in (exdates,) if not isinstance(exdates, list) else exdates:
+        for dts in exdates.dts:
+            exdate = dts.dt
+            # we have a date/datetime
+            result.append(exdate)
+    return result
+
+
+exdates_property = property(_get_exdates)
+
+
+def _get_rrules(self: Component) -> list[vRecur]:
+    """RRULE defines a rule or repeating pattern for recurring components.
+
+    RRULE is defined in :rfc:`5545`.
+    :rfc:`7529` adds the ``SKIP`` parameter :class:`icalendar.prop.vSkip`.
+
+    Property Parameters:
+        IANA and non-standard property parameters can
+        be specified on this property.
+
+    Conformance:
+        This property can be specified in recurring "VEVENT",
+        "VTODO", and "VJOURNAL" calendar components as well as in the
+        "STANDARD" and "DAYLIGHT" sub-components of the "VTIMEZONE"
+        calendar component, but it SHOULD NOT be specified more than once.
+        The recurrence set generated with multiple "RRULE" properties is
+        undefined.
+
+    Description:
+        The recurrence rule, if specified, is used in computing
+        the recurrence set.  The recurrence set is the complete set of
+        recurrence instances for a calendar component.  The recurrence set
+        is generated by considering the initial "DTSTART" property along
+        with the "RRULE", "RDATE", and "EXDATE" properties contained
+        within the recurring component.  The "DTSTART" property defines
+        the first instance in the recurrence set.  The "DTSTART" property
+        value SHOULD be synchronized with the recurrence rule, if
+        specified.  The recurrence set generated with a "DTSTART" property
+        value not synchronized with the recurrence rule is undefined.  The
+        final recurrence set is generated by gathering all of the start
+        DATE-TIME values generated by any of the specified "RRULE" and
+        "RDATE" properties, and then excluding any start DATE-TIME values
+        specified by "EXDATE" properties.  This implies that start DATE-
+        TIME values specified by "EXDATE" properties take precedence over
+        those specified by inclusion properties (i.e., "RDATE" and
+        "RRULE").  Where duplicate instances are generated by the "RRULE"
+        and "RDATE" properties, only one recurrence is considered.
+        Duplicate instances are ignored.
+
+        The "DTSTART" property specified within the iCalendar object
+        defines the first instance of the recurrence.  In most cases, a
+        "DTSTART" property of DATE-TIME value type used with a recurrence
+        rule, should be specified as a date with local time and time zone
+        reference to make sure all the recurrence instances start at the
+        same local time regardless of time zone changes.
+
+        If the duration of the recurring component is specified with the
+        "DTEND" or "DUE" property, then the same exact duration will apply
+        to all the members of the generated recurrence set.  Else, if the
+        duration of the recurring component is specified with the
+        "DURATION" property, then the same nominal duration will apply to
+        all the members of the generated recurrence set and the exact
+        duration of each recurrence instance will depend on its specific
+        start time.  For example, recurrence instances of a nominal
+        duration of one day will have an exact duration of more or less
+        than 24 hours on a day where a time zone shift occurs.  The
+        duration of a specific recurrence may be modified in an exception
+        component or simply by using an "RDATE" property of PERIOD value
+        type.
+
+    Examples:
+        Daily for 10 occurrences:
+
+        .. code-block:: pycon
+
+            >>> from icalendar import Event
+            >>> from datetime import datetime
+            >>> from zoneinfo import ZoneInfo
+            >>> event = Event()
+            >>> event.start = datetime(1997, 9, 2, 9, 0, tzinfo=ZoneInfo("America/New_York"))
+            >>> event.add("RRULE", "FREQ=DAILY;COUNT=10")
+            >>> print(event.to_ical())
+            BEGIN:VEVENT
+            DTSTART;TZID=America/New_York:19970902T090000
+            RRULE:FREQ=DAILY;COUNT=10
+            END:VEVENT
+            >>> event.rrules
+            [vRecur({'FREQ': ['DAILY'], 'COUNT': [10]})]
+
+        Daily until December 24, 1997:
+
+        .. code-block:: pycon
+
+            >>> from icalendar import Event, vRecur
+            >>> from datetime import datetime
+            >>> from zoneinfo import ZoneInfo
+            >>> event = Event()
+            >>> event.start = datetime(1997, 9, 2, 9, 0, tzinfo=ZoneInfo("America/New_York"))
+            >>> event.add("RRULE", vRecur({"FREQ": ["DAILY"]}, until=datetime(1997, 12, 24, tzinfo=ZoneInfo("UTC"))))
+            >>> print(event.to_ical())
+            BEGIN:VEVENT
+            DTSTART;TZID=America/New_York:19970902T090000
+            RRULE:FREQ=DAILY;UNTIL=19971224T000000Z
+            END:VEVENT
+            >>> event.rrules
+            [vRecur({'FREQ': ['DAILY'], 'UNTIL': [datetime.datetime(1997, 12, 24, 0, 0, tzinfo=ZoneInfo(key='UTC'))]})]
+
+    .. note::
+
+        You cannot modify the RRULE value by modifying the result.
+        Use :func:`icalendar.cal.Component.add` to add values.
+
+        If you want to compute recurrences, have a look at :ref:`Related projects`.
+
+    """
+    rrules = self.get("RRULE", [])
+    if not isinstance(rrules, list):
+        return [rrules]
+    return rrules
+
+
+rrules_property = property(_get_rrules)
+
+def multi_language_text_property(main_prop:str, compatibility_prop:str, doc:str) -> property:
+    """This creates a text property.
+
+    This property can be defined several times with different ``LANGUAGE`` parameters.
+
+    Args:
+        main_prop (str): The property to set and get, such as ``NAME``
+        compatibility_prop (str): An old property used before, such as ``X-WR-CALNAME``
+        doc (str): The documentation string
+    """
+    def fget(self: Component) -> Optional[str]:
+        """Get the property"""
+        result = self.get(main_prop, self.get(compatibility_prop))
+        if isinstance(result, list):
+            for item in result:
+                if "LANGUAGE" not in item.params:
+                    return item
+        return result
+
+    def fset(self: Component, value:str):
+        """Set the property."""
+        fdel(self)
+        self.add(main_prop, value)
+
+    def fdel(self: Component):
+        """Delete the property."""
+        self.pop(main_prop, None)
+        self.pop(compatibility_prop, None)
+
+    return property(fget, fset, fdel, doc)
+
+
+def single_int_property(prop:str, default:int, doc:str) -> property:
+    """Create a property for an int value that exists only once.
+
+    Args:
+        prop: The name of the property
+        default: The default value
+        doc: The documentation string
+    """
+    def fget(self: Component) -> int:
+        """Get the property"""
+        try:
+            return int(self.get(prop, default))
+        except ValueError as e:
+            raise InvalidCalendar(f"{prop} must be an int") from e
+
+    def fset(self: Component, value:int):
+        """Set the property."""
+        fdel(self)
+        self.add(prop, value)
+
+    def fdel(self: Component):
+        """Delete the property."""
+        self.pop(prop, None)
+
+    return property(fget, fset, fdel, doc)
+
+
+def single_utc_property(name: str, docs: str) -> property:
+    """Create a property to access a value of datetime in UTC timezone.
+
+    Args:
+        name: name of the property
+        docs: documentation string
+    """
+    docs = (
+        f"""The {name} property. datetime in UTC
+
+    All values will be converted to a datetime in UTC.
+    """
+        + docs
+    )
+
+    def fget(self: Component) -> Optional[datetime]:
+        """Get the value."""
+        if name not in self:
+            return None
+        dt = self.get(name)
+        if isinstance(dt, vText):
+            # we might be in an attribute that is not typed
+            value = vDDDTypes.from_ical(dt)
+        else:
+            value = getattr(dt, "dt", None)
+        if value is None or not isinstance(value, date):
+            raise InvalidCalendar(f"{name} must be a datetime in UTC, not {value}")
+        return tzp.localize_utc(value)
+
+    def fset(self: Component, value: datetime):
+        """Set the value"""
+        if not isinstance(value, date):
+            raise TypeError(f"{name} takes a datetime in UTC, not {value}")
+        fdel(self)
+        self.add(name, tzp.localize_utc(value))
+
+    def fdel(self: Component):
+        """Delete the property."""
+        self.pop(name, None)
+
+    return property(fget, fset, fdel, doc=docs)
+
+
+def single_string_property(name: str, docs: str, other_name:Optional[str]=None) -> property:
+    """Create a property to access a single string value."""
+
+    def fget(self: Component) -> str:
+        """Get the value."""
+        result = self.get(name, None if other_name is None else self.get(other_name, None))
+        if result is None or result == []:
+            return ""
+        if isinstance(result, list):
+            return result[0]
+        return result
+
+    def fset(self: Component, value: str):
+        """Set the value"""
+        fdel(self)
+        self.add(name, value)
+
+    def fdel(self: Component):
+        """Delete the property."""
+        self.pop(name, None)
+        if other_name is not None:
+            self.pop(other_name, None)
+
+    return property(fget, fset, fdel, doc=docs)
+
+color_property = single_string_property(
+    "COLOR",
+    """This property specifies a color used for displaying the component.
+
+    This implements :rfc:`7986` ``COLOR`` property.
+
+    Property Parameters:
+        IANA and non-standard property parameters can
+        be specified on this property.
+
+    Conformance:
+        This property can be specified once in an iCalendar
+        object or in ``VEVENT``, ``VTODO``, or ``VJOURNAL`` calendar components.
+
+    Description:
+        This property specifies a color that clients MAY use
+        when presenting the relevant data to a user.  Typically, this
+        would appear as the "background" color of events or tasks.  The
+        value is a case-insensitive color name taken from the CSS3 set of
+        names, defined in Section 4.3 of `W3C.REC-css3-color-20110607 <https://www.w3.org/TR/css-color-3/>`_.
+
+    Example:
+        ``"turquoise"``, ``"#ffffff"``
+
+        .. code-block:: pycon
+
+            >>> from icalendar import Todo
+            >>> todo = Todo()
+            >>> todo.color = "green"
+            >>> print(todo.to_ical())
+            BEGIN:VTODO
+            COLOR:green
+            END:VTODO
+    """
+)
+
+sequence_property = single_int_property(
+    "SEQUENCE",
+    0,
+    """This property defines the revision sequence number of the calendar component within a sequence of revisions.
+
+Value Type:
+    INTEGER
+
+Property Parameters:
+    IANA and non-standard property parameters can be specified on this property.
+
+Conformance:
+    The property can be specified in "VEVENT", "VTODO", or
+    "VJOURNAL" calendar component.
+
+Description:
+    When a calendar component is created, its sequence
+    number is 0.  It is monotonically incremented by the "Organizer's"
+    CUA each time the "Organizer" makes a significant revision to the
+    calendar component.
+
+    The "Organizer" includes this property in an iCalendar object that
+    it sends to an "Attendee" to specify the current version of the
+    calendar component.
+
+    The "Attendee" includes this property in an iCalendar object that
+    it sends to the "Organizer" to specify the version of the calendar
+    component to which the "Attendee" is referring.
+
+    A change to the sequence number is not the mechanism that an
+    "Organizer" uses to request a response from the "Attendees".  The
+    "RSVP" parameter on the "ATTENDEE" property is used by the
+    "Organizer" to indicate that a response from the "Attendees" is
+    requested.
+
+    Recurrence instances of a recurring component MAY have different
+    sequence numbers.
+
+Examples:
+    The following is an example of this property for a calendar
+    component that was just created by the "Organizer":
+
+    .. code-block:: pycon
+
+        >>> from icalendar import Event
+        >>> event = Event()
+        >>> event.sequence
+        0
+
+    The following is an example of this property for a calendar
+    component that has been revised 10 different times by the
+    "Organizer":
+
+    .. code-block:: pycon
+
+        >>> from icalendar import Calendar
+        >>> calendar = Calendar.example("issue_156_RDATE_with_PERIOD_TZID_khal")
+        >>> event = calendar.events[0]
+        >>> event.sequence
+        10
+    """
+)
+
+def _get_categories(component: Component) -> list[str]:
+    """Get all the categories."""
+    categories : Optional[vCategory|list[vCategory]] = component.get("CATEGORIES")
+    if isinstance(categories, list):
+        _set_categories(component, list(itertools.chain.from_iterable(cat.cats for cat in categories)))
+        return _get_categories(component)
+    if categories is None:
+        categories = vCategory([])
+        component.add("CATEGORIES", categories)
+    return categories.cats
+
+def _set_categories(component: Component, cats: list[str]) -> None:
+    """Set the categories."""
+    component["CATEGORIES"] = categories = vCategory(cats)
+    cats.clear()
+    cats.extend(categories.cats)
+    categories.cats = cats
+
+
+def _del_categories(component: Component) -> None:
+    """Delete the categories."""
+    component.pop("CATEGORIES", None)
+
+
+categories_property = property(
+    _get_categories,
+    _set_categories,
+    _del_categories,
+    """This property defines the categories for a component.
+
+Property Parameters:
+    IANA, non-standard, and language property parameters can be specified on this
+    property.
+
+Conformance:
+    The property can be specified within "VEVENT", "VTODO", or "VJOURNAL" calendar
+    components.
+    Since :rfc:`7986` it can also be defined on a "VCALENDAR" component.
+
+Description:
+    This property is used to specify categories or subtypes
+    of the calendar component.  The categories are useful in searching
+    for a calendar component of a particular type and category.
+    Within the "VEVENT", "VTODO", or "VJOURNAL" calendar components,
+    more than one category can be specified as a COMMA-separated list
+    of categories.
+
+Example:
+    Below, we add the categories to an event:
+
+    .. code-block:: pycon
+
+        >>> from icalendar import Event
+        >>> event = Event()
+        >>> event.categories = ["Work", "Meeting"]
+        >>> print(event.to_ical())
+        BEGIN:VEVENT
+        CATEGORIES:Work,Meeting
+        END:VEVENT
+        >>> event.categories.append("Lecture")
+        >>> event.categories == ["Work", "Meeting", "Lecture"]
+        True
+
+.. note::
+
+   At present, we do not take the LANGUAGE parameter into account.
+"""
+)
+
+uid_property = single_string_property(
+    "UID", """UID specifies the persistent, globally unique identifier for a component.
+
+We recommend using :func:`uuid.uuid4` to generate new values.
+
+Returns:
+    The value of the UID property as a string or ``""`` if no value is set.
+
+Description:
+    The "UID" itself MUST be a globally unique identifier.
+    The generator of the identifier MUST guarantee that the identifier
+    is unique.
+
+    This is the method for correlating scheduling messages with the
+    referenced "VEVENT", "VTODO", or "VJOURNAL" calendar component.
+    The full range of calendar components specified by a recurrence
+    set is referenced by referring to just the "UID" property value
+    corresponding to the calendar component.  The "RECURRENCE-ID"
+    property allows the reference to an individual instance within the
+    recurrence set.
+
+    This property is an important method for group-scheduling
+    applications to match requests with later replies, modifications,
+    or deletion requests.  Calendaring and scheduling applications
+    MUST generate this property in "VEVENT", "VTODO", and "VJOURNAL"
+    calendar components to assure interoperability with other group-
+    scheduling applications.  This identifier is created by the
+    calendar system that generates an iCalendar object.
+
+    Implementations MUST be able to receive and persist values of at
+    least 255 octets for this property, but they MUST NOT truncate
+    values in the middle of a UTF-8 multi-octet sequence.
+
+    :rfc:`7986` states that UID can be used, for
+    example, to identify duplicate calendar streams that a client may
+    have been given access to.  It can be used in conjunction with the
+    "LAST-MODIFIED" property also specified on the "VCALENDAR" object
+    to identify the most recent version of a calendar.
+
+Conformance:
+    :rfc:`5545` states that the "UID" property can be specified on "VEVENT", "VTODO",
+    and "VJOURNAL" calendar components.
+    :rfc:`7986` modifies the definition of the "UID" property to
+    allow it to be defined in an iCalendar object.
+    :rfc:`9074`  adds a "UID" property to "VALARM" components to allow a unique
+    identifier to be specified. The value of this property can then be used
+    to refer uniquely to the "VALARM" component.
+
+    This property can be specified once only.
+
+Security:
+    :rfc:`7986` states that UID values MUST NOT include any data that
+    might identify a user, host, domain, or any other security- or
+    privacy-sensitive information.  It is RECOMMENDED that calendar user
+    agents now generate "UID" values that are hex-encoded random
+    Universally Unique Identifier (UUID) values as defined in
+    Sections 4.4 and 4.5 of :rfc:`4122`.
+    You can use the :mod:`uuid` module to generate new UUIDs.
+
+Compatibility:
+    For Alarms, ``X-ALARMUID`` is also considered.
+
+Examples:
+    The following is an example of such a property value:
+    ``5FC53010-1267-4F8E-BC28-1D7AE55A7C99``.
+
+    Set the UID of a calendar:
+
+    .. code-block:: pycon
+
+        >>> from icalendar import Calendar
+        >>> from uuid import uuid4
+        >>> calendar = Calendar()
+        >>> calendar.uid = uuid4()
+        >>> print(calendar.to_ical())
+        BEGIN:VCALENDAR
+        UID:d755cef5-2311-46ed-a0e1-6733c9e15c63
+        END:VCALENDAR
+
+"""
+)
+
+
+
+__all__ = [
+    "categories_property",
+    "color_property",
+    "exdates_property",
+    "multi_language_text_property",
+    "rdates_property",
+    "rrules_property",
+    "sequence_property",
+    "single_int_property",
+    "single_utc_property",
+    "uid_property",
+]
diff -pruN 6.0.1-3/src/icalendar/cal.py 6.3.1-1/src/icalendar/cal.py
--- 6.0.1-3/src/icalendar/cal.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/cal.py	2025-05-20 07:31:39.000000000 +0000
@@ -3,19 +3,48 @@ files according to RFC 5545.
 
 These are the defined components.
 """
+
 from __future__ import annotations
 
 import os
-from datetime import date, datetime, timedelta
-from typing import List, Optional, Tuple
+from collections import defaultdict
+from datetime import date, datetime, timedelta, tzinfo
+from typing import TYPE_CHECKING, List, NamedTuple, Optional, Tuple, Union
 
 import dateutil.rrule
 import dateutil.tz
+
+from icalendar.attr import (
+    categories_property,
+    color_property,
+    exdates_property,
+    multi_language_text_property,
+    rdates_property,
+    rrules_property,
+    sequence_property,
+    single_int_property,
+    single_string_property,
+    single_utc_property,
+    uid_property,
+)
 from icalendar.caselessdict import CaselessDict
+from icalendar.error import IncompleteComponent, InvalidCalendar
 from icalendar.parser import Contentline, Contentlines, Parameters, q_join, q_split
 from icalendar.parser_tools import DEFAULT_ENCODING
-from icalendar.prop import TypesFactory, vDDDLists, vDDDTypes, vText, vDuration
-from icalendar.timezone import tzp
+from icalendar.prop import (
+    TypesFactory,
+    tzid_from_tzinfo,
+    vDDDLists,
+    vDDDTypes,
+    vDuration,
+    vText,
+    vUTCOffset,
+)
+from icalendar.timezone import TZP, tzp
+from icalendar.tools import is_date, to_datetime
+
+if TYPE_CHECKING:
+    from icalendar.alarms import Alarms
 
 
 def get_example(component_directory: str, example_name: str) -> bytes:
@@ -26,7 +55,9 @@ def get_example(component_directory: str
         example_name = example_name + ".ics"
     example_file = os.path.join(examples, example_name)
     if not os.path.isfile(example_file):
-        raise ValueError(f"Example {example_name} for {component_directory} not found. You can use one of {', '.join(os.listdir(examples))}")
+        raise ValueError(
+            f"Example {example_name} for {component_directory} not found. You can use one of {', '.join(os.listdir(examples))}"
+        )
     with open(example_file, "rb") as f:
         return f.read()
 
@@ -34,51 +65,38 @@ def get_example(component_directory: str
 ######################################
 # The component factory
 
+
 class ComponentFactory(CaselessDict):
     """All components defined in RFC 5545 are registered in this factory class.
     To get a component you can use it like this.
     """
 
     def __init__(self, *args, **kwargs):
-        """Set keys to upper for initial dict.
-        """
+        """Set keys to upper for initial dict."""
         super().__init__(*args, **kwargs)
-        self['VEVENT'] = Event
-        self['VTODO'] = Todo
-        self['VJOURNAL'] = Journal
-        self['VFREEBUSY'] = FreeBusy
-        self['VTIMEZONE'] = Timezone
-        self['STANDARD'] = TimezoneStandard
-        self['DAYLIGHT'] = TimezoneDaylight
-        self['VALARM'] = Alarm
-        self['VCALENDAR'] = Calendar
+        self["VEVENT"] = Event
+        self["VTODO"] = Todo
+        self["VJOURNAL"] = Journal
+        self["VFREEBUSY"] = FreeBusy
+        self["VTIMEZONE"] = Timezone
+        self["STANDARD"] = TimezoneStandard
+        self["DAYLIGHT"] = TimezoneDaylight
+        self["VALARM"] = Alarm
+        self["VCALENDAR"] = Calendar
 
 
 # These Properties have multiple property values inlined in one propertyline
 # seperated by comma. Use CaselessDict as simple caseless set.
-INLINE = CaselessDict({
-    'CATEGORIES': 1,
-    'RESOURCES': 1,
-    'FREEBUSY': 1,
-})
+INLINE = CaselessDict(
+    {
+        "CATEGORIES": 1,
+        "RESOURCES": 1,
+        "FREEBUSY": 1,
+    }
+)
 
 _marker = []
 
-class InvalidCalendar(ValueError):
-    """The calendar given is not valid.
-
-    This calendar does not conform with RFC 5545 or breaks other RFCs.
-    """
-
-class IncompleteComponent(ValueError):
-    """The component is missing attributes.
-
-    The attributes are not required, otherwise this would be
-    an InvalidCalendar. But in order to perform calculations,
-    this attribute is required.
-    """
-
-
 
 class Component(CaselessDict):
     """Component is the base object for calendar, Event and the other
@@ -86,27 +104,26 @@ class Component(CaselessDict):
     directly, but rather one of the subclasses.
     """
 
-    name = None         # should be defined in each component
-    required = ()       # These properties are required
-    singletons = ()     # These properties must only appear once
-    multiple = ()       # may occur more than once
-    exclusive = ()      # These properties are mutually exclusive
-    inclusive = ()      # if any occurs the other(s) MUST occur
-                        # ('duration', 'repeat')
-    ignore_exceptions = False   # if True, and we cannot parse this
-                                # component, we will silently ignore
-                                # it, rather than let the exception
-                                # propagate upwards
+    name = None  # should be defined in each component
+    required = ()  # These properties are required
+    singletons = ()  # These properties must only appear once
+    multiple = ()  # may occur more than once
+    exclusive = ()  # These properties are mutually exclusive
+    inclusive = ()  # if any occurs the other(s) MUST occur
+    # ('duration', 'repeat')
+    ignore_exceptions = False  # if True, and we cannot parse this
+    # component, we will silently ignore
+    # it, rather than let the exception
+    # propagate upwards
     # not_compliant = ['']  # List of non-compliant properties.
 
     def __init__(self, *args, **kwargs):
-        """Set keys to upper for initial dict.
-        """
+        """Set keys to upper for initial dict."""
         super().__init__(*args, **kwargs)
         # set parameters here for properties that use non-default values
         self.subcomponents = []  # Components can be nested.
         self.errors = []  # If we ignored exception(s) while
-                          # parsing a property, contains error strings
+        # parsing a property, contains error strings
 
     # def is_compliant(self, name):
     #    """Returns True is the given property name is compliant with the
@@ -119,16 +136,14 @@ class Component(CaselessDict):
     #    return name in not_compliant
 
     def __bool__(self):
-        """Returns True, CaselessDict would return False if it had no items.
-        """
+        """Returns True, CaselessDict would return False if it had no items."""
         return True
 
     # python 2 compatibility
     __nonzero__ = __bool__
 
     def is_empty(self):
-        """Returns True if Component has no items or subcomponents, else False.
-        """
+        """Returns True if Component has no items or subcomponents, else False."""
         return True if not (list(self.values()) + self.subcomponents) else False  # noqa
 
     #############################
@@ -196,14 +211,20 @@ class Component(CaselessDict):
 
         :returns: None
         """
-        if isinstance(value, datetime) and\
-                name.lower() in ('dtstamp', 'created', 'last-modified'):
+        if isinstance(value, datetime) and name.lower() in (
+            "dtstamp",
+            "created",
+            "last-modified",
+        ):
             # RFC expects UTC for those... force value conversion.
             value = tzp.localize_utc(value)
 
         # encode value
-        if encode and isinstance(value, list) \
-                and name.lower() not in ['rdate', 'exdate', 'categories']:
+        if (
+            encode
+            and isinstance(value, list)
+            and name.lower() not in ["rdate", "exdate", "categories"]
+        ):
             # Individually convert each value to an ical type except rdate and
             # exdate, where lists of dates might be passed to vDDDLists.
             value = [self._encode(name, v, parameters, encode) for v in value]
@@ -225,8 +246,7 @@ class Component(CaselessDict):
         self[name] = value
 
     def _decode(self, name, value):
-        """Internal for decoding property values.
-        """
+        """Internal for decoding property values."""
 
         # TODO: Currently the decoded method calls the icalendar.prop instances
         # from_ical. We probably want to decode properties into Python native
@@ -243,8 +263,7 @@ class Component(CaselessDict):
         return decoded
 
     def decoded(self, name, default=_marker):
-        """Returns decoded value of property.
-        """
+        """Returns decoded value of property."""
         # XXX: fail. what's this function supposed to do in the end?
         # -rnix
 
@@ -264,8 +283,7 @@ class Component(CaselessDict):
     # property line. These methods are used for splitting and joining these.
 
     def get_inline(self, name, decode=1):
-        """Returns a list of values (split on comma).
-        """
+        """Returns a list of values (split on comma)."""
         vals = [v.strip('" ') for v in q_split(self[name])]
         if decode:
             return [self._decode(name, val) for val in vals]
@@ -277,19 +295,17 @@ class Component(CaselessDict):
         """
         if encode:
             values = [self._encode(name, value, encode=1) for value in values]
-        self[name] = types_factory['inline'](q_join(values))
+        self[name] = types_factory["inline"](q_join(values))
 
     #########################
     # Handling of components
 
-    def add_component(self, component):
-        """Add a subcomponent to this component.
-        """
+    def add_component(self, component: Component):
+        """Add a subcomponent to this component."""
         self.subcomponents.append(component)
 
     def _walk(self, name, select):
-        """Walk to given component.
-        """
+        """Walk to given component."""
         result = []
         if (name is None or self.name == name) and select(self):
             result.append(self)
@@ -297,7 +313,7 @@ class Component(CaselessDict):
             result += subcomponent._walk(name, select)
         return result
 
-    def walk(self, name=None, select=lambda c: True):
+    def walk(self, name=None, select=lambda c: True) -> list[Component]:
         """Recursively traverses component and subcomponents. Returns sequence
         of same. If name is passed, only components with name will be returned.
 
@@ -314,12 +330,12 @@ class Component(CaselessDict):
     #####################
     # Generation
 
-    def property_items(self, recursive=True, sorted=True):
+    def property_items(self, recursive=True, sorted=True) -> list[tuple[str, object]]:
         """Returns properties in this component and subcomponents as:
         [(name, value), ...]
         """
-        vText = types_factory['text']
-        properties = [('BEGIN', vText(self.name).to_ical())]
+        vText = types_factory["text"]
+        properties = [("BEGIN", vText(self.name).to_ical())]
         if sorted:
             property_names = self.sorted_keys()
         else:
@@ -337,13 +353,12 @@ class Component(CaselessDict):
             # recursion is fun!
             for subcomponent in self.subcomponents:
                 properties += subcomponent.property_items(sorted=sorted)
-        properties.append(('END', vText(self.name).to_ical()))
+        properties.append(("END", vText(self.name).to_ical()))
         return properties
 
     @classmethod
     def from_ical(cls, st, multiple=False):
-        """Populates the component recursively from a string.
-        """
+        """Populates the component recursively from a string."""
         stack = []  # a stack of components
         comps = []
         for line in Contentlines.from_ical(st):  # raw parsing
@@ -364,7 +379,7 @@ class Component(CaselessDict):
 
             uname = name.upper()
             # check for start of component
-            if uname == 'BEGIN':
+            if uname == "BEGIN":
                 # try and create one of the components defined in the spec,
                 # otherwise get a general Components for robustness.
                 c_name = vals.upper()
@@ -374,23 +389,23 @@ class Component(CaselessDict):
                 # That's opposed to the usage of ``cls``, which represents a
                 # more concrete subclass with a name set (e.g. VCALENDAR).
                 component = c_class()
-                if not getattr(component, 'name', ''):  # undefined components
+                if not getattr(component, "name", ""):  # undefined components
                     component.name = c_name
                 stack.append(component)
             # check for end of event
-            elif uname == 'END':
+            elif uname == "END":
                 # we are done adding properties to this component
                 # so pop it from the stack and add it to the new top.
                 if not stack:
                     # The stack is currently empty, the input must be invalid
-                    raise ValueError('END encountered without an accompanying BEGIN!')
+                    raise ValueError("END encountered without an accompanying BEGIN!")
 
                 component = stack.pop()
                 if not stack:  # we are at the end
                     comps.append(component)
                 else:
                     stack[-1].add_component(component)
-                if vals == 'VTIMEZONE' and 'TZID' in component:
+                if vals == "VTIMEZONE" and "TZID" in component:
                     tzp.cache_timezone_component(component)
             # we are adding properties to the current top of the stack
             else:
@@ -399,21 +414,36 @@ class Component(CaselessDict):
                 if not component:
                     # only accept X-COMMENT at the end of the .ics file
                     # ignore these components in parsing
-                    if uname == 'X-COMMENT':
+                    if uname == "X-COMMENT":
                         break
                     else:
-                        raise ValueError(f'Property "{name}" does not have a parent component.')
-                datetime_names = ('DTSTART', 'DTEND', 'RECURRENCE-ID', 'DUE',
-                                  'RDATE', 'EXDATE')
+                        raise ValueError(
+                            f'Property "{name}" does not have a parent component.'
+                        )
+                datetime_names = (
+                    "DTSTART",
+                    "DTEND",
+                    "RECURRENCE-ID",
+                    "DUE",
+                    "RDATE",
+                    "EXDATE",
+                )
                 try:
-                    if name == 'FREEBUSY':
-                        vals = vals.split(',')
-                        if 'TZID' in params:
-                            parsed_components = [factory(factory.from_ical(val, params['TZID'])) for val in vals]
+                    if name == "FREEBUSY":
+                        vals = vals.split(",")
+                        if "TZID" in params:
+                            parsed_components = [
+                                factory(factory.from_ical(val, params["TZID"]))
+                                for val in vals
+                            ]
                         else:
-                            parsed_components = [factory(factory.from_ical(val)) for val in vals]
-                    elif name in datetime_names and 'TZID' in params:
-                        parsed_components = [factory(factory.from_ical(vals, params['TZID']))]
+                            parsed_components = [
+                                factory(factory.from_ical(val)) for val in vals
+                            ]
+                    elif name in datetime_names and "TZID" in params:
+                        parsed_components = [
+                            factory(factory.from_ical(vals, params["TZID"]))
+                        ]
                     else:
                         parsed_components = [factory(factory.from_ical(vals))]
                 except ValueError as e:
@@ -428,51 +458,55 @@ class Component(CaselessDict):
         if multiple:
             return comps
         if len(comps) > 1:
-            raise ValueError(cls._format_error(
-                'Found multiple components where only one is allowed', st))
+            raise ValueError(
+                cls._format_error(
+                    "Found multiple components where only one is allowed", st
+                )
+            )
         if len(comps) < 1:
-            raise ValueError(cls._format_error(
-                'Found no components where exactly one is required', st))
+            raise ValueError(
+                cls._format_error(
+                    "Found no components where exactly one is required", st
+                )
+            )
         return comps[0]
 
-    def _format_error(error_description, bad_input, elipsis='[...]'):
+    @staticmethod
+    def _format_error(error_description, bad_input, elipsis="[...]"):
         # there's three character more in the error, ie. ' ' x2 and a ':'
         max_error_length = 100 - 3
         if len(error_description) + len(bad_input) + len(elipsis) > max_error_length:
             truncate_to = max_error_length - len(error_description) - len(elipsis)
-            return f'{error_description}: {bad_input[:truncate_to]} {elipsis}'
+            return f"{error_description}: {bad_input[:truncate_to]} {elipsis}"
         else:
-            return f'{error_description}: {bad_input}'
+            return f"{error_description}: {bad_input}"
 
     def content_line(self, name, value, sorted=True):
-        """Returns property as content line.
-        """
-        params = getattr(value, 'params', Parameters())
+        """Returns property as content line."""
+        params = getattr(value, "params", Parameters())
         return Contentline.from_parts(name, params, value, sorted=sorted)
 
     def content_lines(self, sorted=True):
-        """Converts the Component and subcomponents into content lines.
-        """
+        """Converts the Component and subcomponents into content lines."""
         contentlines = Contentlines()
         for name, value in self.property_items(sorted=sorted):
             cl = self.content_line(name, value, sorted=sorted)
             contentlines.append(cl)
-        contentlines.append('')  # remember the empty string in the end
+        contentlines.append("")  # remember the empty string in the end
         return contentlines
 
     def to_ical(self, sorted=True):
-        '''
+        """
         :param sorted: Whether parameters and properties should be
                        lexicographically sorted.
-        '''
+        """
 
         content_lines = self.content_lines(sorted=sorted)
         return content_lines.to_ical()
 
     def __repr__(self):
-        """String representation of class with all of it's subcomponents.
-        """
-        subs = ', '.join(str(it) for it in self.subcomponents)
+        """String representation of class with all of it's subcomponents."""
+        subs = ", ".join(str(it) for it in self.subcomponents)
         return f"{self.name or type(self).__name__}({dict(self)}{', ' + subs if subs else ''})"
 
     def __eq__(self, other):
@@ -494,38 +528,104 @@ class Component(CaselessDict):
 
         return True
 
+    DTSTAMP = single_utc_property(
+        "DTSTAMP",
+        """RFC 5545:
+
+        Conformance:  This property MUST be included in the "VEVENT",
+        "VTODO", "VJOURNAL", or "VFREEBUSY" calendar components.
+
+        Description: In the case of an iCalendar object that specifies a
+        "METHOD" property, this property specifies the date and time that
+        the instance of the iCalendar object was created.  In the case of
+        an iCalendar object that doesn't specify a "METHOD" property, this
+        property specifies the date and time that the information
+        associated with the calendar component was last revised in the
+        calendar store.
+
+        The value MUST be specified in the UTC time format.
+
+        In the case of an iCalendar object that doesn't specify a "METHOD"
+        property, this property is equivalent to the "LAST-MODIFIED"
+        property.
+    """,
+    )
+    LAST_MODIFIED = single_utc_property(
+        "LAST-MODIFIED",
+        """RFC 5545:
+
+        Purpose:  This property specifies the date and time that the
+        information associated with the calendar component was last
+        revised in the calendar store.
+
+        Note: This is analogous to the modification date and time for a
+        file in the file system.
+
+        Conformance:  This property can be specified in the "VEVENT",
+        "VTODO", "VJOURNAL", or "VTIMEZONE" calendar components.
+    """,
+    )
+
+    def is_thunderbird(self) -> bool:
+        """Whether this component has attributes that indicate that Mozilla Thunderbird created it."""
+        return any(attr.startswith("X-MOZ-") for attr in self.keys())
+
+
 #######################################
 # components defined in RFC 5545
 
-def create_single_property(prop:str, value_attr:str, value_type:tuple[type], type_def:type, doc:str):
-    """Create a single property getter and setter."""
 
-    def p_get(self : Component):
+def create_single_property(
+    prop: str,
+    value_attr: Optional[str],
+    value_type: tuple[type],
+    type_def: type,
+    doc: str,
+    vProp: type = vDDDTypes,  # noqa: N803
+):
+    """Create a single property getter and setter.
+
+    :param prop: The name of the property.
+    :param value_attr: The name of the attribute to get the value from.
+    :param value_type: The type of the value.
+    :param type_def: The type of the property.
+    :param doc: The docstring of the property.
+    :param vProp: The type of the property from :mod:`icalendar.prop`.
+    """
+
+    def p_get(self: Component):
         default = object()
         result = self.get(prop, default)
         if result is default:
             return None
         if isinstance(result, list):
             raise InvalidCalendar(f"Multiple {prop} defined.")
-        value = getattr(result, value_attr, result)
+        value = result if value_attr is None else getattr(result, value_attr, result)
         if not isinstance(value, value_type):
-            raise InvalidCalendar(f"{prop} must be either a date or a datetime, not {value}.")
+            raise InvalidCalendar(
+                f"{prop} must be either a {' or '.join(t.__name__ for t in value_type)}, not {value}."
+            )
         return value
 
-    def p_set(self:Component, value) -> None:
+    def p_set(self: Component, value) -> None:
         if value is None:
             p_del(self)
             return
         if not isinstance(value, value_type):
-            raise TypeError(f"Use {' or '.join(t.__name__ for t in value_type)}, not {type(value).__name__}.")
-        self[prop] = vDDDTypes(value)
+            raise TypeError(
+                f"Use {' or '.join(t.__name__ for t in value_type)}, not {type(value).__name__}."
+            )
+        self[prop] = vProp(value)
         if prop in self.exclusive:
             for other_prop in self.exclusive:
                 if other_prop != prop:
                     self.pop(other_prop, None)
-    p_set.__annotations__["value"] = p_get.__annotations__["return"] = Optional[type_def]
 
-    def p_del(self:Component):
+    p_set.__annotations__["value"] = p_get.__annotations__["return"] = Optional[
+        type_def
+    ]
+
+    def p_del(self: Component):
         self.pop(prop)
 
     p_doc = f"""The {prop} property.
@@ -540,45 +640,167 @@ def create_single_property(prop:str, val
     return property(p_get, p_set, p_del, p_doc)
 
 
-def is_date(dt: date) -> bool:
-    """Whether this is a date and not a datetime."""
-    return isinstance(dt, date) and not isinstance(dt, datetime)
-
-def is_datetime(dt: date) -> bool:
-    """Whether this is a date and not a datetime."""
-    return isinstance(dt, datetime)
+_X_MOZ_SNOOZE_TIME = single_utc_property(
+    "X-MOZ-SNOOZE-TIME", "Thunderbird: Alarms before this time are snoozed."
+)
+_X_MOZ_LASTACK = single_utc_property(
+    "X-MOZ-LASTACK", "Thunderbird: Alarms before this time are acknowledged."
+)
+
+
+def _get_duration(self: Component) -> Optional[timedelta]:
+    """Getter for property DURATION."""
+    default = object()
+    duration = self.get("duration", default)
+    if isinstance(duration, vDDDTypes):
+        return duration.dt
+    if isinstance(duration, vDuration):
+        return duration.td
+    if duration is not default and not isinstance(duration, timedelta):
+        raise InvalidCalendar(
+            f"DURATION must be a timedelta, not {type(duration).__name__}."
+        )
+    return None
+
+
+def _set_duration(self: Component, value: Optional[timedelta]):
+    """Setter for property DURATION."""
+    if value is None:
+        self.pop("duration", None)
+        return
+    if not isinstance(value, timedelta):
+        raise TypeError(f"Use timedelta, not {type(value).__name__}.")
+    self["duration"] = vDuration(value)
+    self.pop("DTEND")
+    self.pop("DUE")
+
+
+def _del_duration(self: Component):
+    """Delete property DURATION."""
+    self.pop("DURATION")
+
+
+_doc_duration = """The DURATION property.
+
+The "DTSTART" property for a "{component}" specifies the inclusive start of the event.
+The "DURATION" property in conjunction with the DTSTART property
+for a "{component}" calendar component specifies the non-inclusive end
+of the event.
+
+If you would like to calculate the duration of a {component}, do not use this.
+Instead use the duration property (lower case).
+"""
+
 
 class Event(Component):
+    """
+    A "VEVENT" calendar component is a grouping of component
+    properties that represents a scheduled amount of time on a
+    calendar. For example, it can be an activity, such as a one-hour
+    long department meeting from 8:00 AM to 9:00 AM, tomorrow.
+    """
 
-    name = 'VEVENT'
+    name = "VEVENT"
 
     canonical_order = (
-        'SUMMARY', 'DTSTART', 'DTEND', 'DURATION', 'DTSTAMP',
-        'UID', 'RECURRENCE-ID', 'SEQUENCE', 'RRULE', 'RDATE',
-        'EXDATE',
+        "SUMMARY",
+        "DTSTART",
+        "DTEND",
+        "DURATION",
+        "DTSTAMP",
+        "UID",
+        "RECURRENCE-ID",
+        "SEQUENCE",
+        "RRULE",
+        "RDATE",
+        "EXDATE",
     )
 
-    required = ('UID', 'DTSTAMP',)
+    required = (
+        "UID",
+        "DTSTAMP",
+    )
     singletons = (
-        'CLASS', 'CREATED', 'DESCRIPTION', 'DTSTART', 'GEO', 'LAST-MODIFIED',
-        'LOCATION', 'ORGANIZER', 'PRIORITY', 'DTSTAMP', 'SEQUENCE', 'STATUS',
-        'SUMMARY', 'TRANSP', 'URL', 'RECURRENCE-ID', 'DTEND', 'DURATION',
-        'UID', 'CATEGORIES',
+        "CLASS",
+        "CREATED",
+        "COLOR",
+        "DESCRIPTION",
+        "DTSTART",
+        "GEO",
+        "LAST-MODIFIED",
+        "LOCATION",
+        "ORGANIZER",
+        "PRIORITY",
+        "DTSTAMP",
+        "SEQUENCE",
+        "STATUS",
+        "SUMMARY",
+        "TRANSP",
+        "URL",
+        "RECURRENCE-ID",
+        "DTEND",
+        "DURATION",
+        "UID",
+    )
+    exclusive = (
+        "DTEND",
+        "DURATION",
     )
-    exclusive = ('DTEND', 'DURATION',)
     multiple = (
-        'ATTACH', 'ATTENDEE', 'COMMENT', 'CONTACT', 'EXDATE',
-        'RSTATUS', 'RELATED', 'RESOURCES', 'RDATE', 'RRULE'
+        "ATTACH",
+        "ATTENDEE",
+        "CATEGORIES",
+        "COMMENT",
+        "CONTACT",
+        "EXDATE",
+        "RSTATUS",
+        "RELATED",
+        "RESOURCES",
+        "RDATE",
+        "RRULE",
     )
     ignore_exceptions = True
 
+    @property
+    def alarms(self) -> Alarms:
+        """Compute the alarm times for this component.
+
+        >>> from icalendar import Event
+        >>> event = Event.example("rfc_9074_example_1")
+        >>> len(event.alarms.times)
+        1
+        >>> alarm_time = event.alarms.times[0]
+        >>> alarm_time.trigger  # The time when the alarm pops up
+        datetime.datetime(2021, 3, 2, 10, 15, tzinfo=ZoneInfo(key='America/New_York'))
+        >>> alarm_time.is_active()  # This alarm has not been acknowledged
+        True
+
+        Note that this only uses DTSTART and DTEND, but ignores
+        RDATE, EXDATE, and RRULE properties.
+        """
+        from icalendar.alarms import Alarms
+
+        return Alarms(self)
+
     @classmethod
-    def example(cls, name:str) -> Event:
+    def example(cls, name: str = "rfc_9074_example_3") -> Event:
         """Return the calendar example with the given name."""
         return cls.from_ical(get_example("events", name))
 
-    DTSTART = create_single_property("DTSTART", "dt", (datetime, date), date, 'The "DTSTART" property for a "VEVENT" specifies the inclusive start of the event.')
-    DTEND = create_single_property("DTEND", "dt", (datetime, date), date, 'The "DTEND" property for a "VEVENT" calendar component specifies the non-inclusive end of the event.')
+    DTSTART = create_single_property(
+        "DTSTART",
+        "dt",
+        (datetime, date),
+        date,
+        'The "DTSTART" property for a "VEVENT" specifies the inclusive start of the event.',
+    )
+    DTEND = create_single_property(
+        "DTEND",
+        "dt",
+        (datetime, date),
+        date,
+        'The "DTEND" property for a "VEVENT" calendar component specifies the non-inclusive end of the event.',
+    )
 
     def _get_start_end_duration(self):
         """Verify the calendar validity and return the right attributes."""
@@ -586,48 +808,34 @@ class Event(Component):
         end = self.DTEND
         duration = self.DURATION
         if duration is not None and end is not None:
-            raise InvalidCalendar("Only one of DTEND and DURATION may be in a VEVENT, not both.")
-        if isinstance(start, date) and not isinstance(start, datetime) and duration is not None and duration.seconds != 0:
-            raise InvalidCalendar("When DTSTART is a date, DURATION must be of days or weeks.")
+            raise InvalidCalendar(
+                "Only one of DTEND and DURATION may be in a VEVENT, not both."
+            )
+        if (
+            isinstance(start, date)
+            and not isinstance(start, datetime)
+            and duration is not None
+            and duration.seconds != 0
+        ):
+            raise InvalidCalendar(
+                "When DTSTART is a date, DURATION must be of days or weeks."
+            )
         if start is not None and end is not None and is_date(start) != is_date(end):
-            raise InvalidCalendar("DTSTART and DTEND must be of the same type, either date or datetime.")
+            raise InvalidCalendar(
+                "DTSTART and DTEND must be of the same type, either date or datetime."
+            )
         return start, end, duration
 
-    @property
-    def DURATION(self) -> Optional[timedelta]:  # noqa: N802
-        """The DURATION of the component.
-
-        The "DTSTART" property for a "VEVENT" specifies the inclusive start of the event.
-        The "DURATION" property in conjunction with the DTSTART property
-        for a "VEVENT" calendar component specifies the non-inclusive end
-        of the event.
-
-        If you would like to calculate the duration of an event do not use this.
-        Instead use the difference between DTSTART and DTEND.
-        """
-        default = object()
-        duration = self.get("duration", default)
-        if isinstance(duration, vDDDTypes):
-            return duration.dt
-        if isinstance(duration, vDuration):
-            return duration.td
-        if duration is not default and not isinstance(duration, timedelta):
-            raise InvalidCalendar(f"DURATION must be a timedelta, not {type(duration).__name__}.")
-        return None
-    
-    @DURATION.setter
-    def DURATION(self, value: Optional[timedelta]):  # noqa: N802
-        if value is None:
-            self.pop("duration", None)
-            return
-        if not isinstance(value, timedelta):
-            raise TypeError(f"Use timedelta, not {type(value).__name__}.")
-        self["duration"] = vDuration(value)
-        del self.DTEND
+    DURATION = property(
+        _get_duration,
+        _set_duration,
+        _del_duration,
+        _doc_duration.format(component="VEVENT"),
+    )
 
     @property
     def duration(self) -> timedelta:
-        """The duration of the component.
+        """The duration of the VEVENT.
 
         This duration is calculated from the start and end of the event.
         You cannot set the duration as it is unclear what happens to start and end.
@@ -648,7 +856,7 @@ class Event(Component):
         >>> event = Event()
         >>> event.start = datetime(2021, 1, 1, 12)
         >>> event.end = datetime(2021, 1, 1, 12, 30) # 30 minutes
-        >>> event.end - event.start  # 1800 seconds == 30 minutes
+        >>> event.duration  # 1800 seconds == 30 minutes
         datetime.timedelta(seconds=1800)
         >>> print(event.to_ical())
         BEGIN:VEVENT
@@ -691,23 +899,211 @@ class Event(Component):
         """Set the end."""
         self.DTEND = end
 
+    X_MOZ_SNOOZE_TIME = _X_MOZ_SNOOZE_TIME
+    X_MOZ_LASTACK = _X_MOZ_LASTACK
+    color = color_property
+    sequence = sequence_property
+    categories = categories_property
+    rdates = rdates_property
+    exdates = exdates_property
+    rrules = rrules_property
+    uid = uid_property
+
 
 class Todo(Component):
+    """
+    A "VTODO" calendar component is a grouping of component
+    properties that represents an action item or assignment. For
+    example, it can be used to represent an item of work assigned to
+    an individual, such as "Prepare for the upcoming conference
+    seminar on Internet Calendaring".
+    """
 
-    name = 'VTODO'
+    name = "VTODO"
 
-    required = ('UID', 'DTSTAMP',)
+    required = (
+        "UID",
+        "DTSTAMP",
+    )
     singletons = (
-        'CLASS', 'COMPLETED', 'CREATED', 'DESCRIPTION', 'DTSTAMP', 'DTSTART',
-        'GEO', 'LAST-MODIFIED', 'LOCATION', 'ORGANIZER', 'PERCENT-COMPLETE',
-        'PRIORITY', 'RECURRENCE-ID', 'SEQUENCE', 'STATUS', 'SUMMARY', 'UID',
-        'URL', 'DUE', 'DURATION',
+        "CLASS",
+        "COLOR",
+        "COMPLETED",
+        "CREATED",
+        "DESCRIPTION",
+        "DTSTAMP",
+        "DTSTART",
+        "GEO",
+        "LAST-MODIFIED",
+        "LOCATION",
+        "ORGANIZER",
+        "PERCENT-COMPLETE",
+        "PRIORITY",
+        "RECURRENCE-ID",
+        "SEQUENCE",
+        "STATUS",
+        "SUMMARY",
+        "UID",
+        "URL",
+        "DUE",
+        "DURATION",
+    )
+    exclusive = (
+        "DUE",
+        "DURATION",
     )
-    exclusive = ('DUE', 'DURATION',)
     multiple = (
-        'ATTACH', 'ATTENDEE', 'CATEGORIES', 'COMMENT', 'CONTACT', 'EXDATE',
-        'RSTATUS', 'RELATED', 'RESOURCES', 'RDATE', 'RRULE'
+        "ATTACH",
+        "ATTENDEE",
+        "CATEGORIES",
+        "COMMENT",
+        "CONTACT",
+        "EXDATE",
+        "RSTATUS",
+        "RELATED",
+        "RESOURCES",
+        "RDATE",
+        "RRULE",
+    )
+    DTSTART = create_single_property(
+        "DTSTART",
+        "dt",
+        (datetime, date),
+        date,
+        'The "DTSTART" property for a "VTODO" specifies the inclusive start of the Todo.',
     )
+    DUE = create_single_property(
+        "DUE",
+        "dt",
+        (datetime, date),
+        date,
+        'The "DUE" property for a "VTODO" calendar component specifies the non-inclusive end of the Todo.',
+    )
+    DURATION = property(
+        _get_duration,
+        _set_duration,
+        _del_duration,
+        _doc_duration.format(component="VTODO"),
+    )
+
+    def _get_start_end_duration(self):
+        """Verify the calendar validity and return the right attributes."""
+        start = self.DTSTART
+        end = self.DUE
+        duration = self.DURATION
+        if duration is not None and end is not None:
+            raise InvalidCalendar(
+                "Only one of DUE and DURATION may be in a VTODO, not both."
+            )
+        if (
+            isinstance(start, date)
+            and not isinstance(start, datetime)
+            and duration is not None
+            and duration.seconds != 0
+        ):
+            raise InvalidCalendar(
+                "When DTSTART is a date, DURATION must be of days or weeks."
+            )
+        if start is not None and end is not None and is_date(start) != is_date(end):
+            raise InvalidCalendar(
+                "DTSTART and DUE must be of the same type, either date or datetime."
+            )
+        return start, end, duration
+
+    @property
+    def start(self) -> date | datetime:
+        """The start of the VTODO.
+
+        Invalid values raise an InvalidCalendar.
+        If there is no start, we also raise an IncompleteComponent error.
+
+        You can get the start, end and duration of a Todo as follows:
+
+        >>> from datetime import datetime
+        >>> from icalendar import Todo
+        >>> todo = Todo()
+        >>> todo.start = datetime(2021, 1, 1, 12)
+        >>> todo.end = datetime(2021, 1, 1, 12, 30) # 30 minutes
+        >>> todo.duration  # 1800 seconds == 30 minutes
+        datetime.timedelta(seconds=1800)
+        >>> print(todo.to_ical())
+        BEGIN:VTODO
+        DTSTART:20210101T120000
+        DUE:20210101T123000
+        END:VTODO
+        """
+        start = self._get_start_end_duration()[0]
+        if start is None:
+            raise IncompleteComponent("No DTSTART given.")
+        return start
+
+    @start.setter
+    def start(self, start: Optional[date | datetime]):
+        """Set the start."""
+        self.DTSTART = start
+
+    @property
+    def end(self) -> date | datetime:
+        """The end of the component.
+
+        Invalid values raise an InvalidCalendar error.
+        If there is no end, we also raise an IncompleteComponent error.
+        """
+        start, end, duration = self._get_start_end_duration()
+        if end is None and duration is None:
+            if start is None:
+                raise IncompleteComponent("No DUE or DURATION+DTSTART given.")
+            if is_date(start):
+                return start + timedelta(days=1)
+            return start
+        if duration is not None:
+            if start is not None:
+                return start + duration
+            raise IncompleteComponent("No DUE or DURATION+DTSTART given.")
+        return end
+
+    @end.setter
+    def end(self, end: date | datetime | None):
+        """Set the end."""
+        self.DUE = end
+
+    @property
+    def duration(self) -> timedelta:
+        """The duration of the VTODO.
+
+        This duration is calculated from the start and end of the Todo.
+        You cannot set the duration as it is unclear what happens to start and end.
+        """
+        return self.end - self.start
+
+    X_MOZ_SNOOZE_TIME = _X_MOZ_SNOOZE_TIME
+    X_MOZ_LASTACK = _X_MOZ_LASTACK
+
+    @property
+    def alarms(self) -> Alarms:
+        """Compute the alarm times for this component.
+
+        >>> from datetime import datetime
+        >>> from icalendar import Todo
+        >>> todo = Todo()  # empty without alarms
+        >>> todo.start = datetime(2024, 10, 26, 10, 21)
+        >>> len(todo.alarms.times)
+        0
+
+        Note that this only uses DTSTART and DUE, but ignores
+        RDATE, EXDATE, and RRULE properties.
+        """
+        from icalendar.alarms import Alarms
+
+        return Alarms(self)
+
+    color = color_property
+    sequence = sequence_property
+    categories = categories_property
+    rdates = rdates_property
+    exdates = exdates_property
+    rrules = rrules_property
+    uid = uid_property
 
 
 class Journal(Component):
@@ -725,26 +1121,53 @@ class Journal(Component):
     day.
     """
 
-    name = 'VJOURNAL'
+    name = "VJOURNAL"
 
-    required = ('UID', 'DTSTAMP',)
+    required = (
+        "UID",
+        "DTSTAMP",
+    )
     singletons = (
-        'CLASS', 'CREATED', 'DTSTART', 'DTSTAMP', 'LAST-MODIFIED', 'ORGANIZER',
-        'RECURRENCE-ID', 'SEQUENCE', 'STATUS', 'SUMMARY', 'UID', 'URL',
+        "CLASS",
+        "COLOR",
+        "CREATED",
+        "DTSTART",
+        "DTSTAMP",
+        "LAST-MODIFIED",
+        "ORGANIZER",
+        "RECURRENCE-ID",
+        "SEQUENCE",
+        "STATUS",
+        "SUMMARY",
+        "UID",
+        "URL",
     )
     multiple = (
-        'ATTACH', 'ATTENDEE', 'CATEGORIES', 'COMMENT', 'CONTACT', 'EXDATE',
-        'RELATED', 'RDATE', 'RRULE', 'RSTATUS', 'DESCRIPTION',
+        "ATTACH",
+        "ATTENDEE",
+        "CATEGORIES",
+        "COMMENT",
+        "CONTACT",
+        "EXDATE",
+        "RELATED",
+        "RDATE",
+        "RRULE",
+        "RSTATUS",
+        "DESCRIPTION",
     )
 
     DTSTART = create_single_property(
-        "DTSTART", "dt", (datetime, date), date,
-        'The "DTSTART" property for a "VJOURNAL" that specifies the exact date at which the journal entry was made.')
+        "DTSTART",
+        "dt",
+        (datetime, date),
+        date,
+        'The "DTSTART" property for a "VJOURNAL" that specifies the exact date at which the journal entry was made.',
+    )
 
     @property
     def start(self) -> date:
         """The start of the Journal.
-        
+
         The "DTSTART"
         property is used to specify the calendar date with which the
         journal entry is associated.
@@ -753,51 +1176,95 @@ class Journal(Component):
         if start is None:
             raise IncompleteComponent("No DTSTART given.")
         return start
-    
+
     @start.setter
-    def start(self, value: datetime|date) -> None:
+    def start(self, value: datetime | date) -> None:
         """Set the start of the journal."""
         self.DTSTART = value
 
     end = start
-    
+
     @property
     def duration(self) -> timedelta:
-        """The journal has no duration."""
+        """The journal has no duration: timedelta(0)."""
         return timedelta(0)
 
+    color = color_property
+    sequence = sequence_property
+    categories = categories_property
+    rdates = rdates_property
+    exdates = exdates_property
+    rrules = rrules_property
+    uid = uid_property
+
+
 class FreeBusy(Component):
+    """
+    A "VFREEBUSY" calendar component is a grouping of component
+    properties that represents either a request for free or busy time
+    information, a reply to a request for free or busy time
+    information, or a published set of busy time information.
+    """
 
-    name = 'VFREEBUSY'
+    name = "VFREEBUSY"
 
-    required = ('UID', 'DTSTAMP',)
+    required = (
+        "UID",
+        "DTSTAMP",
+    )
     singletons = (
-        'CONTACT', 'DTSTART', 'DTEND', 'DTSTAMP', 'ORGANIZER',
-        'UID', 'URL',
+        "CONTACT",
+        "DTSTART",
+        "DTEND",
+        "DTSTAMP",
+        "ORGANIZER",
+        "UID",
+        "URL",
     )
-    multiple = ('ATTENDEE', 'COMMENT', 'FREEBUSY', 'RSTATUS',)
+    multiple = (
+        "ATTENDEE",
+        "COMMENT",
+        "FREEBUSY",
+        "RSTATUS",
+    )
+    uid = uid_property
 
 
 class Timezone(Component):
-    name = 'VTIMEZONE'
-    canonical_order = ('TZID',)
-    required = ('TZID',) # it also requires one of components DAYLIGHT and STANDARD
-    singletons = ('TZID', 'LAST-MODIFIED', 'TZURL',)
+    """
+    A "VTIMEZONE" calendar component is a grouping of component
+    properties that defines a time zone. It is used to describe the
+    way in which a time zone changes its offset from UTC over time.
+    """
+
+    subcomponents: list[TimezoneStandard|TimezoneDaylight]
+
+    name = "VTIMEZONE"
+    canonical_order = ("TZID",)
+    required = ("TZID",)  # it also requires one of components DAYLIGHT and STANDARD
+    singletons = (
+        "TZID",
+        "LAST-MODIFIED",
+        "TZURL",
+    )
+
+    _DEFAULT_FIRST_DATE = date(1970, 1, 1)
+    _DEFAULT_LAST_DATE = date(2038, 1, 1)
 
     @classmethod
-    def example(cls, name: str) -> Calendar:
-        """Return the calendar example with the given name."""
+    def example(cls, name: str = "pacific_fiji") -> Calendar:
+        """Return the timezone example with the given name."""
         return cls.from_ical(get_example("timezones", name))
 
     @staticmethod
-    def _extract_offsets(component, tzname):
+    def _extract_offsets(component: TimezoneDaylight | TimezoneStandard, tzname: str):
         """extract offsets and transition times from a VTIMEZONE component
         :param component: a STANDARD or DAYLIGHT component
         :param tzname: the name of the zone
         """
-        offsetfrom = component['TZOFFSETFROM'].td
-        offsetto = component['TZOFFSETTO'].td
-        dtstart = component['DTSTART'].dt
+        offsetfrom = component.TZOFFSETFROM
+        offsetto = component.TZOFFSETTO
+        dtstart = component.DTSTART
 
         # offsets need to be rounded to the next minute, we might loose up
         # to 30 seconds accuracy, but it can't be helped (datetime
@@ -808,38 +1275,38 @@ class Timezone(Component):
         offsetfrom = timedelta(days=offsetfrom.days, seconds=offsetfrom_s)
 
         # expand recurrences
-        if 'RRULE' in component:
+        if "RRULE" in component:
             # to be paranoid about correct weekdays
             # evaluate the rrule with the current offset
-            tzi = dateutil.tz.tzoffset ("(offsetfrom)", offsetfrom)
-            rrstart = dtstart.replace (tzinfo=tzi)
+            tzi = dateutil.tz.tzoffset("(offsetfrom)", offsetfrom)
+            rrstart = dtstart.replace(tzinfo=tzi)
 
-            rrulestr = component['RRULE'].to_ical().decode('utf-8')
+            rrulestr = component["RRULE"].to_ical().decode("utf-8")
             rrule = dateutil.rrule.rrulestr(rrulestr, dtstart=rrstart)
-            tzp.fix_rrule_until(rrule, component['RRULE'])
+            tzp.fix_rrule_until(rrule, component["RRULE"])
 
             # constructing the timezone requires UTC transition times.
             # here we construct local times without tzinfo, the offset to UTC
             # gets subtracted in to_tz().
-            transtimes = [dt.replace (tzinfo=None) for dt in rrule]
+            transtimes = [dt.replace(tzinfo=None) for dt in rrule]
 
         # or rdates
-        elif 'RDATE' in component:
-            if not isinstance(component['RDATE'], list):
-                rdates = [component['RDATE']]
+        elif "RDATE" in component:
+            if not isinstance(component["RDATE"], list):
+                rdates = [component["RDATE"]]
             else:
-                rdates = component['RDATE']
-            transtimes = [dtstart] + [leaf.dt for tree in rdates for
-                                      leaf in tree.dts]
+                rdates = component["RDATE"]
+            transtimes = [dtstart] + [leaf.dt for tree in rdates for leaf in tree.dts]
         else:
             transtimes = [dtstart]
 
-        transitions = [(transtime, offsetfrom, offsetto, tzname) for
-                       transtime in set(transtimes)]
+        transitions = [
+            (transtime, offsetfrom, offsetto, tzname) for transtime in set(transtimes)
+        ]
 
-        if component.name == 'STANDARD':
+        if component.name == "STANDARD":
             is_dst = 0
-        elif component.name == 'DAYLIGHT':
+        elif component.name == "DAYLIGHT":
             is_dst = 1
         return is_dst, transitions
 
@@ -851,13 +1318,24 @@ class Timezone(Component):
         """
         # TODO better way of making sure tznames are unique
         while tzname in tznames:
-            tzname += '_1'
+            tzname += "_1"
         tznames.add(tzname)
         return tzname
 
-    def to_tz(self, tzp=tzp):
+    def to_tz(self, tzp: TZP = tzp, lookup_tzid: bool = True):
         """convert this VTIMEZONE component to a timezone object
-        """
+
+        :param tzp: timezone provider to use
+        :param lookup_tzid: whether to use the TZID property to look up existing
+                            timezone definitions with tzp.
+                            If it is False, a new timezone will be created.
+                            If it is True, the existing timezone will be used
+                            if it exists, otherwise a new timezone will be created.
+        """
+        if lookup_tzid:
+            tz = tzp.timezone(self.tz_name)
+            if tz is not None:
+                return tz
         return tzp.create_timezone(self)
 
     @property
@@ -868,11 +1346,13 @@ class Timezone(Component):
         and may change with winter/summer time.
         """
         try:
-            return str(self['TZID'])
+            return str(self["TZID"])
         except UnicodeEncodeError:
-            return self['TZID'].encode('ascii', 'replace')
+            return self["TZID"].encode("ascii", "replace")
 
-    def get_transitions(self) -> Tuple[List[datetime], List[Tuple[timedelta, timedelta, str]]]:
+    def get_transitions(
+        self,
+    ) -> Tuple[List[datetime], List[Tuple[timedelta, timedelta, str]]]:
         """Return a tuple of (transition_times, transition_info)
 
         - transition_times = [datetime, ...]
@@ -886,19 +1366,23 @@ class Timezone(Component):
         for component in self.walk():
             if type(component) == Timezone:
                 continue
-            assert isinstance(component['DTSTART'].dt, datetime), (
-                "VTIMEZONEs sub-components' DTSTART must be of type datetime, not date"
-            )
+            if is_date(component["DTSTART"].dt):
+                component.DTSTART = to_datetime(component["DTSTART"].dt)
+            assert isinstance(
+                component["DTSTART"].dt, datetime
+            ), "VTIMEZONEs sub-components' DTSTART must be of type datetime, not date"
             try:
-                tzname = str(component['TZNAME'])
+                tzname = str(component["TZNAME"])
             except UnicodeEncodeError:
-                tzname = component['TZNAME'].encode('ascii', 'replace')
+                tzname = component["TZNAME"].encode("ascii", "replace")
                 tzname = self._make_unique_tzname(tzname, tznames)
             except KeyError:
                 # for whatever reason this is str/unicode
-                tzname = f"{zone}_{component['DTSTART'].to_ical().decode('utf-8')}_" + \
-                         f"{component['TZOFFSETFROM'].to_ical()}_" + \
-                         f"{component['TZOFFSETTO'].to_ical()}"
+                tzname = (
+                    f"{zone}_{component['DTSTART'].to_ical().decode('utf-8')}_"
+                    + f"{component['TZOFFSETFROM'].to_ical()}_"
+                    + f"{component['TZOFFSETTO'].to_ical()}"
+                )
                 tzname = self._make_unique_tzname(tzname, tznames)
 
             dst[tzname], component_transitions = self._extract_offsets(
@@ -931,58 +1415,787 @@ class Timezone(Component):
                 if not dst_offset:
                     for index in range(num, len(transitions)):
                         if not dst[transitions[index][3]]:  # [3] is the name
-                            dst_offset = osto - transitions[index][2]  # [2] is osto  # noqa
+                            dst_offset = (
+                                osto - transitions[index][2]
+                            )  # [2] is osto  # noqa
                             break
             assert dst_offset is not False
             transition_info.append((osto, dst_offset, name))
         return transition_times, transition_info
 
+    # binary search
+    _from_tzinfo_skip_search = [
+        timedelta(days=days) for days in (64, 32, 16, 8, 4, 2, 1)
+    ] + [
+        # we know it happens in the night usually around 1am
+        timedelta(hours=4),
+        timedelta(hours=1),
+        # adding some minutes and seconds for faster search
+        timedelta(minutes=20),
+        timedelta(minutes=5),
+        timedelta(minutes=1),
+        timedelta(seconds=20),
+        timedelta(seconds=5),
+        timedelta(seconds=1),
+    ]
+
+    @classmethod
+    def from_tzinfo(
+        cls,
+        timezone: tzinfo,
+        tzid: Optional[str] = None,
+        first_date: date = _DEFAULT_FIRST_DATE,
+        last_date: date = _DEFAULT_LAST_DATE,
+    ) -> Timezone:
+        """Return a VTIMEZONE component from a timezone object.
+
+        This works with pytz and zoneinfo and any other timezone.
+        The offsets are calculated from the tzinfo object.
+
+        Parameters:
+
+        :param tzinfo: the timezone object
+        :param tzid: the tzid for this timezone. If None, it will be extracted from the tzinfo.
+        :param first_date: a datetime that is earlier than anything that happens in the calendar
+        :param last_date: a datetime that is later than anything that happens in the calendar
+        :raises ValueError: If we have no tzid and cannot extract one.
+
+        .. note::
+            This can take some time. Please cache the results.
+        """
+        if tzid is None:
+            tzid = tzid_from_tzinfo(timezone)
+            if tzid is None:
+                raise ValueError(
+                    f"Cannot get TZID from {timezone}. Please set the tzid parameter."
+                )
+        normalize = getattr(timezone, "normalize", lambda dt: dt)  # pytz compatibility
+        first_datetime = datetime(first_date.year, first_date.month, first_date.day)  # noqa: DTZ001
+        last_datetime = datetime(last_date.year, last_date.month, last_date.day)  # noqa: DTZ001
+        if hasattr(timezone, "localize"):  # pytz compatibility
+            first_datetime = timezone.localize(first_datetime)
+            last_datetime = timezone.localize(last_datetime)
+        else:
+            first_datetime = first_datetime.replace(tzinfo=timezone)
+            last_datetime = last_datetime.replace(tzinfo=timezone)
+        # from, to, tzname, is_standard -> start
+        offsets: dict[
+            tuple[Optional[timedelta], timedelta, str, bool], list[datetime]
+        ] = defaultdict(list)
+        start = first_datetime
+        offset_to = None
+        while start < last_datetime:
+            offset_from = offset_to
+            end = start
+            offset_to = end.utcoffset()
+            for add_offset in cls._from_tzinfo_skip_search:
+                last_end = end  # we need to save this as we might be left and right of the time change
+                end = normalize(end + add_offset)
+                try:
+                    while end.utcoffset() == offset_to:
+                        last_end = end
+                        end = normalize(end + add_offset)
+                except OverflowError:
+                    # zoninfo does not go all the way
+                    break
+                # retract if we overshoot
+                end = last_end
+            # Now, start (inclusive) -> end (exclusive) are one timezone
+            is_standard = start.dst() == timedelta()
+            name = start.tzname()
+            if name is None:
+                name = str(offset_to)
+            key = (offset_from, offset_to, name, is_standard)
+            # first_key = (None,) + key[1:]
+            # if first_key in offsets:
+            #     # remove the first one and claim it changes at that day
+            #     offsets[first_key] = offsets.pop(first_key)
+            offsets[key].append(start.replace(tzinfo=None))
+            start = normalize(end + cls._from_tzinfo_skip_search[-1])
+        tz = cls()
+        tz.add("TZID", tzid)
+        tz.add("COMMENT", f"This timezone only works from {first_date} to {last_date}.")
+        for (offset_from, offset_to, tzname, is_standard), starts in offsets.items():
+            first_start = min(starts)
+            starts.remove(first_start)
+            if first_start.date() == last_date:
+                first_start = datetime(last_date.year, last_date.month, last_date.day)  # noqa: DTZ001
+            subcomponent = TimezoneStandard() if is_standard else TimezoneDaylight()
+            if offset_from is None:
+                offset_from = offset_to  # noqa: PLW2901
+            subcomponent.TZOFFSETFROM = offset_from
+            subcomponent.TZOFFSETTO = offset_to
+            subcomponent.add("TZNAME", tzname)
+            subcomponent.DTSTART = first_start
+            if starts:
+                subcomponent.add("RDATE", starts)
+            tz.add_component(subcomponent)
+        return tz
+
+    @classmethod
+    def from_tzid(
+        cls,
+        tzid: str,
+        tzp: TZP = tzp,
+        first_date: date = _DEFAULT_FIRST_DATE,
+        last_date: date = _DEFAULT_LAST_DATE,
+    ) -> Timezone:
+        """Create a VTIMEZONE from a tzid like ``"Europe/Berlin"``.
+
+        :param tzid: the id of the timezone
+        :param tzp: the timezone provider
+        :param first_date: a datetime that is earlier than anything that happens in the calendar
+        :param last_date: a datetime that is later than anything that happens in the calendar
+        :raises ValueError: If the tzid is unknown.
+
+        >>> from icalendar import Timezone
+        >>> tz = Timezone.from_tzid("Europe/Berlin")
+        >>> print(tz.to_ical()[:36])
+        BEGIN:VTIMEZONE
+        TZID:Europe/Berlin
+
+        .. note::
+            This can take some time. Please cache the results.
+        """
+        tz = tzp.timezone(tzid)
+        if tz is None:
+            raise ValueError(f"Unkown timezone {tzid}.")
+        return cls.from_tzinfo(tz, tzid, first_date, last_date)
+
+    @property
+    def standard(self) -> list[TimezoneStandard]:
+        """The STANDARD subcomponents as a list."""
+        return self.walk("STANDARD")
+
+    @property
+    def daylight(self) -> list[TimezoneDaylight]:
+        """The DAYLIGHT subcomponents as a list.
+
+        These are for the daylight saving time.
+        """
+        return self.walk("DAYLIGHT")
+
 
 class TimezoneStandard(Component):
-    name = 'STANDARD'
-    required = ('DTSTART', 'TZOFFSETTO', 'TZOFFSETFROM')
-    singletons = ('DTSTART', 'TZOFFSETTO', 'TZOFFSETFROM',)
-    multiple = ('COMMENT', 'RDATE', 'TZNAME', 'RRULE', 'EXDATE')
+    """
+    The "STANDARD" sub-component of "VTIMEZONE" defines the standard
+    time offset from UTC for a time zone. It represents a time zone's
+    standard time, typically used during winter months in locations
+    that observe Daylight Saving Time.
+    """
+
+    name = "STANDARD"
+    required = ("DTSTART", "TZOFFSETTO", "TZOFFSETFROM")
+    singletons = (
+        "DTSTART",
+        "TZOFFSETTO",
+        "TZOFFSETFROM",
+    )
+    multiple = ("COMMENT", "RDATE", "TZNAME", "RRULE", "EXDATE")
+
+    DTSTART = create_single_property(
+        "DTSTART",
+        "dt",
+        (datetime,),
+        datetime,
+        """The mandatory "DTSTART" property gives the effective onset date
+        and local time for the time zone sub-component definition.
+        "DTSTART" in this usage MUST be specified as a date with a local
+        time value.""",
+    )
+    TZOFFSETTO = create_single_property(
+        "TZOFFSETTO",
+        "td",
+        (timedelta,),
+        timedelta,
+        """The mandatory "TZOFFSETTO" property gives the UTC offset for the
+        time zone sub-component (Standard Time or Daylight Saving Time)
+        when this observance is in use.
+        """,
+        vUTCOffset,
+    )
+    TZOFFSETFROM = create_single_property(
+        "TZOFFSETFROM",
+        "td",
+        (timedelta,),
+        timedelta,
+        """The mandatory "TZOFFSETFROM" property gives the UTC offset that is
+        in use when the onset of this time zone observance begins.
+        "TZOFFSETFROM" is combined with "DTSTART" to define the effective
+        onset for the time zone sub-component definition.  For example,
+        the following represents the time at which the observance of
+        Standard Time took effect in Fall 1967 for New York City:
+
+            DTSTART:19671029T020000
+            TZOFFSETFROM:-0400
+        """,
+        vUTCOffset,
+    )
+    rdates = rdates_property
+    exdates = exdates_property
+    rrules = rrules_property
 
 
 class TimezoneDaylight(Component):
-    name = 'DAYLIGHT'
+    """
+    The "DAYLIGHT" sub-component of "VTIMEZONE" defines the daylight
+    saving time offset from UTC for a time zone. It represents a time
+    zone's daylight saving time, typically used during summer months
+    in locations that observe Daylight Saving Time.
+    """
+
+    name = "DAYLIGHT"
     required = TimezoneStandard.required
     singletons = TimezoneStandard.singletons
     multiple = TimezoneStandard.multiple
 
+    DTSTART = TimezoneStandard.DTSTART
+    TZOFFSETTO = TimezoneStandard.TZOFFSETTO
+    TZOFFSETFROM = TimezoneStandard.TZOFFSETFROM
+
+    rdates = rdates_property
+    exdates = exdates_property
+    rrules = rrules_property
 
 class Alarm(Component):
+    """
+    A "VALARM" calendar component is a grouping of component
+    properties that defines an alarm or reminder for an event or a
+    to-do. For example, it may be used to define a reminder for a
+    pending event or an overdue to-do.
+    """
 
-    name = 'VALARM'
+    name = "VALARM"
     # some properties MAY/MUST/MUST NOT appear depending on ACTION value
-    required = ('ACTION', 'TRIGGER',)
+    required = (
+        "ACTION",
+        "TRIGGER",
+    )
     singletons = (
-            'ATTACH', 'ACTION', 'DESCRIPTION', 'SUMMARY', 'TRIGGER',
-            'DURATION', 'REPEAT',
+        "ATTACH",
+        "ACTION",
+        "DESCRIPTION",
+        "SUMMARY",
+        "TRIGGER",
+        "DURATION",
+        "REPEAT",
+        "UID",
+        "PROXIMITY",
+        "ACKNOWLEDGED",
+    )
+    inclusive = (
+        (
+            "DURATION",
+            "REPEAT",
+        ),
+        (
+            "SUMMARY",
+            "ATTENDEE",
+        ),
+    )
+    multiple = ("ATTENDEE", "ATTACH", "RELATED-TO")
+
+    REPEAT = single_int_property(
+        "REPEAT", 0,
+        """The REPEAT property of an alarm component.
+
+        The alarm can be defined such that it triggers repeatedly.  A
+        definition of an alarm with a repeating trigger MUST include both
+        the "DURATION" and "REPEAT" properties.  The "DURATION" property
+        specifies the delay period, after which the alarm will repeat.
+        The "REPEAT" property specifies the number of additional
+        repetitions that the alarm will be triggered.  This repetition
+        count is in addition to the initial triggering of the alarm.
+        """
+    )
+
+    DURATION = property(
+        _get_duration,
+        _set_duration,
+        _del_duration,
+        """The DURATION property of an alarm component.
+
+    The alarm can be defined such that it triggers repeatedly.  A
+    definition of an alarm with a repeating trigger MUST include both
+    the "DURATION" and "REPEAT" properties.  The "DURATION" property
+    specifies the delay period, after which the alarm will repeat.
+    """,
+    )
+
+    ACKNOWLEDGED = single_utc_property(
+        "ACKNOWLEDGED",
+        """This is defined in RFC 9074:
+
+    Purpose: This property specifies the UTC date and time at which the
+    corresponding alarm was last sent or acknowledged.
+
+    This property is used to specify when an alarm was last sent or acknowledged.
+    This allows clients to determine when a pending alarm has been acknowledged
+    by a calendar user so that any alerts can be dismissed across multiple devices.
+    It also allows clients to track repeating alarms or alarms on recurring events or
+    to-dos to ensure that the right number of missed alarms can be tracked.
+
+    Clients SHOULD set this property to the current date-time value in UTC
+    when a calendar user acknowledges a pending alarm. Certain kinds of alarms,
+    such as email-based alerts, might not provide feedback as to when the calendar user
+    sees them. For those kinds of alarms, the client SHOULD set this property
+    when the alarm is triggered and the action is successfully carried out.
+
+    When an alarm is triggered on a client, clients can check to see if an "ACKNOWLEDGED"
+    property is present. If it is, and the value of that property is greater than or
+    equal to the computed trigger time for the alarm, then the client SHOULD NOT trigger
+    the alarm. Similarly, if an alarm has been triggered and
+    an "alert" has been presented to a calendar user, clients can monitor
+    the iCalendar data to determine whether an "ACKNOWLEDGED" property is added or
+    changed in the alarm component. If the value of any "ACKNOWLEDGED" property
+    in the alarm changes and is greater than or equal to the trigger time of the alarm,
+    then clients SHOULD dismiss or cancel any "alert" presented to the calendar user.
+    """,
+    )
+
+    TRIGGER = create_single_property(
+        "TRIGGER",
+        "dt",
+        (datetime, timedelta),
+        Optional[Union[timedelta, datetime]],
+        """Purpose:  This property specifies when an alarm will trigger.
+
+    Value Type:  The default value type is DURATION.  The value type can
+    be set to a DATE-TIME value type, in which case the value MUST
+    specify a UTC-formatted DATE-TIME value.
+
+    Either a positive or negative duration may be specified for the
+    "TRIGGER" property.  An alarm with a positive duration is
+    triggered after the associated start or end of the event or to-do.
+    An alarm with a negative duration is triggered before the
+    associated start or end of the event or to-do.""",
+    )
+
+    @property
+    def TRIGGER_RELATED(self) -> str:
+        """The RELATED parameter of the TRIGGER property.
+
+        Values are either "START" (default) or "END".
+
+        A value of START will set the alarm to trigger off the
+        start of the associated event or to-do.  A value of END will set
+        the alarm to trigger off the end of the associated event or to-do.
+
+        In this example, we create an alarm that triggers two hours after the
+        end of its parent component:
+
+        >>> from icalendar import Alarm
+        >>> from datetime import timedelta
+        >>> alarm = Alarm()
+        >>> alarm.TRIGGER = timedelta(hours=2)
+        >>> alarm.TRIGGER_RELATED = "END"
+        """
+        trigger = self.get("TRIGGER")
+        if trigger is None:
+            return "START"
+        return trigger.params.get("RELATED", "START")
+
+    @TRIGGER_RELATED.setter
+    def TRIGGER_RELATED(self, value: str):
+        """Set "START" or "END"."""
+        trigger = self.get("TRIGGER")
+        if trigger is None:
+            raise ValueError(
+                "You must set a TRIGGER before setting the RELATED parameter."
             )
-    inclusive = (('DURATION', 'REPEAT',), ('SUMMARY', 'ATTENDEE',))
-    multiple = ('ATTENDEE', 'ATTACH')
+        trigger.params["RELATED"] = value
+
+    class Triggers(NamedTuple):
+        """The computed times of alarm triggers.
+
+        start - triggers relative to the start of the Event or Todo (timedelta)
+
+        end - triggers relative to the end of the Event or Todo (timedelta)
+
+        absolute - triggers at a datetime in UTC
+        """
+
+        start: tuple[timedelta]
+        end: tuple[timedelta]
+        absolute: tuple[datetime]
+
+    @property
+    def triggers(self):
+        """The computed triggers of an Alarm.
+
+        This takes the TRIGGER, DURATION and REPEAT properties into account.
+
+        Here, we create an alarm that triggers 3 times before the start of the
+        parent component:
+
+        >>> from icalendar import Alarm
+        >>> from datetime import timedelta
+        >>> alarm = Alarm()
+        >>> alarm.TRIGGER = timedelta(hours=-4)  # trigger 4 hours before START
+        >>> alarm.DURATION = timedelta(hours=1)  # after 1 hour trigger again
+        >>> alarm.REPEAT = 2  # trigger 2 more times
+        >>> alarm.triggers.start == (timedelta(hours=-4),  timedelta(hours=-3),  timedelta(hours=-2))
+        True
+        >>> alarm.triggers.end
+        ()
+        >>> alarm.triggers.absolute
+        ()
+        """
+        start = []
+        end = []
+        absolute = []
+        trigger = self.TRIGGER
+        if trigger is not None:
+            if isinstance(trigger, date):
+                absolute.append(trigger)
+                add = absolute
+            elif self.TRIGGER_RELATED == "START":
+                start.append(trigger)
+                add = start
+            else:
+                end.append(trigger)
+                add = end
+            duration = self.DURATION
+            if duration is not None:
+                for _ in range(self.REPEAT):
+                    add.append(add[-1] + duration)
+        return self.Triggers(
+            start=tuple(start), end=tuple(end), absolute=tuple(absolute)
+        )
+
+    uid = single_string_property(
+        "UID",
+        uid_property.__doc__,
+        "X-ALARMUID",
+    )
 
 
 class Calendar(Component):
-    """This is the base object for an iCalendar file.
     """
-    name = 'VCALENDAR'
-    canonical_order = ('VERSION', 'PRODID', 'CALSCALE', 'METHOD',)
-    required = ('PRODID', 'VERSION', )
-    singletons = ('PRODID', 'VERSION', 'CALSCALE', 'METHOD')
+    The "VCALENDAR" object is a collection of calendar information.
+    This information can include a variety of components, such as
+    "VEVENT", "VTODO", "VJOURNAL", "VFREEBUSY", "VTIMEZONE", or any
+    other type of calendar component.
+    """
+
+    name = "VCALENDAR"
+    canonical_order = (
+        "VERSION",
+        "PRODID",
+        "CALSCALE",
+        "METHOD",
+        "DESCRIPTION",
+        "X-WR-CALDESC",
+        "NAME",
+        "X-WR-CALNAME",
+    )
+    required = (
+        "PRODID",
+        "VERSION",
+    )
+    singletons = (
+        "PRODID",
+        "VERSION",
+        "CALSCALE",
+        "METHOD",
+        "COLOR",  # RFC 7986
+    )
+    multiple = (
+        "CATEGORIES",  # RFC 7986
+        "DESCRIPTION",  # RFC 7986
+        "NAME",  # RFC 7986
+    )
 
     @classmethod
-    def example(cls, name: str) -> Calendar:
+    def example(cls, name: str = "example") -> Calendar:
         """Return the calendar example with the given name."""
         return cls.from_ical(get_example("calendars", name))
 
+    @classmethod
+    def from_ical(cls, st, multiple=False):
+        comps = Component.from_ical(st, multiple=True)
+        all_timezones_so_far = True
+        for comp in comps:
+            for component in comp.subcomponents:
+                if component.name == 'VTIMEZONE':
+                    if all_timezones_so_far:
+                        pass
+                    else:
+                        # If a preceding component refers to a VTIMEZONE defined later in the source st
+                        # (forward references are allowed by RFC 5545), then the earlier component may have
+                        # the wrong timezone attached.
+                        # However, during computation of comps, all VTIMEZONEs observed do end up in
+                        # the timezone cache. So simply re-running from_ical will rely on the cache
+                        # for those forward references to produce the correct result.
+                        # See test_create_america_new_york_forward_reference.
+                        return Component.from_ical(st, multiple)
+                else:
+                    all_timezones_so_far = False
+
+        # No potentially forward VTIMEZONEs to worry about
+        if multiple:
+            return comps
+        if len(comps) > 1:
+            raise ValueError(cls._format_error(
+                'Found multiple components where only one is allowed', st))
+        if len(comps) < 1:
+            raise ValueError(cls._format_error(
+                'Found no components where exactly one is required', st))
+        return comps[0]
+
+    @property
+    def events(self) -> list[Event]:
+        """All event components in the calendar.
+
+        This is a shortcut to get all events.
+        Modifications do not change the calendar.
+        Use :py:meth:`Component.add_component`.
+
+        >>> from icalendar import Calendar
+        >>> calendar = Calendar.example()
+        >>> event = calendar.events[0]
+        >>> event.start
+        datetime.date(2022, 1, 1)
+        >>> print(event["SUMMARY"])
+        New Year's Day
+        """
+        return self.walk("VEVENT")
+
+    @property
+    def todos(self) -> list[Todo]:
+        """All todo components in the calendar.
+
+        This is a shortcut to get all todos.
+        Modifications do not change the calendar.
+        Use :py:meth:`Component.add_component`.
+        """
+        return self.walk("VTODO")
+
+    @property
+    def freebusy(self) -> list[FreeBusy]:
+        """All FreeBusy components in the calendar.
+
+        This is a shortcut to get all FreeBusy.
+        Modifications do not change the calendar.
+        Use :py:meth:`Component.add_component`.
+        """
+        return self.walk("VFREEBUSY")
+
+    def get_used_tzids(self) -> set[str]:
+        """The set of TZIDs in use.
+
+        This goes through the whole calendar to find all occurrences of
+        timezone information like the TZID parameter in all attributes.
+
+        >>> from icalendar import Calendar
+        >>> calendar = Calendar.example("timezone_rdate")
+        >>> calendar.get_used_tzids()
+        {'posix/Europe/Vaduz'}
+
+        Even if you use UTC, this will not show up.
+        """
+        result = set()
+        for name, value in self.property_items(sorted=False):
+            if hasattr(value, "params"):
+                result.add(value.params.get("TZID"))
+        return result - {None}
+
+    def get_missing_tzids(self) -> set[str]:
+        """The set of missing timezone component tzids.
+
+        To create a :rfc:`5545` compatible calendar,
+        all of these timezones should be added.
+        """
+        tzids = self.get_used_tzids()
+        for timezone in self.timezones:
+            tzids.remove(timezone.tz_name)
+        return tzids
+
+    @property
+    def timezones(self) -> list[Timezone]:
+        """Return the timezones components in this calendar.
+
+        >>> from icalendar import Calendar
+        >>> calendar = Calendar.example("pacific_fiji")
+        >>> [timezone.tz_name for timezone in calendar.timezones]
+        ['custom_Pacific/Fiji']
+
+        .. note::
+
+            This is a read-only property.
+        """
+        return self.walk("VTIMEZONE")
+
+    def add_missing_timezones(
+        self,
+        first_date: date = Timezone._DEFAULT_FIRST_DATE,
+        last_date: date = Timezone._DEFAULT_LAST_DATE,
+    ):
+        """Add all missing VTIMEZONE components.
+
+        This adds all the timezone components that are required.
+
+        .. note::
+
+            Timezones that are not known will not be added.
+
+        :param first_date: earlier than anything that happens in the calendar
+        :param last_date: later than anything happening in the calendar
+
+        >>> from icalendar import Calendar, Event
+        >>> from datetime import datetime
+        >>> from zoneinfo import ZoneInfo
+        >>> calendar = Calendar()
+        >>> event = Event()
+        >>> calendar.add_component(event)
+        >>> event.start = datetime(1990, 10, 11, 12, tzinfo=ZoneInfo("Europe/Berlin"))
+        >>> calendar.timezones
+        []
+        >>> calendar.add_missing_timezones()
+        >>> calendar.timezones[0].tz_name
+        'Europe/Berlin'
+        >>> calendar.get_missing_tzids()  # check that all are added
+        set()
+        """
+        for tzid in self.get_missing_tzids():
+            try:
+                timezone = Timezone.from_tzid(
+                    tzid, first_date=first_date, last_date=last_date
+                )
+            except ValueError:
+                continue
+            self.add_component(timezone)
+
+    calendar_name = multi_language_text_property(
+        "NAME", "X-WR-CALNAME",
+        """This property specifies the name of the calendar.
+
+    This implements :rfc:`7986` ``NAME`` and ``X-WR-CALNAME``.
+
+    Property Parameters:
+        IANA, non-standard, alternate text
+        representation, and language property parameters can be specified
+        on this property.
+
+    Conformance:
+        This property can be specified multiple times in an
+        iCalendar object.  However, each property MUST represent the name
+        of the calendar in a different language.
+
+    Description:
+        This property is used to specify a name of the
+        iCalendar object that can be used by calendar user agents when
+        presenting the calendar data to a user.  Whilst a calendar only
+        has a single name, multiple language variants can be specified by
+        including this property multiple times with different "LANGUAGE"
+        parameter values on each.
+
+    Example:
+        Below, we set the name of the calendar.
+
+        .. code-block:: pycon
+
+            >>> from icalendar import Calendar
+            >>> calendar = Calendar()
+            >>> calendar.calendar_name = "My Calendar"
+            >>> print(calendar.to_ical())
+            BEGIN:VCALENDAR
+            NAME:My Calendar
+            END:VCALENDAR
+    """)
+
+    description = multi_language_text_property(
+        "DESCRIPTION", "X-WR-CALDESC",
+        """This property specifies the description of the calendar.
+
+    This implements :rfc:`7986` ``DESCRIPTION`` and ``X-WR-CALDESC``.
+
+    Conformance:
+        This property can be specified multiple times in an
+        iCalendar object.  However, each property MUST represent the
+        description of the calendar in a different language.
+
+    Description:
+        This property is used to specify a lengthy textual
+        description of the iCalendar object that can be used by calendar
+        user agents when describing the nature of the calendar data to a
+        user.  Whilst a calendar only has a single description, multiple
+        language variants can be specified by including this property
+        multiple times with different "LANGUAGE" parameter values on each.
+
+    Example:
+        Below, we add a description to a calendar.
+
+        .. code-block:: pycon
+
+            >>> from icalendar import Calendar
+            >>> calendar = Calendar()
+            >>> calendar.description = "This is a calendar"
+            >>> print(calendar.to_ical())
+            BEGIN:VCALENDAR
+            DESCRIPTION:This is a calendar
+            END:VCALENDAR
+    """)
+
+    color = single_string_property(
+        "COLOR",
+        """This property specifies a color used for displaying the calendar.
+
+    This implements :rfc:`7986` ``COLOR`` and ``X-APPLE-CALENDAR-COLOR``.
+    Please note that since :rfc:`7986`, subcomponents can have their own color.
+
+    Property Parameters:
+        IANA and non-standard property parameters can
+        be specified on this property.
+
+    Conformance:
+        This property can be specified once in an iCalendar
+        object or in ``VEVENT``, ``VTODO``, or ``VJOURNAL`` calendar components.
+
+    Description:
+        This property specifies a color that clients MAY use
+        when presenting the relevant data to a user.  Typically, this
+        would appear as the "background" color of events or tasks.  The
+        value is a case-insensitive color name taken from the CSS3 set of
+        names, defined in Section 4.3 of `W3C.REC-css3-color-20110607 <https://www.w3.org/TR/css-color-3/>`_.
+
+    Example:
+        ``"turquoise"``, ``"#ffffff"``
+
+        .. code-block:: pycon
+
+            >>> from icalendar import Calendar
+            >>> calendar = Calendar()
+            >>> calendar.color = "black"
+            >>> print(calendar.to_ical())
+            BEGIN:VCALENDAR
+            COLOR:black
+            END:VCALENDAR
+
+    """,
+    "X-APPLE-CALENDAR-COLOR",
+    )
+    categories = categories_property
+    uid = uid_property
+
 # These are read only singleton, so one instance is enough for the module
 types_factory = TypesFactory()
 component_factory = ComponentFactory()
 
-__all__ = ["Alarm", "Calendar", "Component", "ComponentFactory", "Event",
-           "FreeBusy", "INLINE", "Journal", "Timezone", "TimezoneDaylight",
-           "TimezoneStandard", "Todo", "component_factory", "get_example",
-           "IncompleteComponent", "InvalidCalendar"]
+__all__ = [
+    "INLINE",
+    "Alarm",
+    "Calendar",
+    "Component",
+    "ComponentFactory",
+    "Event",
+    "FreeBusy",
+    "IncompleteComponent",
+    "Journal",
+    "Timezone",
+    "TimezoneDaylight",
+    "TimezoneStandard",
+    "Todo",
+    "component_factory",
+    "get_example",
+]
diff -pruN 6.0.1-3/src/icalendar/caselessdict.py 6.3.1-1/src/icalendar/caselessdict.py
--- 6.0.1-3/src/icalendar/caselessdict.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/caselessdict.py	2025-05-20 07:31:39.000000000 +0000
@@ -14,10 +14,8 @@ def canonsort_keys(keys, canonical_order
 
 
 def canonsort_items(dict1, canonical_order=None):
-    """Returns a list of items from dict1, sorted by canonical_order.
-    """
-    return [(k, dict1[k]) for k
-            in canonsort_keys(dict1.keys(), canonical_order)]
+    """Returns a list of items from dict1, sorted by canonical_order."""
+    return [(k, dict1[k]) for k in canonsort_keys(dict1.keys(), canonical_order)]
 
 
 class CaselessDict(OrderedDict):
@@ -26,8 +24,7 @@ class CaselessDict(OrderedDict):
     """
 
     def __init__(self, *args, **kwargs):
-        """Set keys to upper for initial dict.
-        """
+        """Set keys to upper for initial dict."""
         super().__init__(*args, **kwargs)
         for key, value in self.items():
             key_upper = to_unicode(key).upper()
@@ -74,7 +71,7 @@ class CaselessDict(OrderedDict):
         # Multiple keys where key1.upper() == key2.upper() will be lost.
         mappings = list(args) + [kwargs]
         for mapping in mappings:
-            if hasattr(mapping, 'items'):
+            if hasattr(mapping, "items"):
                 mapping = iter(mapping.items())
             for key, value in mapping:
                 self[key] = value
@@ -83,7 +80,7 @@ class CaselessDict(OrderedDict):
         return type(self)(super().copy())
 
     def __repr__(self):
-        return f'{type(self).__name__}({dict(self)})'
+        return f"{type(self).__name__}({dict(self)})"
 
     def __eq__(self, other):
         return self is other or dict(self.items()) == dict(other.items())
diff -pruN 6.0.1-3/src/icalendar/cli.py 6.3.1-1/src/icalendar/cli.py
--- 6.0.1-3/src/icalendar/cli.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/cli.py	2025-05-20 07:31:39.000000000 +0000
@@ -1,5 +1,6 @@
 #!/usr/bin/env python3
 """utility program that allows user to preview calendar's events"""
+
 import sys
 import pathlib
 import argparse
@@ -7,6 +8,7 @@ from datetime import datetime
 
 from icalendar import Calendar, __version__
 
+
 def _format_name(address):
     """Retrieve the e-mail and the name from an address.
 
@@ -14,10 +16,10 @@ def _format_name(address):
 
     :returns str: The name and the e-mail address.
     """
-    email = address.split(':')[-1]
-    name = email.split('@')[0]
+    email = address.split(":")[-1]
+    name = email.split("@")[0]
     if not email:
-        return ''
+        return ""
     return f"{name} <{email}>"
 
 
@@ -28,35 +30,36 @@ def _format_attendees(attendees):
 
     :returns str: Formatted list of attendees.
     """
-    if isinstance(attendees, list):
-        return '\n'.join(map(lambda s: s.rjust(len(s) + 5), map(_format_name, attendees)))
-    return _format_name(attendees)
+    if isinstance(attendees, str):
+        attendees = [attendees]
+    return "\n".join(map(lambda s: s.rjust(len(s) + 5), map(_format_name, attendees)))
+
 
 def view(event):
     """Make a human readable summary of an iCalendar file.
 
     :returns str: Human readable summary.
     """
-    summary = event.get('summary', default='')
-    organizer = _format_name(event.get('organizer', default=''))
-    attendees = _format_attendees(event.get('attendee', default=[]))
-    location = event.get('location', default='')
-    comment = event.get('comment', '')
-    description = event.get('description', '').split('\n')
-    description = '\n'.join(map(lambda s: s.rjust(len(s) + 5), description))
-
-    start = event.decoded('dtstart')
-    if 'duration' in event:
-        end = event.decoded('dtend', default=start + event.decoded('duration'))
+    summary = event.get("summary", default="")
+    organizer = _format_name(event.get("organizer", default=""))
+    attendees = _format_attendees(event.get("attendee", default=[]))
+    location = event.get("location", default="")
+    comment = event.get("comment", "")
+    description = event.get("description", "").split("\n")
+    description = "\n".join(map(lambda s: s.rjust(len(s) + 5), description))
+
+    start = event.decoded("dtstart")
+    if "duration" in event:
+        end = event.decoded("dtend", default=start + event.decoded("duration"))
     else:
-        end = event.decoded('dtend', default=start)
-    duration = event.decoded('duration', default=end - start)
+        end = event.decoded("dtend", default=start)
+    duration = event.decoded("duration", default=end - start)
     if isinstance(start, datetime):
         start = start.astimezone()
-    start = start.strftime('%c')
+    start = start.strftime("%c")
     if isinstance(end, datetime):
         end = end.astimezone()
-    end = end.strftime('%c')
+    end = end.strftime("%c")
 
     return f"""    Organizer: {organizer}
     Attendees:
@@ -70,21 +73,33 @@ def view(event):
     Description:
 {description}"""
 
+
 def main():
     parser = argparse.ArgumentParser(description=__doc__)
-    parser.add_argument('calendar_files', nargs='+', type=pathlib.Path)
-    parser.add_argument('--output', '-o', type=argparse.FileType('w'), default=sys.stdout, help='output file')
-    parser.add_argument('-v', '--version', action='version', version=f'{parser.prog} version {__version__}')
+    parser.add_argument("calendar_files", nargs="+", type=pathlib.Path)
+    parser.add_argument(
+        "--output",
+        "-o",
+        type=argparse.FileType("w"),
+        default=sys.stdout,
+        help="output file",
+    )
+    parser.add_argument(
+        "-v",
+        "--version",
+        action="version",
+        version=f"{parser.prog} version {__version__}",
+    )
     argv = parser.parse_args()
 
     for calendar_file in argv.calendar_files:
-        with open(calendar_file, encoding='utf-8-sig') as f:
+        with open(calendar_file, encoding="utf-8-sig") as f:
             calendar = Calendar.from_ical(f.read())
-            for event in calendar.walk('vevent'):
-                argv.output.write(view(event) + '\n\n')
+            for event in calendar.walk("vevent"):
+                argv.output.write(view(event) + "\n\n")
 
 
 __all__ = ["main", "view"]
 
-if __name__ == '__main__':
+if __name__ == "__main__":
     main()
diff -pruN 6.0.1-3/src/icalendar/enums.py 6.3.1-1/src/icalendar/enums.py
--- 6.0.1-3/src/icalendar/enums.py	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/enums.py	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,129 @@
+"""Enumerations for different types in the RFCs."""
+from enum import Enum as _Enum
+
+
+class Enum(_Enum):
+    """Enum class that can be pickled."""
+
+    def __reduce_ex__(self, _p):
+        """For pickling."""
+        return self.__class__, (self._name_,)
+
+
+class StrEnum(str, Enum):
+    """Enum for strings."""
+
+
+class PARTSTAT(StrEnum):
+    """Enum for PARTSTAT from :rfc:`5545`.
+
+    Attributes:
+        ``NEEDS_ACTION``,
+        ``ACCEPTED``,
+        ``DECLINED``,
+        ``TENTATIVE``,
+        ``DELEGATED``,
+        ``COMPLETED``,
+        ``IN_PROCESS``
+    """
+    NEEDS_ACTION = "NEEDS-ACTION"
+    ACCEPTED = "ACCEPTED"
+    DECLINED = "DECLINED"
+    TENTATIVE = "TENTATIVE"
+    DELEGATED = "DELEGATED"
+    COMPLETED = "COMPLETED"
+    IN_PROCESS = "IN-PROCESS"
+
+
+class FBTYPE(StrEnum):
+    """Enum for FBTYPE from :rfc:`5545`.
+
+    Attributes:
+        ``FREE``,
+        ``BUSY``,
+        ``BUSY-UNAVAILABLE``,
+        ``BUSY-TENTATIVE``
+    """
+    FREE = "FREE"
+    BUSY = "BUSY"
+    BUSY_UNAVAILABLE = "BUSY-UNAVAILABLE"
+    BUSY_TENTATIVE = "BUSY-TENTATIVE"
+
+
+class CUTYPE(StrEnum):
+    """Enum for CTYPE from :rfc:`5545`.
+
+    Attributes:
+        ``INDIVIDUAL``,
+        ``GROUP``,
+        ``RESOURCE``,
+        ``ROOM``,
+        ``UNKNOWN``
+    """
+    INDIVIDUAL = "INDIVIDUAL"
+    GROUP = "GROUP"
+    RESOURCE = "RESOURCE"
+    ROOM = "ROOM"
+    UNKNOWN = "UNKNOWN"
+
+
+class RELTYPE(StrEnum):
+    """Enum for RELTYPE from :rfc:`5545`.
+
+    Attributes:
+        ``PARENT``,
+        ``CHILD``,
+        ``SIBLING``
+    """
+    PARENT = "PARENT"
+    CHILD = "CHILD"
+    SIBLING = "SIBLING"
+
+
+class RANGE(StrEnum):
+    """Enum for RANGE from :rfc:`5545`.
+
+    Attributes:
+        ``THISANDFUTURE``,
+        ``THISANDPRIOR``
+    """
+
+    THISANDFUTURE = "THISANDFUTURE"
+    THISANDPRIOR = "THISANDPRIOR"  # deprecated
+
+
+class RELATED(StrEnum):
+    """Enum for RELATED from :rfc:`5545`.
+
+    Attributes:
+        ``START``,
+        ``END``
+    """
+    START = "START"
+    END = "END"
+
+
+class ROLE(StrEnum):
+    """Enum for ROLE from :rfc:`5545`.
+
+    Attributes:
+        ``CHAIR``,
+        ``REQ-PARTICIPANT``,
+        ``OPT-PARTICIPANT``,
+        ``NON-PARTICIPANT``
+    """
+    CHAIR = "CHAIR"
+    REQ_PARTICIPANT = "REQ-PARTICIPANT"
+    OPT_PARTICIPANT = "OPT-PARTICIPANT"
+    NON_PARTICIPANT = "NON-PARTICIPANT"
+
+
+__all__ = [
+    "PARTSTAT",
+    "FBTYPE",
+    "CUTYPE",
+    "RANGE",
+    "RELATED",
+    "ROLE",
+    "RELTYPE",
+]
diff -pruN 6.0.1-3/src/icalendar/error.py 6.3.1-1/src/icalendar/error.py
--- 6.0.1-3/src/icalendar/error.py	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/error.py	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,67 @@
+"""Errors thrown by icalendar."""
+
+
+class InvalidCalendar(ValueError):
+    """The calendar given is not valid.
+
+    This calendar does not conform with RFC 5545 or breaks other RFCs.
+    """
+
+
+class IncompleteComponent(ValueError):
+    """The component is missing attributes.
+
+    The attributes are not required, otherwise this would be
+    an InvalidCalendar. But in order to perform calculations,
+    this attribute is required.
+
+    This error is not raised in the UPPERCASE properties like .DTSTART,
+    only in the lowercase computations like .start.
+    """
+
+
+class IncompleteAlarmInformation(ValueError):
+    """The alarms cannot be calculated yet because information is missing."""
+
+
+class LocalTimezoneMissing(IncompleteAlarmInformation):
+    """We are missing the local timezone to compute the value.
+
+    Use Alarms.set_local_timezone().
+    """
+
+
+class ComponentEndMissing(IncompleteAlarmInformation):
+    """We are missing the end of a component that the alarm is for.
+
+    Use Alarms.set_end().
+    """
+
+
+class ComponentStartMissing(IncompleteAlarmInformation):
+    """We are missing the start of a component that the alarm is for.
+
+    Use Alarms.set_start().
+    """
+
+class FeatureWillBeRemovedInFutureVersion(DeprecationWarning):
+    """This feature will be removed in a future version."""
+
+
+class WillBeRemovedInVersion7(FeatureWillBeRemovedInFutureVersion):
+    """This feature will be removed in icalendar version 7.
+
+    Suppress FeatureWillBeRemovedInFutureVersion instead.
+    """
+
+__all__ = [
+    "InvalidCalendar",
+    "IncompleteComponent",
+    "IncompleteAlarmInformation",
+    "LocalTimezoneMissing",
+    "ComponentEndMissing",
+    
+    "ComponentStartMissing",
+    "FeatureWillBeRemovedInFutureVersion",
+    "WillBeRemovedInVersion7",
+]
diff -pruN 6.0.1-3/src/icalendar/fuzzing/ical_fuzzer.py 6.3.1-1/src/icalendar/fuzzing/ical_fuzzer.py
--- 6.0.1-3/src/icalendar/fuzzing/ical_fuzzer.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/fuzzing/ical_fuzzer.py	2025-05-20 07:31:39.000000000 +0000
@@ -23,12 +23,30 @@ with atheris.instrument_imports():
     from icalendar.tests.fuzzed import fuzz_calendar_v1
 
 _value_error_matches = [
-    "component", "parse", "Expected", "Wrong date format", "END encountered",
-    "vDDD", 'recurrence', 'Offset must', 'Invalid iCalendar',
-    'alue MUST', 'Key name', 'Invalid content line', 'does not exist',
-    'base 64', 'must use datetime', 'Unknown date type', 'Wrong',
-    'Start time', 'iCalendar', 'recurrence', 'float, float', 'utc offset',
-    'parent', 'MUST be a datetime'
+    "component",
+    "parse",
+    "Expected",
+    "Wrong date format",
+    "END encountered",
+    "vDDD",
+    "recurrence",
+    "Offset must",
+    "Invalid iCalendar",
+    "alue MUST",
+    "Key name",
+    "Invalid content line",
+    "does not exist",
+    "base 64",
+    "must use datetime",
+    "Unknown date type",
+    "Wrong",
+    "Start time",
+    "iCalendar",
+    "recurrence",
+    "float, float",
+    "utc offset",
+    "parent",
+    "MUST be a datetime",
 ]
 
 
@@ -43,11 +61,18 @@ def TestOneInput(data):
         try:
             # print the ICS file for the test case extraction
             # see https://stackoverflow.com/a/27367173/1320237
-            print(base64.b64encode(calendar_string.encode("UTF-8", "surrogateescape")).decode("ASCII"))
-        except UnicodeEncodeError: pass
+            print(
+                base64.b64encode(
+                    calendar_string.encode("UTF-8", "surrogateescape")
+                ).decode("ASCII")
+            )
+        except UnicodeEncodeError:
+            pass
         print("--- end calendar ---")
 
-        fuzz_calendar_v1(icalendar.Calendar.from_ical, calendar_string, multiple, should_walk)
+        fuzz_calendar_v1(
+            icalendar.Calendar.from_ical, calendar_string, multiple, should_walk
+        )
     except ValueError as e:
         if any(m in str(e) for m in _value_error_matches):
             return -1
diff -pruN 6.0.1-3/src/icalendar/param.py 6.3.1-1/src/icalendar/param.py
--- 6.0.1-3/src/icalendar/param.py	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/param.py	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,454 @@
+"""Parameter access for icalendar.
+
+Related:
+
+- :rfc:`5545`, Section 3.2. Property Parameters
+- :rfc:`7986`, Section 6. Property Parameters
+- https://github.com/collective/icalendar/issues/798
+"""
+from __future__ import annotations
+
+import functools
+from typing import TYPE_CHECKING, Callable, Optional, TypeVar, Union
+
+from icalendar import enums
+
+if TYPE_CHECKING:
+    from enum import Enum
+
+    from icalendar.parser import Parameters
+
+
+class IcalendarProperty:
+    """Interface provided by properties in icalendar.prop."""
+    params: Parameters
+
+
+def _default_return_none() -> Optional[str]:
+    """Return None by default."""
+    return None
+
+
+def _default_return_string() -> str:
+    """Return None by default."""
+    return ""
+
+T = TypeVar("T")
+
+def string_parameter(
+        name:str,
+        doc:str,
+        default:Callable = _default_return_none,
+        convert:Optional[Callable[[str], T]] = None,
+        convert_to:Optional[Callable[[T], str]] = None
+    ) -> property:
+    """Return a parameter with a quoted value (case sensitive)."""
+
+    if convert_to is None:
+        convert_to = convert
+
+    @functools.wraps(default)
+    def fget(self: IcalendarProperty) -> Optional[str]:
+        value = self.params.get(name)
+        if value is None:
+            return default()
+        return convert(value) if convert else value
+
+    def fset(self: IcalendarProperty, value: str):
+        self.params[name] = convert_to(value) if convert_to else value
+
+    def fdel(self: IcalendarProperty):
+        self.params.pop(name, None)
+
+    return property(fget, fset, fdel, doc=doc)
+
+
+ALTREP = string_parameter(
+    "ALTREP",
+    """ALTREP - Specify an alternate text representation for the property value.
+
+Description:
+    This parameter specifies a URI that points to an
+    alternate representation for a textual property value.  A property
+    specifying this parameter MUST also include a value that reflects
+    the default representation of the text value.  The URI parameter
+    value MUST be specified in a quoted-string.
+
+.. note::
+
+    While there is no restriction imposed on the URI schemes
+    allowed for this parameter, Content Identifier (CID) :rfc:`2392`,
+    HTTP :rfc:`2616`, and HTTPS :rfc:`2818` are the URI schemes most
+    commonly used by current implementations.
+""")
+
+CN = string_parameter(
+    "CN",
+    """Specify the common name to be associated with the calendar user specified.
+
+Description:
+    This parameter can be specified on properties with a
+    CAL-ADDRESS value type.  The parameter specifies the common name
+    to be associated with the calendar user specified by the property.
+    The parameter value is text.  The parameter value can be used for
+    display text to be associated with the calendar address specified
+    by the property.
+""",
+    default=_default_return_string
+)
+
+def _default_return_individual() -> enums.CUTYPE|str:
+    """Default value."""
+    return enums.CUTYPE.INDIVIDUAL
+
+def _convert_enum(enum: type[Enum]) -> Callable[[str], Enum]:
+
+    def convert(value: str) -> str:
+        """Convert if possible."""
+        try:
+            return enum(value.upper())
+        except ValueError:
+            return value
+    return convert
+
+CUTYPE = string_parameter(
+    "CUTYPE",
+    """Identify the type of calendar user specified by the property.
+
+Description:
+    This parameter can be specified on properties with a
+    CAL-ADDRESS value type.  The parameter identifies the type of
+    calendar user specified by the property.  If not specified on a
+    property that allows this parameter, the default is INDIVIDUAL.
+    Applications MUST treat x-name and iana-token values they don't
+    recognize the same way as they would the UNKNOWN value.
+""", default=_default_return_individual, convert=_convert_enum(enums.CUTYPE))
+
+
+def quoted_list_parameter(name: str, doc: str) -> property:
+    """Return a parameter that contains a quoted list."""
+
+    def fget(self: IcalendarProperty) -> tuple[str]:
+        value = self.params.get(name)
+        if value is None:
+            return ()
+        if isinstance(value, str):
+            return tuple(value.split(","))
+        return value
+
+    def fset(self: IcalendarProperty, value: str|tuple[str]):
+        if value == ():
+            fdel(self)
+        else:
+            self.params[name] = (value,) if isinstance(value, str) else value
+
+    def fdel(self: IcalendarProperty):
+        self.params.pop(name, None)
+
+    return property(fget, fset, fdel, doc=doc)
+
+
+DELEGATED_FROM = quoted_list_parameter(
+    "DELEGATED-FROM",
+    """Specify the calendar users that have delegated their participation to the calendar user specified by the property.
+
+Description:
+    This parameter can be specified on properties with a
+    CAL-ADDRESS value type.  This parameter specifies those calendar
+    users that have delegated their participation in a group-scheduled
+    event or to-do to the calendar user specified by the property.
+    The individual calendar address parameter values MUST each be
+    specified in a quoted-string.
+""")
+
+DELEGATED_TO = quoted_list_parameter(
+    "DELEGATED-TO",
+    """Specify the calendar users to whom the calendar user specified by the property has delegated participation.
+
+Description:
+    This parameter can be specified on properties with a
+    CAL-ADDRESS value type.  This parameter specifies those calendar
+    users whom have been delegated participation in a group-scheduled
+    event or to-do by the calendar user specified by the property.
+    The individual calendar address parameter values MUST each be
+    specified in a quoted-string.
+    """)
+
+DIR = string_parameter(
+    "DIR",
+    """Specify reference to a directory entry associated with the calendar user specified by the property.
+
+Description:
+    This parameter can be specified on properties with a
+    CAL-ADDRESS value type.  The parameter specifies a reference to
+    the directory entry associated with the calendar user specified by
+    the property.  The parameter value is a URI.  The URI parameter
+    value MUST be specified in a quoted-string.
+
+.. note::
+
+    While there is no restriction imposed on the URI schemes
+    allowed for this parameter, CID :rfc:`2392`, DATA :rfc:`2397`, FILE
+    :rfc:`1738`, FTP :rfc:`1738`, HTTP :rfc:`2616`, HTTPS :rfc:`2818`, LDAP
+    :rfc:`4516`, and MID :rfc:`2392` are the URI schemes most commonly
+    used by current implementations.
+""")
+
+def _default_return_busy() -> enums.FBTYPE|str:
+    """Default value."""
+    return enums.FBTYPE.BUSY
+
+FBTYPE = string_parameter(
+    "FBTYPE",
+    """Specify the free or busy time type.
+
+Description:
+    This parameter specifies the free or busy time type.
+    The value FREE indicates that the time interval is free for
+    scheduling.  The value BUSY indicates that the time interval is
+    busy because one or more events have been scheduled for that
+    interval.  The value BUSY-UNAVAILABLE indicates that the time
+    interval is busy and that the interval can not be scheduled.  The
+    value BUSY-TENTATIVE indicates that the time interval is busy
+    because one or more events have been tentatively scheduled for
+    that interval.  If not specified on a property that allows this
+    parameter, the default is BUSY.  Applications MUST treat x-name
+    and iana-token values they don't recognize the same way as they
+    would the BUSY value.
+""", default=_default_return_busy, convert=_convert_enum(enums.FBTYPE))
+
+LANGUAGE = string_parameter(
+    "LANGUAGE",
+    """Specify the language for text values in a property or property parameter.
+
+Description:
+    This parameter identifies the language of the text in
+    the property value and of all property parameter values of the
+    property.  The value of the "LANGUAGE" property parameter is that
+    defined in :rfc:`5646`.
+
+    For transport in a MIME entity, the Content-Language header field
+    can be used to set the default language for the entire body part.
+    Otherwise, no default language is assumed.
+""")
+
+MEMBER = quoted_list_parameter(
+    "MEMBER",
+    """Specify the group or list membership of the calendar user specified by the property.
+
+Description:
+    This parameter can be specified on properties with a
+    CAL-ADDRESS value type.  The parameter identifies the groups or
+    list membership for the calendar user specified by the property.
+    The parameter value is either a single calendar address in a
+    quoted-string or a COMMA-separated list of calendar addresses,
+    each in a quoted-string.  The individual calendar address
+    parameter values MUST each be specified in a quoted-string.
+"""
+)
+
+def _default_return_needs_action() -> enums.PARTSTAT|str:
+    """Default value."""
+    return enums.PARTSTAT.NEEDS_ACTION
+
+PARTSTAT = string_parameter(
+    "PARTSTAT",
+    """Specify the participation status for the calendar user specified by the property.
+
+Description:
+    This parameter can be specified on properties with a
+    CAL-ADDRESS value type.  The parameter identifies the
+    participation status for the calendar user specified by the
+    property value.  The parameter values differ depending on whether
+    they are associated with a group-scheduled "VEVENT", "VTODO", or
+    "VJOURNAL".  The values MUST match one of the values allowed for
+    the given calendar component.  If not specified on a property that
+    allows this parameter, the default value is NEEDS-ACTION.
+    Applications MUST treat x-name and iana-token values they don't
+    recognize the same way as they would the NEEDS-ACTION value.
+""", default=_default_return_needs_action, convert=_convert_enum(enums.PARTSTAT))
+
+def _default_range_none() -> Optional[enums.RANGE|str]:
+    return None
+
+RANGE = string_parameter(
+    "RANGE",
+    """Specify the effective range of recurrence instances from the instance specified by the recurrence identifier specified by the property.
+
+Description:
+    This parameter can be specified on a property that
+    specifies a recurrence identifier.  The parameter specifies the
+    effective range of recurrence instances that is specified by the
+    property.  The effective range is from the recurrence identifier
+    specified by the property.  If this parameter is not specified on
+    an allowed property, then the default range is the single instance
+    specified by the recurrence identifier value of the property.  The
+    parameter value can only be "THISANDFUTURE" to indicate a range
+    defined by the recurrence identifier and all subsequent instances.
+    The value "THISANDPRIOR" is deprecated by this revision of
+    iCalendar and MUST NOT be generated by applications.
+""", default=_default_range_none, convert=_convert_enum(enums.RANGE))
+
+def _default_related() -> enums.RELATED|str:
+    return enums.RELATED.START
+
+RELATED = string_parameter(
+    "RELATED",
+    """Specify the relationship of the alarm trigger with respect to the start or end of the calendar component.
+
+Description:
+    This parameter can be specified on properties that
+    specify an alarm trigger with a "DURATION" value type.  The
+    parameter specifies whether the alarm will trigger relative to the
+    start or end of the calendar component.  The parameter value START
+    will set the alarm to trigger off the start of the calendar
+    component; the parameter value END will set the alarm to trigger
+    off the end of the calendar component.  If the parameter is not
+    specified on an allowable property, then the default is START.
+
+""", default=_default_related, convert=_convert_enum(enums.RANGE))
+
+
+def _default_req_participant() -> enums.ROLE|str:
+    return enums.ROLE.REQ_PARTICIPANT
+
+ROLE = string_parameter(
+    "ROLE",
+    """Specify the participation role for the calendar user specified by the property.
+
+Description:
+    This parameter can be specified on properties with a
+    CAL-ADDRESS value type.  The parameter specifies the participation
+    role for the calendar user specified by the property in the group
+    schedule calendar component.  If not specified on a property that
+    allows this parameter, the default value is REQ-PARTICIPANT.
+    Applications MUST treat x-name and iana-token values they don't
+    recognize the same way as they would the REQ-PARTICIPANT value.
+""", default=_default_req_participant, convert=_convert_enum(enums.ROLE)
+)
+
+def boolean_parameter(name: str, default:bool, doc: str) -> property:
+
+    def _default() -> bool:
+        return default
+
+    return string_parameter(
+        name,
+        doc,
+        default=_default,
+        convert=lambda x: x.upper() == "TRUE",
+        convert_to=lambda x: "TRUE" if x else "FALSE",
+    )
+
+RSVP = boolean_parameter(
+    "RSVP",
+    False,
+    """Specify whether there is an expectation of a favor of anreply from the calendar user specified by the property value.
+
+Description:
+    This parameter can be specified on properties with a
+    CAL-ADDRESS value type.  The parameter identifies the expectation
+    of a reply from the calendar user specified by the property value.
+    This parameter is used by the "Organizer" to request a
+    participation status reply from an "Attendee" of a group-scheduled
+    event or to-do.  If not specified on a property that allows this
+    parameter, the default value is ``False``.
+"""
+)
+
+SENT_BY = string_parameter(
+    "SENT-BY",
+    """Specify the calendar user that is acting on behalf of the calendar user specified by the property.
+
+Description:
+    This parameter can be specified on properties with a
+    CAL-ADDRESS value type.  The parameter specifies the calendar user
+    that is acting on behalf of the calendar user specified by the
+    property.  The parameter value MUST be a mailto URI as defined in
+    :rfc:`2368`.  The individual calendar address parameter values MUST
+    each be specified in a quoted-string.
+"""
+)
+
+TZID = string_parameter(
+    "TZID",
+    """Specify the identifier for the time zone definition for a time component in the property value.
+
+Description:
+    This parameter MUST be specified on the "DTSTART",
+    "DTEND", "DUE", "EXDATE", and "RDATE" properties when either a
+    DATE-TIME or TIME value type is specified and when the value is
+    neither a UTC or a "floating" time.  Refer to the DATE-TIME or
+    TIME value type definition for a description of UTC and "floating
+    time" formats.  This property parameter specifies a text value
+    that uniquely identifies the "VTIMEZONE" calendar component to be
+    used when evaluating the time portion of the property.  The value
+    of the "TZID" property parameter will be equal to the value of the
+    "TZID" property for the matching time zone definition.  An
+    individual "VTIMEZONE" calendar component MUST be specified for
+    each unique "TZID" parameter value specified in the iCalendar
+    object.
+
+    The parameter MUST be specified on properties with a DATE-TIME
+    value if the DATE-TIME is not either a UTC or a "floating" time.
+    Failure to include and follow VTIMEZONE definitions in iCalendar
+    objects may lead to inconsistent understanding of the local time
+    at any given location.
+
+    The presence of the SOLIDUS character as a prefix, indicates that
+    this "TZID" represents a unique ID in a globally defined time zone
+    registry (when such registry is defined).
+
+.. note::
+
+    This document does not define a naming convention for
+    time zone identifiers.  Implementers may want to use the naming
+    conventions defined in existing time zone specifications such
+    as the public-domain TZ database (TZDB). The specification of
+    globally unique time zone identifiers is not addressed by this
+    document and is left for future study.
+"""
+)
+
+def _default_return_parent() -> enums.RELTYPE:
+    return enums.RELTYPE.PARENT
+
+RELTYPE = string_parameter(
+    "RELTYPE",
+    """Specify the type of hierarchical relationship associated with the calendar component specified by the property.
+
+Description:
+    This parameter can be specified on a property that
+    references another related calendar.  The parameter specifies the
+    hierarchical relationship type of the calendar component
+    referenced by the property.  The parameter value can be PARENT, to
+    indicate that the referenced calendar component is a superior of
+    calendar component; CHILD to indicate that the referenced calendar
+    component is a subordinate of the calendar component; or SIBLING
+    to indicate that the referenced calendar component is a peer of
+    the calendar component.  If this parameter is not specified on an
+    allowable property, the default relationship type is PARENT.
+    Applications MUST treat x-name and iana-token values they don't
+    recognize the same way as they would the PARENT value.
+""", default=_default_return_parent, convert=_convert_enum(enums.RELTYPE))
+
+__all__ = [
+    "string_parameter",
+    "quoted_list_parameter",
+    "ALTREP",
+    "CN",
+    "CUTYPE",
+    "DELEGATED_FROM",
+    "DELEGATED_TO",
+    "DIR",
+    "FBTYPE",
+    "LANGUAGE",
+    "MEMBER",
+    "PARTSTAT",
+    "RANGE",
+    "RELATED",
+    "ROLE",
+    "RSVP",
+    "SENT_BY",
+    "TZID",
+]
diff -pruN 6.0.1-3/src/icalendar/parser.py 6.3.1-1/src/icalendar/parser.py
--- 6.0.1-3/src/icalendar/parser.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/parser.py	2025-05-20 07:31:39.000000000 +0000
@@ -5,9 +5,11 @@ Eg. RFC 2426 (vCard)
 It is stupid in the sense that it treats the content purely as strings. No type
 conversion is attempted.
 """
+from __future__ import annotations
 
+import os
 from icalendar.caselessdict import CaselessDict
-from icalendar.parser_tools import DEFAULT_ENCODING
+from icalendar.parser_tools import DEFAULT_ENCODING, ICAL_TYPE
 from icalendar.parser_tools import SEQUENCE_TYPES
 from icalendar.parser_tools import to_unicode
 
@@ -15,38 +17,43 @@ import re
 
 
 def escape_char(text):
-    """Format value according to iCalendar TEXT escaping rules.
-    """
+    """Format value according to iCalendar TEXT escaping rules."""
     assert isinstance(text, (str, bytes))
     # NOTE: ORDER MATTERS!
-    return text.replace(r'\N', '\n')\
-               .replace('\\', '\\\\')\
-               .replace(';', r'\;')\
-               .replace(',', r'\,')\
-               .replace('\r\n', r'\n')\
-               .replace('\n', r'\n')
+    return (
+        text.replace(r"\N", "\n")
+        .replace("\\", "\\\\")
+        .replace(";", r"\;")
+        .replace(",", r"\,")
+        .replace("\r\n", r"\n")
+        .replace("\n", r"\n")
+    )
 
 
 def unescape_char(text):
     assert isinstance(text, (str, bytes))
     # NOTE: ORDER MATTERS!
     if isinstance(text, str):
-        return text.replace('\\N', '\\n')\
-                   .replace('\r\n', '\n')\
-                   .replace('\\n', '\n')\
-                   .replace('\\,', ',')\
-                   .replace('\\;', ';')\
-                   .replace('\\\\', '\\')
+        return (
+            text.replace("\\N", "\\n")
+            .replace("\r\n", "\n")
+            .replace("\\n", "\n")
+            .replace("\\,", ",")
+            .replace("\\;", ";")
+            .replace("\\\\", "\\")
+        )
     elif isinstance(text, bytes):
-        return text.replace(b'\\N', b'\\n')\
-                   .replace(b'\r\n', b'\n')\
-                   .replace(b'\\n', b'\n')\
-                   .replace(b'\\,', b',')\
-                   .replace(b'\\;', b';')\
-                   .replace(b'\\\\', b'\\')
+        return (
+            text.replace(b"\\N", b"\\n")
+            .replace(b"\r\n", b"\n")
+            .replace(b"\\n", b"\n")
+            .replace(b"\\,", b",")
+            .replace(b"\\;", b";")
+            .replace(b"\\\\", b"\\")
+        )
 
 
-def foldline(line, limit=75, fold_sep='\r\n '):
+def foldline(line, limit=75, fold_sep="\r\n "):
     """Make a string folded as defined in RFC5545
     Lines of text SHOULD NOT be longer than 75 octets, excluding the line
     break.  Long content lines SHOULD be split into a multiple line
@@ -56,16 +63,16 @@ def foldline(line, limit=75, fold_sep='\
     SPACE or HTAB).
     """
     assert isinstance(line, str)
-    assert '\n' not in line
+    assert "\n" not in line
 
     # Use a fast and simple variant for the common case that line is all ASCII.
     try:
-        line.encode('ascii')
+        line.encode("ascii")
     except (UnicodeEncodeError, UnicodeDecodeError):
         pass
     else:
         return fold_sep.join(
-            line[i:i + limit - 1] for i in range(0, len(line), limit - 1)
+            line[i : i + limit - 1] for i in range(0, len(line), limit - 1)
         )
 
     ret_chars = []
@@ -78,34 +85,33 @@ def foldline(line, limit=75, fold_sep='\
             byte_count = char_byte_len
         ret_chars.append(char)
 
-    return ''.join(ret_chars)
+    return "".join(ret_chars)
 
 
 #################################################################
 # Property parameter stuff
 
-def param_value(value):
-    """Returns a parameter value.
-    """
+
+def param_value(value, always_quote=False):
+    """Returns a parameter value."""
     if isinstance(value, SEQUENCE_TYPES):
-        return q_join(value)
-    elif isinstance(value, str):
-        return dquote(value)
-    else:
-        return dquote(value.to_ical().decode(DEFAULT_ENCODING))
+        return q_join(map(rfc_6868_escape, value), always_quote=always_quote)
+    if isinstance(value, str):
+        return dquote(rfc_6868_escape(value), always_quote=always_quote)
+    return dquote(rfc_6868_escape(value.to_ical().decode(DEFAULT_ENCODING)))
 
 
 # Could be improved
 
 # [\w-] because of the iCalendar RFC
 # . because of the vCard RFC
-NAME = re.compile(r'[\w.-]+')
+NAME = re.compile(r"[\w.-]+")
 
-UNSAFE_CHAR = re.compile('[\x00-\x08\x0a-\x1f\x7F",:;]')
-QUNSAFE_CHAR = re.compile('[\x00-\x08\x0a-\x1f\x7F"]')
-FOLD = re.compile(b'(\r?\n)+[ \t]')
-uFOLD = re.compile('(\r?\n)+[ \t]')
-NEWLINE = re.compile(r'\r?\n')
+UNSAFE_CHAR = re.compile('[\x00-\x08\x0a-\x1f\x7f",:;]')
+QUNSAFE_CHAR = re.compile('[\x00-\x08\x0a-\x1f\x7f"]')
+FOLD = re.compile(b"(\r?\n)+[ \t]")
+uFOLD = re.compile("(\r?\n)+[ \t]")
+NEWLINE = re.compile(r"\r?\n")
 
 
 def validate_token(name):
@@ -123,24 +129,22 @@ def validate_param_value(value, quoted=T
 
 # chars presence of which in parameter value will be cause the value
 # to be enclosed in double-quotes
-QUOTABLE = re.compile("[,;: ’']")
+QUOTABLE = re.compile("[,;:’]")
 
 
-def dquote(val):
-    """Enclose parameter values containing [,;:] in double quotes.
-    """
+def dquote(val, always_quote=False):
+    """Enclose parameter values containing [,;:] in double quotes."""
     # a double-quote character is forbidden to appear in a parameter value
     # so replace it with a single-quote character
     val = val.replace('"', "'")
-    if QUOTABLE.search(val):
+    if QUOTABLE.search(val) or always_quote:
         return f'"{val}"'
     return val
 
 
 # parsing helper
-def q_split(st, sep=',', maxsplit=-1):
-    """Splits a string on char, taking double (q)uotes into considderation.
-    """
+def q_split(st, sep=",", maxsplit=-1):
+    """Splits a string on char, taking double (q)uotes into considderation."""
     if maxsplit == 0:
         return [st]
 
@@ -162,16 +166,33 @@ def q_split(st, sep=',', maxsplit=-1):
     return result
 
 
-def q_join(lst, sep=','):
-    """Joins a list on sep, quoting strings with QUOTABLE chars.
-    """
-    return sep.join(dquote(itm) for itm in lst)
+def q_join(lst, sep=",", always_quote=False):
+    """Joins a list on sep, quoting strings with QUOTABLE chars."""
+    return sep.join(dquote(itm, always_quote=always_quote) for itm in lst)
 
 
 class Parameters(CaselessDict):
     """Parser and generator of Property parameter strings. It knows nothing of
     datatypes. Its main concern is textual structure.
     """
+    
+    # The following paremeters must always be enclosed in double quotes
+    always_quoted = (
+        "ALTREP",
+        "DELEGATED-FROM",
+        "DELEGATED-TO",
+        "DIR",
+        "MEMBER",
+        "SENT-BY",
+        # Part of X-APPLE-STRUCTURED-LOCATION
+        "X-ADDRESS",
+        "X-TITLE",
+    )
+    # this is quoted should one of the values be present
+    quote_also = {
+        # This is escaped in the RFC
+        "CN" : " '",
+    }
 
     def params(self):
         """In RFC 5545 keys are called parameters, so this is to be consitent
@@ -179,24 +200,24 @@ class Parameters(CaselessDict):
         """
         return self.keys()
 
-# TODO?
-# Later, when I get more time... need to finish this off now. The last major
-# thing missing.
-#   def _encode(self, name, value, cond=1):
-#       # internal, for conditional convertion of values.
-#       if cond:
-#           klass = types_factory.for_property(name)
-#           return klass(value)
-#       return value
-#
-#   def add(self, name, value, encode=0):
-#       "Add a parameter value and optionally encode it."
-#       if encode:
-#           value = self._encode(name, value, encode)
-#       self[name] = value
-#
-#   def decoded(self, name):
-#       "returns a decoded value, or list of same"
+    # TODO?
+    # Later, when I get more time... need to finish this off now. The last major
+    # thing missing.
+    #   def _encode(self, name, value, cond=1):
+    #       # internal, for conditional convertion of values.
+    #       if cond:
+    #           klass = types_factory.for_property(name)
+    #           return klass(value)
+    #       return value
+    #
+    #   def add(self, name, value, encode=0):
+    #       "Add a parameter value and optionally encode it."
+    #       if encode:
+    #           value = self._encode(name, value, encode)
+    #       self[name] = value
+    #
+    #   def decoded(self, name):
+    #       "returns a decoded value, or list of same"
 
     def to_ical(self, sorted=True):
         result = []
@@ -205,13 +226,20 @@ class Parameters(CaselessDict):
             items.sort()
 
         for key, value in items:
-            value = param_value(value)
-            if isinstance(value, str):
-                value = value.encode(DEFAULT_ENCODING)
+            upper_key = key.upper()
+            check_quoteable_characters = self.quote_also.get(key.upper())
+            always_quote = (
+                upper_key in self.always_quoted or (
+                    check_quoteable_characters and
+                    any(c in value for c in check_quoteable_characters)
+                )
+            )
+            quoted_value = param_value(value, always_quote=always_quote)
+            if isinstance(quoted_value, str):
+                quoted_value = quoted_value.encode(DEFAULT_ENCODING)
             # CaselessDict keys are always unicode
-            key = key.upper().encode(DEFAULT_ENCODING)
-            result.append(key + b'=' + value)
-        return b';'.join(result)
+            result.append(upper_key.encode(DEFAULT_ENCODING) + b"=" + quoted_value)
+        return b";".join(result)
 
     @classmethod
     def from_ical(cls, st, strict=False):
@@ -219,24 +247,24 @@ class Parameters(CaselessDict):
 
         # parse into strings
         result = cls()
-        for param in q_split(st, ';'):
+        for param in q_split(st, ";"):
             try:
-                key, val = q_split(param, '=', maxsplit=1)
+                key, val = q_split(param, "=", maxsplit=1)
                 validate_token(key)
                 # Property parameter values that are not in quoted
                 # strings are case insensitive.
                 vals = []
-                for v in q_split(val, ','):
+                for v in q_split(val, ","):
                     if v.startswith('"') and v.endswith('"'):
                         v = v.strip('"')
                         validate_param_value(v, quoted=True)
-                        vals.append(v)
+                        vals.append(rfc_6868_unescape(v))
                     else:
                         validate_param_value(v, quoted=False)
                         if strict:
-                            vals.append(v.upper())
+                            vals.append(rfc_6868_unescape(v.upper()))
                         else:
-                            vals.append(v)
+                            vals.append(rfc_6868_unescape(v))
                 if not vals:
                     result[key] = val
                 else:
@@ -245,21 +273,65 @@ class Parameters(CaselessDict):
                     else:
                         result[key] = vals
             except ValueError as exc:
-                raise ValueError(
-                    f'{param!r} is not a valid parameter string: {exc}')
+                raise ValueError(f"{param!r} is not a valid parameter string: {exc}")
         return result
 
 
 def escape_string(val):
     # f'{i:02X}'
-    return val.replace(r'\,', '%2C').replace(r'\:', '%3A')\
-              .replace(r'\;', '%3B').replace(r'\\', '%5C')
+    return (
+        val.replace(r"\,", "%2C")
+        .replace(r"\:", "%3A")
+        .replace(r"\;", "%3B")
+        .replace(r"\\", "%5C")
+    )
 
 
 def unescape_string(val):
-    return val.replace('%2C', ',').replace('%3A', ':')\
-              .replace('%3B', ';').replace('%5C', '\\')
+    return (
+        val.replace("%2C", ",")
+        .replace("%3A", ":")
+        .replace("%3B", ";")
+        .replace("%5C", "\\")
+    )
+
 
+RFC_6868_UNESCAPE_REGEX = re.compile(r"\^\^|\^n|\^'")
+
+
+def rfc_6868_unescape(param_value: str) -> str:
+    """Take care of :rfc:`6868` unescaping.
+
+    - ^^ -> ^
+    - ^n -> system specific newline
+    - ^' -> "
+    - ^ with others stay intact
+    """
+    replacements = {
+        "^^": "^",
+        "^n": os.linesep,
+        "^'": '"',
+    }
+    return RFC_6868_UNESCAPE_REGEX.sub(lambda m: replacements.get(m.group(0), m.group(0)), param_value)
+
+
+RFC_6868_ESCAPE_REGEX = re.compile(r'\^|\r\n|\r|\n|"')
+
+def rfc_6868_escape(param_value: str) -> str:
+    """Take care of :rfc:`6868` escaping.
+
+    - ^ -> ^^
+    - " -> ^'
+    - newline -> ^n
+    """
+    replacements = {
+        "^": "^^",
+        "\n": "^n",
+        "\r": "^n",
+        "\r\n": "^n",
+        '"': "^'",
+    }
+    return RFC_6868_ESCAPE_REGEX.sub(lambda m: replacements.get(m.group(0), m.group(0)), param_value)
 
 def unescape_list_or_string(val):
     if isinstance(val, list):
@@ -271,26 +343,29 @@ def unescape_list_or_string(val):
 #########################################
 # parsing and generation of content lines
 
+
 class Contentline(str):
     """A content line is basically a string that can be folded and parsed into
     parts.
     """
+
     def __new__(cls, value, strict=False, encoding=DEFAULT_ENCODING):
         value = to_unicode(value, encoding=encoding)
-        assert '\n' not in value, ('Content line can not contain unescaped '
-                                   'new line characters.')
+        assert "\n" not in value, (
+            "Content line can not contain unescaped " "new line characters."
+        )
         self = super().__new__(cls, value)
         self.strict = strict
         return self
 
     @classmethod
-    def from_parts(cls, name, params, values, sorted=True):
-        """Turn a parts into a content line.
-        """
+    def from_parts(cls, name:ICAL_TYPE, params: Parameters, values, sorted=True):
+        """Turn a parts into a content line."""
         assert isinstance(params, Parameters)
-        if hasattr(values, 'to_ical'):
+        if hasattr(values, "to_ical"):
             values = values.to_ical()
         else:
+            from icalendar.prop import vText
             values = vText(values).to_ical()
         # elif isinstance(values, basestring):
         #    values = escape_char(values)
@@ -301,12 +376,11 @@ class Contentline(str):
         values = to_unicode(values)
         if params:
             params = to_unicode(params.to_ical(sorted=sorted))
-            return cls(f'{name};{params}:{values}')
-        return cls(f'{name}:{values}')
+            return cls(f"{name};{params}:{values}")
+        return cls(f"{name}:{values}")
 
     def parts(self):
-        """Split the content line up into (name, parameters, values) parts.
-        """
+        """Split the content line up into (name, parameters, values) parts."""
         try:
             st = escape_string(self)
             name_split = None
@@ -314,39 +388,40 @@ class Contentline(str):
             in_quotes = False
             for i, ch in enumerate(st):
                 if not in_quotes:
-                    if ch in ':;' and not name_split:
+                    if ch in ":;" and not name_split:
                         name_split = i
-                    if ch == ':' and not value_split:
+                    if ch == ":" and not value_split:
                         value_split = i
                 if ch == '"':
                     in_quotes = not in_quotes
             name = unescape_string(st[:name_split])
             if not name:
-                raise ValueError('Key name is required')
+                raise ValueError("Key name is required")
             validate_token(name)
             if not value_split:
                 value_split = i + 1
             if not name_split or name_split + 1 == value_split:
-                raise ValueError('Invalid content line')
-            params = Parameters.from_ical(st[name_split + 1: value_split],
-                                          strict=self.strict)
+                raise ValueError("Invalid content line")
+            params = Parameters.from_ical(
+                st[name_split + 1 : value_split], strict=self.strict
+            )
             params = Parameters(
                 (unescape_string(key), unescape_list_or_string(value))
                 for key, value in iter(params.items())
             )
-            values = unescape_string(st[value_split + 1:])
+            values = unescape_string(st[value_split + 1 :])
             return (name, params, values)
         except ValueError as exc:
             raise ValueError(
-                f"Content line could not be parsed into parts: '{self}': {exc}")
+                f"Content line could not be parsed into parts: '{self}': {exc}"
+            ) from exc
 
     @classmethod
     def from_ical(cls, ical, strict=False):
-        """Unfold the content lines in an iCalendar into long content lines.
-        """
+        """Unfold the content lines in an iCalendar into long content lines."""
         ical = to_unicode(ical)
         # a fold is carriage return followed by either a space or a tab
-        return cls(uFOLD.sub('', ical), strict=strict)
+        return cls(uFOLD.sub("", ical), strict=strict)
 
     def to_ical(self):
         """Long content lines are folded so they are less than 75 characters
@@ -362,33 +437,46 @@ class Contentlines(list):
     """
 
     def to_ical(self):
-        """Simply join self.
-        """
-        return b'\r\n'.join(line.to_ical() for line in self if line) + b'\r\n'
+        """Simply join self."""
+        return b"\r\n".join(line.to_ical() for line in self if line) + b"\r\n"
 
     @classmethod
     def from_ical(cls, st):
-        """Parses a string into content lines.
-        """
+        """Parses a string into content lines."""
         st = to_unicode(st)
         try:
             # a fold is carriage return followed by either a space or a tab
-            unfolded = uFOLD.sub('', st)
-            lines = cls(Contentline(line) for
-                        line in NEWLINE.split(unfolded) if line)
-            lines.append('')  # '\r\n' at the end of every content line
+            unfolded = uFOLD.sub("", st)
+            lines = cls(Contentline(line) for line in NEWLINE.split(unfolded) if line)
+            lines.append("")  # '\r\n' at the end of every content line
             return lines
         except Exception:
-            raise ValueError('Expected StringType with content lines')
-
-
-# XXX: what kind of hack is this? import depends to be at end
-from icalendar.prop import vText
+            raise ValueError("Expected StringType with content lines")
 
 
-__all__ = ["Contentline", "Contentlines", "FOLD", "NAME", "NEWLINE",
-           "Parameters", "QUNSAFE_CHAR", "QUOTABLE", "UNSAFE_CHAR", "dquote",
-           "escape_char", "escape_string", "foldline", "param_value", "q_join",
-           "q_split", "uFOLD", "unescape_char",
-           "unescape_list_or_string", "unescape_string", "validate_param_value",
-           "validate_token"]
+__all__ = [
+    "Contentline",
+    "Contentlines",
+    "FOLD",
+    "NAME",
+    "NEWLINE",
+    "Parameters",
+    "QUNSAFE_CHAR",
+    "QUOTABLE",
+    "UNSAFE_CHAR",
+    "dquote",
+    "escape_char",
+    "escape_string",
+    "foldline",
+    "param_value",
+    "q_join",
+    "q_split",
+    "rfc_6868_escape",
+    "rfc_6868_unescape",
+    "uFOLD",
+    "unescape_char",
+    "unescape_list_or_string",
+    "unescape_string",
+    "validate_param_value",
+    "validate_token",
+]
diff -pruN 6.0.1-3/src/icalendar/parser_tools.py 6.3.1-1/src/icalendar/parser_tools.py
--- 6.0.1-3/src/icalendar/parser_tools.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/parser_tools.py	2025-05-20 07:31:39.000000000 +0000
@@ -1,11 +1,11 @@
-from typing import Any, Union
+from typing import List, Union
 
 SEQUENCE_TYPES = (list, tuple)
-DEFAULT_ENCODING = 'utf-8'
+DEFAULT_ENCODING = "utf-8"
 ICAL_TYPE = Union[str, bytes]
 
 
-def from_unicode(value: ICAL_TYPE, encoding='utf-8') -> bytes:
+def from_unicode(value: ICAL_TYPE, encoding="utf-8") -> bytes:
     """
     Converts a value to bytes, even if it already is bytes
     :param value: The value to convert
@@ -13,29 +13,32 @@ def from_unicode(value: ICAL_TYPE, encod
     :return: The bytes representation of the value
     """
     if isinstance(value, bytes):
-        value = value
+        return value
     elif isinstance(value, str):
         try:
-            value = value.encode(encoding)
+            return value.encode(encoding)
         except UnicodeEncodeError:
-            value = value.encode('utf-8', 'replace')
-    return value
+            return value.encode("utf-8", "replace")
+    else:
+        return value
 
 
-def to_unicode(value: ICAL_TYPE, encoding='utf-8-sig') -> str:
-    """Converts a value to unicode, even if it is already a unicode string.
-    """
+def to_unicode(value: ICAL_TYPE, encoding="utf-8-sig") -> str:
+    """Converts a value to unicode, even if it is already a unicode string."""
     if isinstance(value, str):
         return value
     elif isinstance(value, bytes):
         try:
-            value = value.decode(encoding)
+            return value.decode(encoding)
         except UnicodeDecodeError:
-            value = value.decode('utf-8-sig', 'replace')
-    return value
+            return value.decode("utf-8-sig", "replace")
+    else:
+        return value
 
 
-def data_encode(data: Union[ICAL_TYPE, dict, list], encoding=DEFAULT_ENCODING) -> bytes:
+def data_encode(
+    data: Union[ICAL_TYPE, dict, list], encoding=DEFAULT_ENCODING
+) -> Union[bytes, List[bytes], dict]:
     """Encode all datastructures to the given encoding.
     Currently unicode strings, dicts and lists are supported.
     """
@@ -50,5 +53,11 @@ def data_encode(data: Union[ICAL_TYPE, d
         return data
 
 
-__all__ = ["DEFAULT_ENCODING", "SEQUENCE_TYPES", "ICAL_TYPE", "data_encode", "from_unicode",
-           "to_unicode"]
+__all__ = [
+    "DEFAULT_ENCODING",
+    "SEQUENCE_TYPES",
+    "ICAL_TYPE",
+    "data_encode",
+    "from_unicode",
+    "to_unicode",
+]
diff -pruN 6.0.1-3/src/icalendar/prop.py 6.3.1-1/src/icalendar/prop.py
--- 6.0.1-3/src/icalendar/prop.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/prop.py	2025-05-20 07:31:39.000000000 +0000
@@ -7,12 +7,16 @@ prefer) for the classes/datatypes that a
 
 4.2 Defined property parameters are:
 
+.. code-block:: text
+
      ALTREP, CN, CUTYPE, DELEGATED-FROM, DELEGATED-TO, DIR, ENCODING, FMTTYPE,
      FBTYPE, LANGUAGE, MEMBER, PARTSTAT, RANGE, RELATED, RELTYPE, ROLE, RSVP,
      SENT-BY, TZID, VALUE
 
 4.3 Defined value data types are:
 
+.. code-block:: text
+
     BINARY, BOOLEAN, CAL-ADDRESS, DATE, DATE-TIME, DURATION, FLOAT, INTEGER,
     PERIOD, RECUR, TEXT, TIME, URI, UTC-OFFSET
 
@@ -30,75 +34,65 @@ from_ical() method. The to_ical() method
 iCalendar format. The from_ical() method can parse this format and return a
 primitive Python datatype. So it should always be true that:
 
+.. code-block:: python
+
     x == vDataType.from_ical(VDataType(x).to_ical())
 
 These types are mainly used for parsing and file generation. But you can set
 them directly.
 """
-from datetime import date
-from datetime import datetime
-from datetime import time
-from datetime import timedelta
-from datetime import tzinfo
-from icalendar.caselessdict import CaselessDict
-from icalendar.parser import Parameters
-from icalendar.parser import escape_char
-from icalendar.parser import unescape_char
-from icalendar.parser_tools import (
-    DEFAULT_ENCODING, SEQUENCE_TYPES, to_unicode, from_unicode, ICAL_TYPE
-)
+
+from __future__ import annotations
 
 import base64
 import binascii
-from .timezone import tzp
 import re
-import time as _time
+from datetime import date, datetime, time, timedelta
+from typing import Union
 
-from typing import Optional, Union
-from enum import Enum, auto
+from icalendar.caselessdict import CaselessDict
+from icalendar.enums import Enum
+from icalendar.parser import Parameters, escape_char, unescape_char
+from icalendar.parser_tools import (
+    DEFAULT_ENCODING,
+    ICAL_TYPE,
+    SEQUENCE_TYPES,
+    from_unicode,
+    to_unicode,
+)
 
+from .timezone import tzid_from_dt, tzid_from_tzinfo, tzp
 
-DURATION_REGEX = re.compile(r'([-+]?)P(?:(\d+)W)?(?:(\d+)D)?'
-                            r'(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?)?$')
+DURATION_REGEX = re.compile(
+    r"([-+]?)P(?:(\d+)W)?(?:(\d+)D)?" r"(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?)?$"
+)
 
-WEEKDAY_RULE = re.compile(r'(?P<signal>[+-]?)(?P<relative>[\d]{0,2})'
-                          r'(?P<weekday>[\w]{2})$')
-
-
-def tzid_from_dt(dt: datetime) -> Optional[str]:
-    """Retrieve the timezone id from the datetime object."""
-    tzid = None
-    if hasattr(dt.tzinfo, 'zone'):
-        tzid = dt.tzinfo.zone  # pytz implementation
-    elif hasattr(dt.tzinfo, 'key'):
-        tzid = dt.tzinfo.key  # ZoneInfo implementation
-    elif hasattr(dt.tzinfo, 'tzname'):
-        # dateutil implementation, but this is broken
-        # See https://github.com/collective/icalendar/issues/333 for details
-        tzid = dt.tzinfo.tzname(dt)
-    return tzid
+WEEKDAY_RULE = re.compile(
+    r"(?P<signal>[+-]?)(?P<relative>[\d]{0,2})" r"(?P<weekday>[\w]{2})$"
+)
 
 
 class vBinary:
-    """Binary property values are base 64 encoded.
-    """
+    """Binary property values are base 64 encoded."""
+
+    params: Parameters
 
     def __init__(self, obj):
         self.obj = to_unicode(obj)
-        self.params = Parameters(encoding='BASE64', value="BINARY")
+        self.params = Parameters(encoding="BASE64", value="BINARY")
 
     def __repr__(self):
         return f"vBinary({self.to_ical()})"
 
     def to_ical(self):
-        return binascii.b2a_base64(self.obj.encode('utf-8'))[:-1]
+        return binascii.b2a_base64(self.obj.encode("utf-8"))[:-1]
 
     @staticmethod
     def from_ical(ical):
         try:
             return base64.b64decode(ical)
         except (ValueError, UnicodeError):
-            raise ValueError('Not valid base 64 encoding.')
+            raise ValueError("Not valid base 64 encoding.")
 
     def __eq__(self, other):
         """self == other"""
@@ -106,17 +100,55 @@ class vBinary:
 
 
 class vBoolean(int):
-    """Returns specific string according to state.
+    """Boolean
+
+    Value Name:  BOOLEAN
+
+    Purpose:  This value type is used to identify properties that contain
+      either a "TRUE" or "FALSE" Boolean value.
+
+    Format Definition:  This value type is defined by the following
+      notation:
+
+    .. code-block:: text
+
+        boolean    = "TRUE" / "FALSE"
+
+    Description:  These values are case-insensitive text.  No additional
+      content value encoding is defined for this value type.
+
+    Example:  The following is an example of a hypothetical property that
+      has a BOOLEAN value type:
+
+    .. code-block:: python
+
+        TRUE
+
+    .. code-block:: pycon
+
+        >>> from icalendar.prop import vBoolean
+        >>> boolean = vBoolean.from_ical('TRUE')
+        >>> boolean
+        True
+        >>> boolean = vBoolean.from_ical('FALSE')
+        >>> boolean
+        False
+        >>> boolean = vBoolean.from_ical('True')
+        >>> boolean
+        True
     """
-    BOOL_MAP = CaselessDict({'true': True, 'false': False})
 
-    def __new__(cls, *args, **kwargs):
+    params: Parameters
+
+    BOOL_MAP = CaselessDict({"true": True, "false": False})
+
+    def __new__(cls, *args, params={}, **kwargs):
         self = super().__new__(cls, *args, **kwargs)
-        self.params = Parameters()
+        self.params = Parameters(params)
         return self
 
     def to_ical(self):
-        return b'TRUE' if self else b'FALSE'
+        return b"TRUE" if self else b"FALSE"
 
     @classmethod
     def from_ical(cls, ical):
@@ -127,14 +159,15 @@ class vBoolean(int):
 
 
 class vText(str):
-    """Simple text.
-    """
+    """Simple text."""
 
-    def __new__(cls, value, encoding=DEFAULT_ENCODING):
+    params: Parameters
+
+    def __new__(cls, value, encoding=DEFAULT_ENCODING, params={}):
         value = to_unicode(value, encoding=encoding)
         self = super().__new__(cls, value)
         self.encoding = encoding
-        self.params = Parameters()
+        self.params = Parameters(params)
         return self
 
     def __repr__(self) -> str:
@@ -144,19 +177,66 @@ class vText(str):
         return escape_char(self).encode(self.encoding)
 
     @classmethod
-    def from_ical(cls, ical:ICAL_TYPE):
+    def from_ical(cls, ical: ICAL_TYPE):
         ical_unesc = unescape_char(ical)
         return cls(ical_unesc)
 
+    from icalendar.param import ALTREP, LANGUAGE, RELTYPE
+
 
 class vCalAddress(str):
-    """This just returns an unquoted string.
+    """Calendar User Address
+
+    Value Name:
+        CAL-ADDRESS
+
+    Purpose:
+        This value type is used to identify properties that contain a
+        calendar user address.
+
+    Description:
+        The value is a URI as defined by [RFC3986] or any other
+        IANA-registered form for a URI.  When used to address an Internet
+        email transport address for a calendar user, the value MUST be a
+        mailto URI, as defined by [RFC2368].
+
+    Example:
+        ``mailto:`` is in front of the address.
+
+        .. code-block:: text
+
+            mailto:jane_doe@example.com
+
+        Parsing:
+
+        .. code-block:: pycon
+
+            >>> from icalendar import vCalAddress
+            >>> cal_address = vCalAddress.from_ical('mailto:jane_doe@example.com')
+            >>> cal_address
+            vCalAddress('mailto:jane_doe@example.com')
+
+        Encoding:
+
+        .. code-block:: pycon
+
+            >>> from icalendar import vCalAddress, Event
+            >>> event = Event()
+            >>> jane = vCalAddress("mailto:jane_doe@example.com")
+            >>> jane.name = "Jane"
+            >>> event["organizer"] = jane
+            >>> print(event.to_ical())
+            BEGIN:VEVENT
+            ORGANIZER;CN=Jane:mailto:jane_doe@example.com
+            END:VEVENT
     """
 
-    def __new__(cls, value, encoding=DEFAULT_ENCODING):
+    params: Parameters
+
+    def __new__(cls, value, encoding=DEFAULT_ENCODING, params={}):
         value = to_unicode(value, encoding=encoding)
         self = super().__new__(cls, value)
-        self.params = Parameters()
+        self.params = Parameters(params)
         return self
 
     def __repr__(self):
@@ -169,65 +249,182 @@ class vCalAddress(str):
     def from_ical(cls, ical):
         return cls(ical)
 
+    @property
+    def email(self) -> str:
+        """The email address without mailto: at the start."""
+        if self.lower().startswith("mailto:"):
+            return self[7:]
+        return str(self)
+
+    from icalendar.param import (
+        CN,
+        CUTYPE,
+        DELEGATED_FROM,
+        DELEGATED_TO,
+        DIR,
+        LANGUAGE,
+        PARTSTAT,
+        ROLE,
+        RSVP,
+        SENT_BY,
+    )
+
+    name = CN
+
 
 class vFloat(float):
-    """Just a float.
+    """Float
+
+    Value Name:
+        FLOAT
+
+    Purpose:
+        This value type is used to identify properties that contain
+        a real-number value.
+
+    Format Definition:
+        This value type is defined by the following notation:
+
+        .. code-block:: text
+
+            float      = (["+"] / "-") 1*DIGIT ["." 1*DIGIT]
+
+    Description:
+        If the property permits, multiple "float" values are
+        specified by a COMMA-separated list of values.
+
+        Example:
+
+        .. code-block:: text
+
+            1000000.0000001
+            1.333
+            -3.14
+
+        .. code-block:: pycon
+
+            >>> from icalendar.prop import vFloat
+            >>> float = vFloat.from_ical('1000000.0000001')
+            >>> float
+            1000000.0000001
+            >>> float = vFloat.from_ical('1.333')
+            >>> float
+            1.333
+            >>> float = vFloat.from_ical('+1.333')
+            >>> float
+            1.333
+            >>> float = vFloat.from_ical('-3.14')
+            >>> float
+            -3.14
     """
 
-    def __new__(cls, *args, **kwargs):
+    params: Parameters
+
+    def __new__(cls, *args, params={}, **kwargs):
         self = super().__new__(cls, *args, **kwargs)
-        self.params = Parameters()
+        self.params = Parameters(params)
         return self
 
     def to_ical(self):
-        return str(self).encode('utf-8')
+        return str(self).encode("utf-8")
 
     @classmethod
     def from_ical(cls, ical):
         try:
             return cls(ical)
         except Exception:
-            raise ValueError(f'Expected float value, got: {ical}')
+            raise ValueError(f"Expected float value, got: {ical}")
 
 
 class vInt(int):
-    """Just an int.
+    """Integer
+
+    Value Name:
+        INTEGER
+
+    Purpose:
+        This value type is used to identify properties that contain a
+        signed integer value.
+
+    Format Definition:
+        This value type is defined by the following notation:
+
+        .. code-block:: text
+
+            integer    = (["+"] / "-") 1*DIGIT
+
+    Description:
+        If the property permits, multiple "integer" values are
+        specified by a COMMA-separated list of values.  The valid range
+        for "integer" is -2147483648 to 2147483647.  If the sign is not
+        specified, then the value is assumed to be positive.
+
+        Example:
+
+        .. code-block:: text
+
+            1234567890
+            -1234567890
+            +1234567890
+            432109876
+
+        .. code-block:: pycon
+
+            >>> from icalendar.prop import vInt
+            >>> integer = vInt.from_ical('1234567890')
+            >>> integer
+            1234567890
+            >>> integer = vInt.from_ical('-1234567890')
+            >>> integer
+            -1234567890
+            >>> integer = vInt.from_ical('+1234567890')
+            >>> integer
+            1234567890
+            >>> integer = vInt.from_ical('432109876')
+            >>> integer
+            432109876
     """
 
-    def __new__(cls, *args, **kwargs):
+    params: Parameters
+
+    def __new__(cls, *args, params={}, **kwargs):
         self = super().__new__(cls, *args, **kwargs)
-        self.params = Parameters()
+        self.params = Parameters(params)
         return self
 
     def to_ical(self) -> bytes:
-        return str(self).encode('utf-8')
+        return str(self).encode("utf-8")
 
     @classmethod
-    def from_ical(cls, ical:ICAL_TYPE):
+    def from_ical(cls, ical: ICAL_TYPE):
         try:
             return cls(ical)
         except Exception:
-            raise ValueError(f'Expected int, got: {ical}')
+            raise ValueError(f"Expected int, got: {ical}")
 
 
 class vDDDLists:
-    """A list of vDDDTypes values.
-    """
+    """A list of vDDDTypes values."""
+
+    params: Parameters
+    dts: list
 
     def __init__(self, dt_list):
-        if not hasattr(dt_list, '__iter__'):
+        if not hasattr(dt_list, "__iter__"):
             dt_list = [dt_list]
         vDDD = []
         tzid = None
         for dt in dt_list:
             dt = vDDDTypes(dt)
             vDDD.append(dt)
-            if 'TZID' in dt.params:
-                tzid = dt.params['TZID']
+            if "TZID" in dt.params:
+                tzid = dt.params["TZID"]
 
+        params = {}
         if tzid:
             # NOTE: no support for multiple timezones here!
-            self.params = Parameters({'TZID': tzid})
+            params["TZID"] = tzid
+        self.params = Parameters(params)
         self.dts = vDDD
 
     def to_ical(self):
@@ -243,29 +440,41 @@ class vDDDLists:
         return out
 
     def __eq__(self, other):
-        if not isinstance(other, vDDDLists):
-            return False
-        return self.dts == other.dts
+        if isinstance(other, vDDDLists):
+            return self.dts == other.dts
+        if isinstance(other, (TimeBase, date)):
+            return self.dts == [other]
+        return False
+
+    def __repr__(self):
+        """String representation."""
+        return f"{self.__class__.__name__}({self.dts})"
 
 
 class vCategory:
+    params: Parameters
 
-    def __init__(self, c_list):
-        if not hasattr(c_list, '__iter__') or isinstance(c_list, str):
+    def __init__(self, c_list: list[str] | str, params={}):
+        if not hasattr(c_list, "__iter__") or isinstance(c_list, str):
             c_list = [c_list]
-        self.cats = [vText(c) for c in c_list]
-        self.params = Parameters()
+        self.cats: list[vText | str] = [vText(c) for c in c_list]
+        self.params = Parameters(params)
 
     def __iter__(self):
         return iter(vCategory.from_ical(self.to_ical()))
 
     def to_ical(self):
-        return b",".join([c.to_ical() for c in self.cats])
+        return b",".join(
+            [
+                c.to_ical() if hasattr(c, "to_ical") else vText(c).to_ical()
+                for c in self.cats
+            ]
+        )
 
     @staticmethod
     def from_ical(ical):
         ical = to_unicode(ical)
-        out = unescape_char(ical).split(',')
+        out = unescape_char(ical).split(",")
         return out
 
     def __eq__(self, other):
@@ -276,15 +485,36 @@ class vCategory:
 class TimeBase:
     """Make classes with a datetime/date comparable."""
 
+    params: Parameters
+    ignore_for_equality = {"TZID", "VALUE"}
+
     def __eq__(self, other):
         """self == other"""
+        if isinstance(other, date):
+            return self.dt == other
         if isinstance(other, TimeBase):
-            return self.params == other.params and self.dt == other.dt
+            default = object()
+            for key in (
+                set(self.params) | set(other.params)
+            ) - self.ignore_for_equality:
+                if key[:2].lower() != "x-" and self.params.get(
+                    key, default
+                ) != other.params.get(key, default):
+                    return False
+            return self.dt == other.dt
+        if isinstance(other, vDDDLists):
+            return other == self
         return False
 
     def __hash__(self):
         return hash(self.dt)
 
+    from icalendar.param import RANGE, RELATED, TZID
+
+    def __repr__(self):
+        """String representation."""
+        return f"{self.__class__.__name__}({self.dt}, {self.params})"
+
 
 class vDDDTypes(TimeBase):
     """A combined Datetime, Date or Duration parser/generator. Their format
@@ -292,22 +522,25 @@ class vDDDTypes(TimeBase):
     So this is practical.
     """
 
+    params: Parameters
+
     def __init__(self, dt):
         if not isinstance(dt, (datetime, date, timedelta, time, tuple)):
-            raise ValueError('You must use datetime, date, timedelta, '
-                             'time or tuple (for periods)')
+            raise ValueError(
+                "You must use datetime, date, timedelta, " "time or tuple (for periods)"
+            )
         if isinstance(dt, (datetime, timedelta)):
             self.params = Parameters()
         elif isinstance(dt, date):
-            self.params = Parameters({'value': 'DATE'})
+            self.params = Parameters({"value": "DATE"})
         elif isinstance(dt, time):
-            self.params = Parameters({'value': 'TIME'})
-        elif isinstance(dt, tuple):
-            self.params = Parameters({'value': 'PERIOD'})
+            self.params = Parameters({"value": "TIME"})
+        else:  # isinstance(dt, tuple)
+            self.params = Parameters({"value": "PERIOD"})
 
         tzid = tzid_from_dt(dt) if isinstance(dt, (datetime, time)) else None
-        if tzid is not None and tzid != 'UTC':
-            self.params.update({'TZID': tzid})
+        if tzid is not None and tzid != "UTC":
+            self.params.update({"TZID": tzid})
 
         self.dt = dt
 
@@ -324,16 +557,16 @@ class vDDDTypes(TimeBase):
         elif isinstance(dt, tuple) and len(dt) == 2:
             return vPeriod(dt).to_ical()
         else:
-            raise ValueError(f'Unknown date type: {type(dt)}')
+            raise ValueError(f"Unknown date type: {type(dt)}")
 
     @classmethod
     def from_ical(cls, ical, timezone=None):
         if isinstance(ical, cls):
             return ical.dt
         u = ical.upper()
-        if u.startswith(('P', '-P', '+P')):
+        if u.startswith(("P", "-P", "+P")):
             return vDuration.from_ical(ical)
-        if '/' in u:
+        if "/" in u:
             return vPeriod.from_ical(ical, timezone=timezone)
 
         if len(ical) in (15, 16):
@@ -343,28 +576,71 @@ class vDDDTypes(TimeBase):
         elif len(ical) in (6, 7):
             return vTime.from_ical(ical)
         else:
-            raise ValueError(
-                f"Expected datetime, date, or time, got: '{ical}'"
-            )
-
-    def __repr__(self):
-        """repr(self)"""
-        return f"{self.__class__.__name__}({self.dt}, {self.params})"
+            raise ValueError(f"Expected datetime, date, or time, got: '{ical}'")
 
 
 class vDate(TimeBase):
-    """Render and generates iCalendar date format.
+    """Date
+
+    Value Name:
+        DATE
+
+    Purpose:
+        This value type is used to identify values that contain a
+        calendar date.
+
+    Format Definition:
+        This value type is defined by the following notation:
+
+        .. code-block:: text
+
+            date               = date-value
+
+            date-value         = date-fullyear date-month date-mday
+            date-fullyear      = 4DIGIT
+            date-month         = 2DIGIT        ;01-12
+            date-mday          = 2DIGIT        ;01-28, 01-29, 01-30, 01-31
+                                               ;based on month/year
+
+    Description:
+        If the property permits, multiple "date" values are
+        specified as a COMMA-separated list of values.  The format for the
+        value type is based on the [ISO.8601.2004] complete
+        representation, basic format for a calendar date.  The textual
+        format specifies a four-digit year, two-digit month, and two-digit
+        day of the month.  There are no separator characters between the
+        year, month, and day component text.
+
+    Example:
+        The following represents July 14, 1997:
+
+        .. code-block:: text
+
+            19970714
+
+        .. code-block:: pycon
+
+            >>> from icalendar.prop import vDate
+            >>> date = vDate.from_ical('19970714')
+            >>> date.year
+            1997
+            >>> date.month
+            7
+            >>> date.day
+            14
     """
 
+    params: Parameters
+
     def __init__(self, dt):
         if not isinstance(dt, date):
-            raise ValueError('Value MUST be a date instance')
+            raise ValueError("Value MUST be a date instance")
         self.dt = dt
-        self.params = Parameters({'value': 'DATE'})
+        self.params = Parameters({"value": "DATE"})
 
     def to_ical(self):
         s = f"{self.dt.year:04}{self.dt.month:02}{self.dt.day:02}"
-        return s.encode('utf-8')
+        return s.encode("utf-8")
 
     @staticmethod
     def from_ical(ical):
@@ -376,7 +652,7 @@ class vDate(TimeBase):
             )
             return date(*timetuple)
         except Exception:
-            raise ValueError(f'Wrong date format {ical}')
+            raise ValueError(f"Wrong date format {ical}")
 
 
 class vDatetime(TimeBase):
@@ -386,31 +662,57 @@ class vDatetime(TimeBase):
     When a vDatetime object is created from an
     ical string, you can pass a valid timezone identifier. When a
     vDatetime object is created from a python datetime object, it uses the
-    tzinfo component, if present. Otherwise an timezone-naive object is
+    tzinfo component, if present. Otherwise a timezone-naive object is
     created. Be aware that there are certain limitations with timezone naive
     DATE-TIME components in the icalendar standard.
     """
 
-    def __init__(self, dt):
+    params: Parameters
+
+    def __init__(self, dt, params={}):
         self.dt = dt
-        self.params = Parameters()
+        self.params = Parameters(params)
 
     def to_ical(self):
         dt = self.dt
         tzid = tzid_from_dt(dt)
 
         s = f"{dt.year:04}{dt.month:02}{dt.day:02}T{dt.hour:02}{dt.minute:02}{dt.second:02}"
-        if tzid == 'UTC':
+        if tzid == "UTC":
             s += "Z"
         elif tzid:
-            self.params.update({'TZID': tzid})
-        return s.encode('utf-8')
+            self.params.update({"TZID": tzid})
+        return s.encode("utf-8")
 
     @staticmethod
     def from_ical(ical, timezone=None):
+        """Create a datetime from the RFC string.
+
+        Format:
+
+        .. code-block:: text
+
+            YYYYMMDDTHHMMSS
+
+        .. code-block:: pycon
+
+            >>> from icalendar import vDatetime
+            >>> vDatetime.from_ical("20210302T101500")
+            datetime.datetime(2021, 3, 2, 10, 15)
+
+            >>> vDatetime.from_ical("20210302T101500", "America/New_York")
+            datetime.datetime(2021, 3, 2, 10, 15, tzinfo=ZoneInfo(key='America/New_York'))
+
+            >>> from zoneinfo import ZoneInfo
+            >>> timezone = ZoneInfo("Europe/Berlin")
+            >>> vDatetime.from_ical("20210302T101500", timezone)
+            datetime.datetime(2021, 3, 2, 10, 15, tzinfo=ZoneInfo(key='Europe/Berlin'))
+        """
         tzinfo = None
-        if timezone:
+        if isinstance(timezone, str):
             tzinfo = tzp.timezone(timezone)
+        elif timezone is not None:
+            tzinfo = timezone
 
         try:
             timetuple = (
@@ -425,24 +727,90 @@ class vDatetime(TimeBase):
                 return tzp.localize(datetime(*timetuple), tzinfo)
             elif not ical[15:]:
                 return datetime(*timetuple)
-            elif ical[15:16] == 'Z':
+            elif ical[15:16] == "Z":
                 return tzp.localize_utc(datetime(*timetuple))
             else:
                 raise ValueError(ical)
-        except Exception:
-            raise ValueError(f'Wrong datetime format: {ical}')
+        except Exception as e:
+            raise ValueError(f"Wrong datetime format: {ical}") from e
 
 
 class vDuration(TimeBase):
-    """Subclass of timedelta that renders itself in the iCalendar DURATION
-    format.
+    """Duration
+
+    Value Name:
+        DURATION
+
+    Purpose:
+        This value type is used to identify properties that contain
+        a duration of time.
+
+    Format Definition:
+        This value type is defined by the following notation:
+
+        .. code-block:: text
+
+            dur-value  = (["+"] / "-") "P" (dur-date / dur-time / dur-week)
+
+            dur-date   = dur-day [dur-time]
+            dur-time   = "T" (dur-hour / dur-minute / dur-second)
+            dur-week   = 1*DIGIT "W"
+            dur-hour   = 1*DIGIT "H" [dur-minute]
+            dur-minute = 1*DIGIT "M" [dur-second]
+            dur-second = 1*DIGIT "S"
+            dur-day    = 1*DIGIT "D"
+
+    Description:
+        If the property permits, multiple "duration" values are
+        specified by a COMMA-separated list of values.  The format is
+        based on the [ISO.8601.2004] complete representation basic format
+        with designators for the duration of time.  The format can
+        represent nominal durations (weeks and days) and accurate
+        durations (hours, minutes, and seconds).  Note that unlike
+        [ISO.8601.2004], this value type doesn't support the "Y" and "M"
+        designators to specify durations in terms of years and months.
+        The duration of a week or a day depends on its position in the
+        calendar.  In the case of discontinuities in the time scale, such
+        as the change from standard time to daylight time and back, the
+        computation of the exact duration requires the subtraction or
+        addition of the change of duration of the discontinuity.  Leap
+        seconds MUST NOT be considered when computing an exact duration.
+        When computing an exact duration, the greatest order time
+        components MUST be added first, that is, the number of days MUST
+        be added first, followed by the number of hours, number of
+        minutes, and number of seconds.
+
+    Example:
+        A duration of 15 days, 5 hours, and 20 seconds would be:
+
+        .. code-block:: text
+
+            P15DT5H0M20S
+
+        A duration of 7 weeks would be:
+
+        .. code-block:: text
+
+            P7W
+
+        .. code-block:: pycon
+
+            >>> from icalendar.prop import vDuration
+            >>> duration = vDuration.from_ical('P15DT5H0M20S')
+            >>> duration
+            datetime.timedelta(days=15, seconds=18020)
+            >>> duration = vDuration.from_ical('P7W')
+            >>> duration
+            datetime.timedelta(days=49)
     """
 
-    def __init__(self, td):
+    params: Parameters
+
+    def __init__(self, td, params={}):
         if not isinstance(td, timedelta):
-            raise ValueError('Value MUST be a timedelta instance')
+            raise ValueError("Value MUST be a timedelta instance")
         self.td = td
-        self.params = Parameters()
+        self.params = Parameters(params)
 
     def to_ical(self):
         sign = ""
@@ -463,18 +831,21 @@ class vDuration(TimeBase):
             if seconds:
                 timepart += f"{seconds}S"
         if td.days == 0 and timepart:
-            return (str(sign).encode('utf-8') + b'P'
-                    + str(timepart).encode('utf-8'))
+            return str(sign).encode("utf-8") + b"P" + str(timepart).encode("utf-8")
         else:
-            return (str(sign).encode('utf-8') + b'P'
-                    + str(abs(td.days)).encode('utf-8')
-                    + b'D' + str(timepart).encode('utf-8'))
+            return (
+                str(sign).encode("utf-8")
+                + b"P"
+                + str(abs(td.days)).encode("utf-8")
+                + b"D"
+                + str(timepart).encode("utf-8")
+            )
 
     @staticmethod
     def from_ical(ical):
         match = DURATION_REGEX.match(ical)
         if not match:
-            raise ValueError(f'Invalid iCalendar duration: {ical}')
+            raise ValueError(f"Invalid iCalendar duration: {ical}")
 
         sign, weeks, days, hours, minutes, seconds = match.groups()
         value = timedelta(
@@ -482,33 +853,98 @@ class vDuration(TimeBase):
             days=int(days or 0),
             hours=int(hours or 0),
             minutes=int(minutes or 0),
-            seconds=int(seconds or 0)
+            seconds=int(seconds or 0),
         )
 
-        if sign == '-':
+        if sign == "-":
             value = -value
 
         return value
 
     @property
-    def dt(self):
+    def dt(self) -> timedelta:
         """The time delta for compatibility."""
         return self.td
 
 
 class vPeriod(TimeBase):
-    """A precise period of time.
+    """Period of Time
+
+    Value Name:
+        PERIOD
+
+    Purpose:
+        This value type is used to identify values that contain a
+        precise period of time.
+
+    Format Definition:
+        This value type is defined by the following notation:
+
+        .. code-block:: text
+
+            period     = period-explicit / period-start
+
+           period-explicit = date-time "/" date-time
+           ; [ISO.8601.2004] complete representation basic format for a
+           ; period of time consisting of a start and end.  The start MUST
+           ; be before the end.
+
+           period-start = date-time "/" dur-value
+           ; [ISO.8601.2004] complete representation basic format for a
+           ; period of time consisting of a start and positive duration
+           ; of time.
+
+    Description:
+        If the property permits, multiple "period" values are
+        specified by a COMMA-separated list of values.  There are two
+        forms of a period of time.  First, a period of time is identified
+        by its start and its end.  This format is based on the
+        [ISO.8601.2004] complete representation, basic format for "DATE-
+        TIME" start of the period, followed by a SOLIDUS character
+        followed by the "DATE-TIME" of the end of the period.  The start
+        of the period MUST be before the end of the period.  Second, a
+        period of time can also be defined by a start and a positive
+        duration of time.  The format is based on the [ISO.8601.2004]
+        complete representation, basic format for the "DATE-TIME" start of
+        the period, followed by a SOLIDUS character, followed by the
+        [ISO.8601.2004] basic format for "DURATION" of the period.
+
+    Example:
+        The period starting at 18:00:00 UTC, on January 1, 1997 and
+        ending at 07:00:00 UTC on January 2, 1997 would be:
+
+        .. code-block:: text
+
+            19970101T180000Z/19970102T070000Z
+
+        The period start at 18:00:00 on January 1, 1997 and lasting 5 hours
+        and 30 minutes would be:
+
+        .. code-block:: text
+
+            19970101T180000Z/PT5H30M
+
+        .. code-block:: pycon
+
+            >>> from icalendar.prop import vPeriod
+            >>> period = vPeriod.from_ical('19970101T180000Z/19970102T070000Z')
+            >>> period = vPeriod.from_ical('19970101T180000Z/PT5H30M')
     """
 
-    def __init__(self, per):
+    params: Parameters
+
+    def __init__(self, per: tuple[datetime, Union[datetime, timedelta]]):
         start, end_or_duration = per
         if not (isinstance(start, datetime) or isinstance(start, date)):
-            raise ValueError('Start value MUST be a datetime or date instance')
-        if not (isinstance(end_or_duration, datetime)
-                or isinstance(end_or_duration, date)
-                or isinstance(end_or_duration, timedelta)):
-            raise ValueError('end_or_duration MUST be a datetime, '
-                             'date or timedelta instance')
+            raise ValueError("Start value MUST be a datetime or date instance")
+        if not (
+            isinstance(end_or_duration, datetime)
+            or isinstance(end_or_duration, date)
+            or isinstance(end_or_duration, timedelta)
+        ):
+            raise ValueError(
+                "end_or_duration MUST be a datetime, " "date or timedelta instance"
+            )
         by_duration = 0
         if isinstance(end_or_duration, timedelta):
             by_duration = 1
@@ -520,12 +956,12 @@ class vPeriod(TimeBase):
         if start > end:
             raise ValueError("Start time is greater than end time")
 
-        self.params = Parameters({'value': 'PERIOD'})
+        self.params = Parameters({"value": "PERIOD"})
         # set the timezone identifier
         # does not support different timezones for start and end
         tzid = tzid_from_dt(start)
         if tzid:
-            self.params['TZID'] = tzid
+            self.params["TZID"] = tzid
 
         self.start = start
         self.end = end
@@ -541,55 +977,98 @@ class vPeriod(TimeBase):
 
     def to_ical(self):
         if self.by_duration:
-            return (vDatetime(self.start).to_ical() + b'/'
-                    + vDuration(self.duration).to_ical())
-        return (vDatetime(self.start).to_ical() + b'/'
-                + vDatetime(self.end).to_ical())
+            return (
+                vDatetime(self.start).to_ical()
+                + b"/"
+                + vDuration(self.duration).to_ical()
+            )
+        return vDatetime(self.start).to_ical() + b"/" + vDatetime(self.end).to_ical()
 
     @staticmethod
     def from_ical(ical, timezone=None):
         try:
-            start, end_or_duration = ical.split('/')
+            start, end_or_duration = ical.split("/")
             start = vDDDTypes.from_ical(start, timezone=timezone)
             end_or_duration = vDDDTypes.from_ical(end_or_duration, timezone=timezone)
             return (start, end_or_duration)
         except Exception:
-            raise ValueError(f'Expected period format, got: {ical}')
+            raise ValueError(f"Expected period format, got: {ical}")
 
     def __repr__(self):
         if self.by_duration:
             p = (self.start, self.duration)
         else:
             p = (self.start, self.end)
-        return f'vPeriod({p!r})'
+        return f"vPeriod({p!r})"
 
     @property
     def dt(self):
         """Make this cooperate with the other vDDDTypes."""
         return (self.start, (self.duration if self.by_duration else self.end))
 
+    from icalendar.param import FBTYPE
+
 
 class vWeekday(str):
-    """This returns an unquoted weekday abbrevation.
+    """Either a ``weekday`` or a ``weekdaynum``
+
+    .. code-block:: pycon
+
+        >>> from icalendar import vWeekday
+        >>> vWeekday("MO") # Simple weekday
+        'MO'
+        >>> vWeekday("2FR").relative # Second friday
+        2
+        >>> vWeekday("2FR").weekday
+        'FR'
+        >>> vWeekday("-1SU").relative # Last Sunday
+        -1
+
+    Definition from `RFC 5545, Section 3.3.10 <https://www.rfc-editor.org/rfc/rfc5545#section-3.3.10>`_:
+
+    .. code-block:: text
+
+        weekdaynum = [[plus / minus] ordwk] weekday
+        plus        = "+"
+        minus       = "-"
+        ordwk       = 1*2DIGIT       ;1 to 53
+        weekday     = "SU" / "MO" / "TU" / "WE" / "TH" / "FR" / "SA"
+        ;Corresponding to SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY,
+        ;FRIDAY, and SATURDAY days of the week.
+
     """
-    week_days = CaselessDict({
-        "SU": 0, "MO": 1, "TU": 2, "WE": 3, "TH": 4, "FR": 5, "SA": 6,
-    })
 
-    def __new__(cls, value, encoding=DEFAULT_ENCODING):
+    params: Parameters
+
+    week_days = CaselessDict(
+        {
+            "SU": 0,
+            "MO": 1,
+            "TU": 2,
+            "WE": 3,
+            "TH": 4,
+            "FR": 5,
+            "SA": 6,
+        }
+    )
+
+    def __new__(cls, value, encoding=DEFAULT_ENCODING, params={}):
         value = to_unicode(value, encoding=encoding)
         self = super().__new__(cls, value)
         match = WEEKDAY_RULE.match(self)
         if match is None:
-            raise ValueError(f'Expected weekday abbrevation, got: {self}')
+            raise ValueError(f"Expected weekday abbrevation, got: {self}")
         match = match.groupdict()
-        sign = match['signal']
-        weekday = match['weekday']
-        relative = match['relative']
-        if weekday not in vWeekday.week_days or sign not in '+-':
-            raise ValueError(f'Expected weekday abbrevation, got: {self}')
+        sign = match["signal"]
+        weekday = match["weekday"]
+        relative = match["relative"]
+        if weekday not in vWeekday.week_days or sign not in "+-":
+            raise ValueError(f"Expected weekday abbrevation, got: {self}")
+        self.weekday = weekday or None
         self.relative = relative and int(relative) or None
-        self.params = Parameters()
+        if sign == "-" and self.relative:
+            self.relative *= -1
+        self.params = Parameters(params)
         return self
 
     def to_ical(self):
@@ -600,29 +1079,32 @@ class vWeekday(str):
         try:
             return cls(ical.upper())
         except Exception:
-            raise ValueError(f'Expected weekday abbrevation, got: {ical}')
+            raise ValueError(f"Expected weekday abbrevation, got: {ical}")
 
 
 class vFrequency(str):
-    """A simple class that catches illegal values.
-    """
+    """A simple class that catches illegal values."""
 
-    frequencies = CaselessDict({
-        "SECONDLY": "SECONDLY",
-        "MINUTELY": "MINUTELY",
-        "HOURLY": "HOURLY",
-        "DAILY": "DAILY",
-        "WEEKLY": "WEEKLY",
-        "MONTHLY": "MONTHLY",
-        "YEARLY": "YEARLY",
-    })
+    params: Parameters
+
+    frequencies = CaselessDict(
+        {
+            "SECONDLY": "SECONDLY",
+            "MINUTELY": "MINUTELY",
+            "HOURLY": "HOURLY",
+            "DAILY": "DAILY",
+            "WEEKLY": "WEEKLY",
+            "MONTHLY": "MONTHLY",
+            "YEARLY": "YEARLY",
+        }
+    )
 
-    def __new__(cls, value, encoding=DEFAULT_ENCODING):
+    def __new__(cls, value, encoding=DEFAULT_ENCODING, params={}):
         value = to_unicode(value, encoding=encoding)
         self = super().__new__(cls, value)
         if self not in vFrequency.frequencies:
-            raise ValueError(f'Expected frequency, got: {self}')
-        self.params = Parameters()
+            raise ValueError(f"Expected frequency, got: {self}")
+        self.params = Parameters(params)
         return self
 
     def to_ical(self):
@@ -633,7 +1115,7 @@ class vFrequency(str):
         try:
             return cls(ical.upper())
         except Exception:
-            raise ValueError(f'Expected frequency, got: {ical}')
+            raise ValueError(f"Expected frequency, got: {ical}")
 
 
 class vMonth(int):
@@ -642,6 +1124,8 @@ class vMonth(int):
     In :rfc:`5545`, this is just an int.
     In :rfc:`7529`, this can be followed by `L` to indicate a leap month.
 
+    .. code-block:: pycon
+
         >>> from icalendar import vMonth
         >>> vMonth(1) # first month January
         vMonth('1')
@@ -652,14 +1136,19 @@ class vMonth(int):
         >>> vMonth("5L").leap
         True
 
-    Definition from RFC::
+    Definition from RFC:
+
+    .. code-block:: text
 
         type-bymonth = element bymonth {
            xsd:positiveInteger |
            xsd:string
         }
     """
-    def __new__(cls, month:Union[str, int]):
+
+    params: Parameters
+
+    def __new__(cls, month: Union[str, int], params={}):
         if isinstance(month, vMonth):
             return cls(month.to_ical().decode())
         if isinstance(month, str):
@@ -667,7 +1156,7 @@ class vMonth(int):
                 month_index = int(month)
                 leap = False
             else:
-                if not month[-1] == "L" and month[:-1].isdigit():
+                if month[-1] != "L" and month[:-1].isdigit():
                     raise ValueError(f"Invalid month: {month!r}")
                 month_index = int(month[:-1])
                 leap = True
@@ -676,12 +1165,12 @@ class vMonth(int):
             month_index = int(month)
         self = super().__new__(cls, month_index)
         self.leap = leap
-        self.params = Parameters()
+        self.params = Parameters(params)
         return self
 
     def to_ical(self) -> bytes:
         """The ical representation."""
-        return str(self).encode('utf-8')
+        return str(self).encode("utf-8")
 
     @classmethod
     def from_ical(cls, ical: str):
@@ -689,13 +1178,16 @@ class vMonth(int):
 
     def leap():
         doc = "Whether this is a leap month."
+
         def fget(self) -> bool:
             return self._leap
-        def fset(self, value:bool) -> None:
+
+        def fset(self, value: bool) -> None:
             self._leap = value
+
         return locals()
-    leap = property(**leap())
 
+    leap = property(**leap())
 
     def __repr__(self) -> str:
         """repr(self)"""
@@ -712,56 +1204,178 @@ class vSkip(vText, Enum):
     These are defined in :rfc:`7529`.
 
     OMIT  is the default value.
+
+    Examples:
+
+    .. code-block:: pycon
+
+        >>> from icalendar import vSkip
+        >>> vSkip.OMIT
+        vSkip('OMIT')
+        >>> vSkip.FORWARD
+        vSkip('FORWARD')
+        >>> vSkip.BACKWARD
+        vSkip('BACKWARD')
     """
 
     OMIT = "OMIT"
     FORWARD = "FORWARD"
     BACKWARD = "BACKWARD"
 
-    def __reduce_ex__(self, _p):
-        """For pickling."""
-        return self.__class__, (self._name_,)
+    __reduce_ex__ = Enum.__reduce_ex__
+
+    def __repr__(self):
+        return f"{self.__class__.__name__}({self._name_!r})"
 
 
 class vRecur(CaselessDict):
     """Recurrence definition.
-    """
 
-    frequencies = ["SECONDLY", "MINUTELY", "HOURLY", "DAILY", "WEEKLY",
-                   "MONTHLY", "YEARLY"]
+    Property Name:
+        RRULE
+
+    Purpose:
+        This property defines a rule or repeating pattern for recurring events, to-dos,
+        journal entries, or time zone definitions.
+
+    Value Type:
+        RECUR
+
+    Property Parameters:
+        IANA and non-standard property parameters can be specified on this property.
+
+    Conformance:
+        This property can be specified in recurring "VEVENT", "VTODO", and "VJOURNAL"
+        calendar components as well as in the "STANDARD" and "DAYLIGHT" sub-components
+        of the "VTIMEZONE" calendar component, but it SHOULD NOT be specified more than once.
+        The recurrence set generated with multiple "RRULE" properties is undefined.
+
+    Description:
+        The recurrence rule, if specified, is used in computing the recurrence set.
+        The recurrence set is the complete set of recurrence instances for a calendar component.
+        The recurrence set is generated by considering the initial "DTSTART" property along
+        with the "RRULE", "RDATE", and "EXDATE" properties contained within the
+        recurring component. The "DTSTART" property defines the first instance in the
+        recurrence set. The "DTSTART" property value SHOULD be synchronized with the
+        recurrence rule, if specified. The recurrence set generated with a "DTSTART" property
+        value not synchronized with the recurrence rule is undefined.
+        The final recurrence set is generated by gathering all of the start DATE-TIME
+        values generated by any of the specified "RRULE" and "RDATE" properties, and then
+        excluding any start DATE-TIME values specified by "EXDATE" properties.
+        This implies that start DATE- TIME values specified by "EXDATE" properties take
+        precedence over those specified by inclusion properties (i.e., "RDATE" and "RRULE").
+        Where duplicate instances are generated by the "RRULE" and "RDATE" properties,
+        only one recurrence is considered. Duplicate instances are ignored.
+
+        The "DTSTART" property specified within the iCalendar object defines the first
+        instance of the recurrence. In most cases, a "DTSTART" property of DATE-TIME value
+        type used with a recurrence rule, should be specified as a date with local time
+        and time zone reference to make sure all the recurrence instances start at the
+        same local time regardless of time zone changes.
+
+        If the duration of the recurring component is specified with the "DTEND" or
+        "DUE" property, then the same exact duration will apply to all the members of the
+        generated recurrence set. Else, if the duration of the recurring component is
+        specified with the "DURATION" property, then the same nominal duration will apply
+        to all the members of the generated recurrence set and the exact duration of each
+        recurrence instance will depend on its specific start time. For example, recurrence
+        instances of a nominal duration of one day will have an exact duration of more or less
+        than 24 hours on a day where a time zone shift occurs. The duration of a specific
+        recurrence may be modified in an exception component or simply by using an
+        "RDATE" property of PERIOD value type.
+
+    Examples:
+        The following RRULE specifies daily events for 10 occurrences.
+
+        .. code-block:: text
+
+            RRULE:FREQ=DAILY;COUNT=10
+
+        Below, we parse the RRULE ical string.
+
+        .. code-block:: pycon
+
+            >>> from icalendar.prop import vRecur
+            >>> rrule = vRecur.from_ical('FREQ=DAILY;COUNT=10')
+            >>> rrule
+            vRecur({'FREQ': ['DAILY'], 'COUNT': [10]})
+
+        You can choose to add an rrule to an :class:`icalendar.cal.Event` or
+        :class:`icalendar.cal.Todo`.
+
+        .. code-block:: pycon
+
+            >>> from icalendar import Event
+            >>> event = Event()
+            >>> event.add('RRULE', 'FREQ=DAILY;COUNT=10')
+            >>> event.rrules
+            [vRecur({'FREQ': ['DAILY'], 'COUNT': [10]})]
+    """
+
+    params: Parameters
+
+    frequencies = [
+        "SECONDLY",
+        "MINUTELY",
+        "HOURLY",
+        "DAILY",
+        "WEEKLY",
+        "MONTHLY",
+        "YEARLY",
+    ]
 
     # Mac iCal ignores RRULEs where FREQ is not the first rule part.
     # Sorts parts according to the order listed in RFC 5545, section 3.3.10.
-    canonical_order = ("RSCALE", "FREQ", "UNTIL", "COUNT", "INTERVAL",
-                       "BYSECOND", "BYMINUTE", "BYHOUR", "BYDAY", "BYWEEKDAY",
-                       "BYMONTHDAY", "BYYEARDAY", "BYWEEKNO", "BYMONTH",
-                       "BYSETPOS", "WKST", "SKIP")
-
-    types = CaselessDict({
-        'COUNT': vInt,
-        'INTERVAL': vInt,
-        'BYSECOND': vInt,
-        'BYMINUTE': vInt,
-        'BYHOUR': vInt,
-        'BYWEEKNO': vInt,
-        'BYMONTHDAY': vInt,
-        'BYYEARDAY': vInt,
-        'BYMONTH': vMonth,
-        'UNTIL': vDDDTypes,
-        'BYSETPOS': vInt,
-        'WKST': vWeekday,
-        'BYDAY': vWeekday,
-        'FREQ': vFrequency,
-        'BYWEEKDAY': vWeekday,
-        'SKIP': vSkip,
-    })
+    canonical_order = (
+        "RSCALE",
+        "FREQ",
+        "UNTIL",
+        "COUNT",
+        "INTERVAL",
+        "BYSECOND",
+        "BYMINUTE",
+        "BYHOUR",
+        "BYDAY",
+        "BYWEEKDAY",
+        "BYMONTHDAY",
+        "BYYEARDAY",
+        "BYWEEKNO",
+        "BYMONTH",
+        "BYSETPOS",
+        "WKST",
+        "SKIP",
+    )
+
+    types = CaselessDict(
+        {
+            "COUNT": vInt,
+            "INTERVAL": vInt,
+            "BYSECOND": vInt,
+            "BYMINUTE": vInt,
+            "BYHOUR": vInt,
+            "BYWEEKNO": vInt,
+            "BYMONTHDAY": vInt,
+            "BYYEARDAY": vInt,
+            "BYMONTH": vMonth,
+            "UNTIL": vDDDTypes,
+            "BYSETPOS": vInt,
+            "WKST": vWeekday,
+            "BYDAY": vWeekday,
+            "FREQ": vFrequency,
+            "BYWEEKDAY": vWeekday,
+            "SKIP": vSkip,
+        }
+    )
 
-    def __init__(self, *args, **kwargs):
+    def __init__(self, *args, params={}, **kwargs):
+        if args and isinstance(args[0], str):
+            # we have a string as an argument.
+            args = (self.from_ical(args[0]),) + args[1:]
         for k, v in kwargs.items():
             if not isinstance(v, SEQUENCE_TYPES):
                 kwargs[k] = [v]
         super().__init__(*args, **kwargs)
-        self.params = Parameters()
+        self.params = Parameters(params)
 
     def to_ical(self):
         result = []
@@ -769,19 +1383,19 @@ class vRecur(CaselessDict):
             typ = self.types.get(key, vText)
             if not isinstance(vals, SEQUENCE_TYPES):
                 vals = [vals]
-            vals = b','.join(typ(val).to_ical() for val in vals)
+            vals = b",".join(typ(val).to_ical() for val in vals)
 
             # CaselessDict keys are always unicode
             key = key.encode(DEFAULT_ENCODING)
-            result.append(key + b'=' + vals)
+            result.append(key + b"=" + vals)
 
-        return b';'.join(result)
+        return b";".join(result)
 
     @classmethod
     def parse_type(cls, key, values):
         # integers
         parser = cls.types.get(key, vText)
-        return [parser.from_ical(v) for v in values.split(',')]
+        return [parser.from_ical(v) for v in values.split(",")]
 
     @classmethod
     def from_ical(cls, ical: str):
@@ -789,9 +1403,9 @@ class vRecur(CaselessDict):
             return ical
         try:
             recur = cls()
-            for pairs in ical.split(';'):
+            for pairs in ical.split(";"):
                 try:
-                    key, vals = pairs.split('=')
+                    key, vals = pairs.split("=")
                 except ValueError:
                     # E.g. incorrect trailing semicolon, like (issue #157):
                     # FREQ=YEARLY;BYMONTH=11;BYDAY=1SU;
@@ -801,21 +1415,129 @@ class vRecur(CaselessDict):
         except ValueError:
             raise
         except:
-            raise ValueError(f'Error in recurrence rule: {ical}')
+            raise ValueError(f"Error in recurrence rule: {ical}")
 
 
 class vTime(TimeBase):
-    """Render and generates iCalendar time format.
+    """Time
+
+    Value Name:
+        TIME
+
+    Purpose:
+        This value type is used to identify values that contain a
+        time of day.
+
+    Format Definition:
+        This value type is defined by the following notation:
+
+        .. code-block:: text
+
+            time         = time-hour time-minute time-second [time-utc]
+
+            time-hour    = 2DIGIT        ;00-23
+            time-minute  = 2DIGIT        ;00-59
+            time-second  = 2DIGIT        ;00-60
+            ;The "60" value is used to account for positive "leap" seconds.
+
+            time-utc     = "Z"
+
+    Description:
+        If the property permits, multiple "time" values are
+        specified by a COMMA-separated list of values.  No additional
+        content value encoding (i.e., BACKSLASH character encoding, see
+        vText) is defined for this value type.
+
+        The "TIME" value type is used to identify values that contain a
+        time of day.  The format is based on the [ISO.8601.2004] complete
+        representation, basic format for a time of day.  The text format
+        consists of a two-digit, 24-hour of the day (i.e., values 00-23),
+        two-digit minute in the hour (i.e., values 00-59), and two-digit
+        seconds in the minute (i.e., values 00-60).  The seconds value of
+        60 MUST only be used to account for positive "leap" seconds.
+        Fractions of a second are not supported by this format.
+
+        In parallel to the "DATE-TIME" definition above, the "TIME" value
+        type expresses time values in three forms:
+
+        The form of time with UTC offset MUST NOT be used.  For example,
+        the following is not valid for a time value:
+
+        .. code-block:: text
+
+            230000-0800        ;Invalid time format
+
+        **FORM #1 LOCAL TIME**
+
+        The local time form is simply a time value that does not contain
+        the UTC designator nor does it reference a time zone.  For
+        example, 11:00 PM:
+
+        .. code-block:: text
+
+            230000
+
+        Time values of this type are said to be "floating" and are not
+        bound to any time zone in particular.  They are used to represent
+        the same hour, minute, and second value regardless of which time
+        zone is currently being observed.  For example, an event can be
+        defined that indicates that an individual will be busy from 11:00
+        AM to 1:00 PM every day, no matter which time zone the person is
+        in.  In these cases, a local time can be specified.  The recipient
+        of an iCalendar object with a property value consisting of a local
+        time, without any relative time zone information, SHOULD interpret
+        the value as being fixed to whatever time zone the "ATTENDEE" is
+        in at any given moment.  This means that two "Attendees", may
+        participate in the same event at different UTC times; floating
+        time SHOULD only be used where that is reasonable behavior.
+
+        In most cases, a fixed time is desired.  To properly communicate a
+        fixed time in a property value, either UTC time or local time with
+        time zone reference MUST be specified.
+
+        The use of local time in a TIME value without the "TZID" property
+        parameter is to be interpreted as floating time, regardless of the
+        existence of "VTIMEZONE" calendar components in the iCalendar
+        object.
+
+        **FORM #2: UTC TIME**
+
+        UTC time, or absolute time, is identified by a LATIN CAPITAL
+        LETTER Z suffix character, the UTC designator, appended to the
+        time value.  For example, the following represents 07:00 AM UTC:
+
+        .. code-block:: text
+
+            070000Z
+
+        The "TZID" property parameter MUST NOT be applied to TIME
+        properties whose time values are specified in UTC.
+
+        **FORM #3: LOCAL TIME AND TIME ZONE REFERENCE**
+
+        The local time with reference to time zone information form is
+        identified by the use the "TZID" property parameter to reference
+        the appropriate time zone definition.
+
+        Example:
+            The following represents 8:30 AM in New York in winter,
+            five hours behind UTC, in each of the three formats:
+
+        .. code-block:: text
+
+            083000
+            133000Z
+            TZID=America/New_York:083000
     """
 
     def __init__(self, *args):
         if len(args) == 1:
             if not isinstance(args[0], (time, datetime)):
-                raise ValueError(f'Expected a datetime.time, got: {args[0]}')
+                raise ValueError(f"Expected a datetime.time, got: {args[0]}")
             self.dt = args[0]
         else:
             self.dt = time(*args)
-        self.params = Parameters({'value': 'TIME'})
+        self.params = Parameters({"value": "TIME"})
 
     def to_ical(self):
         return self.dt.strftime("%H%M%S")
@@ -827,17 +1549,59 @@ class vTime(TimeBase):
             timetuple = (int(ical[:2]), int(ical[2:4]), int(ical[4:6]))
             return time(*timetuple)
         except Exception:
-            raise ValueError(f'Expected time, got: {ical}')
+            raise ValueError(f"Expected time, got: {ical}")
 
 
 class vUri(str):
-    """Uniform resource identifier is basically just an unquoted string.
+    """URI
+
+    Value Name:
+        URI
+
+    Purpose:
+        This value type is used to identify values that contain a
+        uniform resource identifier (URI) type of reference to the
+        property value.
+
+    Format Definition:
+        This value type is defined by the following notation:
+
+        .. code-block:: text
+
+            uri = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
+
+    Description:
+        This value type might be used to reference binary
+        information, for values that are large, or otherwise undesirable
+        to include directly in the iCalendar object.
+
+        Property values with this value type MUST follow the generic URI
+        syntax defined in [RFC3986].
+
+        When a property parameter value is a URI value type, the URI MUST
+        be specified as a quoted-string value.
+
+        Example:
+            The following is a URI for a network file:
+
+            .. code-block:: text
+
+                http://example.com/my-report.txt
+
+            .. code-block:: pycon
+
+                >>> from icalendar.prop import vUri
+                >>> uri = vUri.from_ical('http://example.com/my-report.txt')
+                >>> uri
+                'http://example.com/my-report.txt'
     """
 
-    def __new__(cls, value, encoding=DEFAULT_ENCODING):
+    params: Parameters
+
+    def __new__(cls, value, encoding=DEFAULT_ENCODING, params={}):
         value = to_unicode(value, encoding=encoding)
         self = super().__new__(cls, value)
-        self.params = Parameters()
+        self.params = Parameters(params)
         return self
 
     def to_ical(self):
@@ -848,64 +1612,176 @@ class vUri(str):
         try:
             return cls(ical)
         except Exception:
-            raise ValueError(f'Expected , got: {ical}')
+            raise ValueError(f"Expected , got: {ical}")
 
 
 class vGeo:
-    """A special type that is only indirectly defined in the rfc.
+    """Geographic Position
+
+    Property Name:
+        GEO
+
+    Purpose:
+        This property specifies information related to the global
+        position for the activity specified by a calendar component.
+
+    Value Type:
+        FLOAT.  The value MUST be two SEMICOLON-separated FLOAT values.
+
+    Property Parameters:
+        IANA and non-standard property parameters can be specified on
+        this property.
+
+    Conformance:
+        This property can be specified in "VEVENT" or "VTODO"
+        calendar components.
+
+    Description:
+        This property value specifies latitude and longitude,
+        in that order (i.e., "LAT LON" ordering).  The longitude
+        represents the location east or west of the prime meridian as a
+        positive or negative real number, respectively.  The longitude and
+        latitude values MAY be specified up to six decimal places, which
+        will allow for accuracy to within one meter of geographical
+        position.  Receiving applications MUST accept values of this
+        precision and MAY truncate values of greater precision.
+
+        Example:
+
+        .. code-block:: text
+
+            GEO:37.386013;-122.082932
+
+        Parse vGeo:
+
+        .. code-block:: pycon
+
+            >>> from icalendar.prop import vGeo
+            >>> geo = vGeo.from_ical('37.386013;-122.082932')
+            >>> geo
+            (37.386013, -122.082932)
+
+        Add a geo location to an event:
+
+        .. code-block:: pycon
+
+            >>> from icalendar import Event
+            >>> event = Event()
+            >>> latitude = 37.386013
+            >>> longitude = -122.082932
+            >>> event.add('GEO', (latitude, longitude))
+            >>> event['GEO']
+            vGeo((37.386013, -122.082932))
     """
 
-    def __init__(self, geo):
+    params: Parameters
+
+    def __init__(self, geo: tuple[float | str | int, float | str | int], params={}):
+        """Create a new vGeo from a tuple of (latitude, longitude).
+
+        Raises:
+            ValueError: if geo is not a tuple of (latitude, longitude)
+        """
         try:
             latitude, longitude = (geo[0], geo[1])
             latitude = float(latitude)
             longitude = float(longitude)
-        except Exception:
-            raise ValueError('Input must be (float, float) for '
-                             'latitude and longitude')
+        except Exception as e:
+            raise ValueError(
+                "Input must be (float, float) for " "latitude and longitude"
+            ) from e
         self.latitude = latitude
         self.longitude = longitude
-        self.params = Parameters()
+        self.params = Parameters(params)
 
     def to_ical(self):
-        return f'{self.latitude};{self.longitude}'
+        return f"{self.latitude};{self.longitude}"
 
     @staticmethod
     def from_ical(ical):
         try:
-            latitude, longitude = ical.split(';')
+            latitude, longitude = ical.split(";")
             return (float(latitude), float(longitude))
-        except Exception:
-            raise ValueError(f"Expected 'float;float' , got: {ical}")
+        except Exception as e:
+            raise ValueError(f"Expected 'float;float' , got: {ical}") from e
 
     def __eq__(self, other):
         return self.to_ical() == other.to_ical()
 
+    def __repr__(self):
+        """repr(self)"""
+        return f"{self.__class__.__name__}(({self.latitude}, {self.longitude}))"
+
 
 class vUTCOffset:
-    """Renders itself as a utc offset.
+    """UTC Offset
+
+    Value Name:
+        UTC-OFFSET
+
+    Purpose:
+        This value type is used to identify properties that contain
+        an offset from UTC to local time.
+
+    Format Definition:
+        This value type is defined by the following notation:
+
+        .. code-block:: text
+
+            utc-offset = time-numzone
+
+            time-numzone = ("+" / "-") time-hour time-minute [time-second]
+
+    Description:
+        The PLUS SIGN character MUST be specified for positive
+        UTC offsets (i.e., ahead of UTC).  The HYPHEN-MINUS character MUST
+        be specified for negative UTC offsets (i.e., behind of UTC).  The
+        value of "-0000" and "-000000" are not allowed.  The time-second,
+        if present, MUST NOT be 60; if absent, it defaults to zero.
+
+        Example:
+            The following UTC offsets are given for standard time for
+            New York (five hours behind UTC) and Geneva (one hour ahead of
+            UTC):
+
+        .. code-block:: text
+
+            -0500
+
+            +0100
+
+        .. code-block:: pycon
+
+            >>> from icalendar.prop import vUTCOffset
+            >>> utc_offset = vUTCOffset.from_ical('-0500')
+            >>> utc_offset
+            datetime.timedelta(days=-1, seconds=68400)
+            >>> utc_offset = vUTCOffset.from_ical('+0100')
+            >>> utc_offset
+            datetime.timedelta(seconds=3600)
     """
 
+    params: Parameters
+
     ignore_exceptions = False  # if True, and we cannot parse this
 
     # component, we will silently ignore
     # it, rather than let the exception
     # propagate upwards
 
-    def __init__(self, td):
+    def __init__(self, td, params={}):
         if not isinstance(td, timedelta):
-            raise ValueError('Offset value MUST be a timedelta instance')
+            raise ValueError("Offset value MUST be a timedelta instance")
         self.td = td
-        self.params = Parameters()
+        self.params = Parameters(params)
 
     def to_ical(self):
-
         if self.td < timedelta(0):
-            sign = '-%s'
+            sign = "-%s"
             td = timedelta(0) - self.td  # get timedelta relative to 0
         else:
             # Google Calendar rejects '0000' but accepts '+0000'
-            sign = '+%s'
+            sign = "+%s"
             td = self.td
 
         days, seconds = td.days, td.seconds
@@ -914,9 +1790,9 @@ class vUTCOffset:
         minutes = abs((seconds % 3600) // 60)
         seconds = abs(seconds % 60)
         if seconds:
-            duration = f'{hours:02}{minutes:02}{seconds:02}'
+            duration = f"{hours:02}{minutes:02}{seconds:02}"
         else:
-            duration = f'{hours:02}{minutes:02}'
+            duration = f"{hours:02}{minutes:02}"
         return sign % duration
 
     @classmethod
@@ -924,17 +1800,18 @@ class vUTCOffset:
         if isinstance(ical, cls):
             return ical.td
         try:
-            sign, hours, minutes, seconds = (ical[0:1],
-                                             int(ical[1:3]),
-                                             int(ical[3:5]),
-                                             int(ical[5:7] or 0))
+            sign, hours, minutes, seconds = (
+                ical[0:1],
+                int(ical[1:3]),
+                int(ical[3:5]),
+                int(ical[5:7] or 0),
+            )
             offset = timedelta(hours=hours, minutes=minutes, seconds=seconds)
         except Exception:
-            raise ValueError(f'Expected utc offset, got: {ical}')
+            raise ValueError(f"Expected utc offset, got: {ical}")
         if not cls.ignore_exceptions and offset >= timedelta(hours=24):
-            raise ValueError(
-                f'Offset must be less than 24 hours, was {ical}')
-        if sign == '-':
+            raise ValueError(f"Offset must be less than 24 hours, was {ical}")
+        if sign == "-":
             return -offset
         return offset
 
@@ -943,6 +1820,12 @@ class vUTCOffset:
             return False
         return self.td == other.td
 
+    def __hash__(self):
+        return hash(self.td)
+
+    def __repr__(self):
+        return f"vUTCOffset({self.td!r})"
+
 
 class vInline(str):
     """This is an especially dumb class that just holds raw unparsed text and
@@ -950,10 +1833,12 @@ class vInline(str):
     class, so no further processing is needed.
     """
 
-    def __new__(cls, value, encoding=DEFAULT_ENCODING):
+    params: Parameters
+
+    def __new__(cls, value, encoding=DEFAULT_ENCODING, params={}):
         value = to_unicode(value, encoding=encoding)
         self = super().__new__(cls, value)
-        self.params = Parameters()
+        self.params = Parameters(params)
         return self
 
     def to_ical(self):
@@ -998,116 +1883,117 @@ class TypesFactory(CaselessDict):
             vWeekday,
             vCategory,
         )
-        self['binary'] = vBinary
-        self['boolean'] = vBoolean
-        self['cal-address'] = vCalAddress
-        self['date'] = vDDDTypes
-        self['date-time'] = vDDDTypes
-        self['duration'] = vDDDTypes
-        self['float'] = vFloat
-        self['integer'] = vInt
-        self['period'] = vPeriod
-        self['recur'] = vRecur
-        self['text'] = vText
-        self['time'] = vTime
-        self['uri'] = vUri
-        self['utc-offset'] = vUTCOffset
-        self['geo'] = vGeo
-        self['inline'] = vInline
-        self['date-time-list'] = vDDDLists
-        self['categories'] = vCategory
+        self["binary"] = vBinary
+        self["boolean"] = vBoolean
+        self["cal-address"] = vCalAddress
+        self["date"] = vDDDTypes
+        self["date-time"] = vDDDTypes
+        self["duration"] = vDDDTypes
+        self["float"] = vFloat
+        self["integer"] = vInt
+        self["period"] = vPeriod
+        self["recur"] = vRecur
+        self["text"] = vText
+        self["time"] = vTime
+        self["uri"] = vUri
+        self["utc-offset"] = vUTCOffset
+        self["geo"] = vGeo
+        self["inline"] = vInline
+        self["date-time-list"] = vDDDLists
+        self["categories"] = vCategory
 
     #################################################
     # Property types
 
     # These are the default types
-    types_map = CaselessDict({
-        ####################################
-        # Property value types
-        # Calendar Properties
-        'calscale': 'text',
-        'method': 'text',
-        'prodid': 'text',
-        'version': 'text',
-        # Descriptive Component Properties
-        'attach': 'uri',
-        'categories': 'categories',
-        'class': 'text',
-        'comment': 'text',
-        'description': 'text',
-        'geo': 'geo',
-        'location': 'text',
-        'percent-complete': 'integer',
-        'priority': 'integer',
-        'resources': 'text',
-        'status': 'text',
-        'summary': 'text',
-        # Date and Time Component Properties
-        'completed': 'date-time',
-        'dtend': 'date-time',
-        'due': 'date-time',
-        'dtstart': 'date-time',
-        'duration': 'duration',
-        'freebusy': 'period',
-        'transp': 'text',
-        # Time Zone Component Properties
-        'tzid': 'text',
-        'tzname': 'text',
-        'tzoffsetfrom': 'utc-offset',
-        'tzoffsetto': 'utc-offset',
-        'tzurl': 'uri',
-        # Relationship Component Properties
-        'attendee': 'cal-address',
-        'contact': 'text',
-        'organizer': 'cal-address',
-        'recurrence-id': 'date-time',
-        'related-to': 'text',
-        'url': 'uri',
-        'uid': 'text',
-        # Recurrence Component Properties
-        'exdate': 'date-time-list',
-        'exrule': 'recur',
-        'rdate': 'date-time-list',
-        'rrule': 'recur',
-        # Alarm Component Properties
-        'action': 'text',
-        'repeat': 'integer',
-        'trigger': 'duration',
-        # Change Management Component Properties
-        'created': 'date-time',
-        'dtstamp': 'date-time',
-        'last-modified': 'date-time',
-        'sequence': 'integer',
-        # Miscellaneous Component Properties
-        'request-status': 'text',
-        ####################################
-        # parameter types (luckily there is no name overlap)
-        'altrep': 'uri',
-        'cn': 'text',
-        'cutype': 'text',
-        'delegated-from': 'cal-address',
-        'delegated-to': 'cal-address',
-        'dir': 'uri',
-        'encoding': 'text',
-        'fmttype': 'text',
-        'fbtype': 'text',
-        'language': 'text',
-        'member': 'cal-address',
-        'partstat': 'text',
-        'range': 'text',
-        'related': 'text',
-        'reltype': 'text',
-        'role': 'text',
-        'rsvp': 'boolean',
-        'sent-by': 'cal-address',
-        'tzid': 'text',
-        'value': 'text',
-    })
+    types_map = CaselessDict(
+        {
+            ####################################
+            # Property value types
+            # Calendar Properties
+            "calscale": "text",
+            "method": "text",
+            "prodid": "text",
+            "version": "text",
+            # Descriptive Component Properties
+            "attach": "uri",
+            "categories": "categories",
+            "class": "text",
+            "comment": "text",
+            "description": "text",
+            "geo": "geo",
+            "location": "text",
+            "percent-complete": "integer",
+            "priority": "integer",
+            "resources": "text",
+            "status": "text",
+            "summary": "text",
+            # Date and Time Component Properties
+            "completed": "date-time",
+            "dtend": "date-time",
+            "due": "date-time",
+            "dtstart": "date-time",
+            "duration": "duration",
+            "freebusy": "period",
+            "transp": "text",
+            # Time Zone Component Properties
+            "tzid": "text",
+            "tzname": "text",
+            "tzoffsetfrom": "utc-offset",
+            "tzoffsetto": "utc-offset",
+            "tzurl": "uri",
+            # Relationship Component Properties
+            "attendee": "cal-address",
+            "contact": "text",
+            "organizer": "cal-address",
+            "recurrence-id": "date-time",
+            "related-to": "text",
+            "url": "uri",
+            "uid": "text",
+            # Recurrence Component Properties
+            "exdate": "date-time-list",
+            "exrule": "recur",
+            "rdate": "date-time-list",
+            "rrule": "recur",
+            # Alarm Component Properties
+            "action": "text",
+            "repeat": "integer",
+            "trigger": "duration",
+            "acknowledged": "date-time",
+            # Change Management Component Properties
+            "created": "date-time",
+            "dtstamp": "date-time",
+            "last-modified": "date-time",
+            "sequence": "integer",
+            # Miscellaneous Component Properties
+            "request-status": "text",
+            ####################################
+            # parameter types (luckily there is no name overlap)
+            "altrep": "uri",
+            "cn": "text",
+            "cutype": "text",
+            "delegated-from": "cal-address",
+            "delegated-to": "cal-address",
+            "dir": "uri",
+            "encoding": "text",
+            "fmttype": "text",
+            "fbtype": "text",
+            "language": "text",
+            "member": "cal-address",
+            "partstat": "text",
+            "range": "text",
+            "related": "text",
+            "reltype": "text",
+            "role": "text",
+            "rsvp": "boolean",
+            "sent-by": "cal-address",
+            "value": "text",
+        }
+    )
 
     def for_property(self, name):
-        """Returns a the default type for a property or parameter
-        """
-        return self[self.types_map.get(name, 'text')]
+        """Returns a the default type for a property or parameter"""
+        return self[self.types_map.get(name, "text")]
 
     def to_ical(self, name, value):
         """Encodes a named value from a primitive python type to an icalendar
@@ -1125,9 +2011,34 @@ class TypesFactory(CaselessDict):
         return decoded
 
 
-__all__ = ["DURATION_REGEX", "TimeBase", "TypesFactory", "WEEKDAY_RULE",
-           "tzid_from_dt", "vBinary", "vBoolean", "vCalAddress",
-           "vCategory", "vDDDLists", "vDDDTypes", "vDate", "vDatetime",
-           "vDuration", "vFloat", "vFrequency", "vGeo", "vInline", "vInt",
-           "vMonth", "vPeriod", "vRecur", "vSkip", "vText", "vTime",
-           "vUTCOffset", "vUri", "vWeekday"]
+__all__ = [
+    "DURATION_REGEX",
+    "TimeBase",
+    "TypesFactory",
+    "WEEKDAY_RULE",
+    "tzid_from_dt",
+    "vBinary",
+    "vBoolean",
+    "vCalAddress",
+    "vCategory",
+    "vDDDLists",
+    "vDDDTypes",
+    "vDate",
+    "vDatetime",
+    "vDuration",
+    "vFloat",
+    "vFrequency",
+    "vGeo",
+    "vInline",
+    "vInt",
+    "vMonth",
+    "vPeriod",
+    "vRecur",
+    "vText",
+    "vTime",
+    "vUTCOffset",
+    "vUri",
+    "vWeekday",
+    "tzid_from_tzinfo",
+    "vSkip",
+]
diff -pruN 6.0.1-3/src/icalendar/tests/alarms/rfc_5545_absolute_alarm_example.ics 6.3.1-1/src/icalendar/tests/alarms/rfc_5545_absolute_alarm_example.ics
--- 6.0.1-3/src/icalendar/tests/alarms/rfc_5545_absolute_alarm_example.ics	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/alarms/rfc_5545_absolute_alarm_example.ics	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,7 @@
+BEGIN:VALARM
+TRIGGER;VALUE=DATE-TIME:19970317T133000Z
+REPEAT:4
+DURATION:PT15M
+ACTION:AUDIO
+ATTACH;FMTTYPE=audio/basic:ftp://example.com/pub/sounds/bell-01.aud
+END:VALARM
diff -pruN 6.0.1-3/src/icalendar/tests/alarms/rfc_5545_end.ics 6.3.1-1/src/icalendar/tests/alarms/rfc_5545_end.ics
--- 6.0.1-3/src/icalendar/tests/alarms/rfc_5545_end.ics	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/alarms/rfc_5545_end.ics	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,8 @@
+BEGIN:VALARM
+TRIGGER;RELATED=END:-P2D
+ACTION:EMAIL
+ATTENDEE:mailto:john_doe@example.com
+SUMMARY:*** REMINDER: SEND AGENDA FOR WEEKLY STAFF MEETING ***
+DESCRIPTION:A draft agenda needs to be sent out to the attendees to the weekly managers meeting (MGR-LIST). Attached is a pointer the document template for the agenda file.
+ATTACH;FMTTYPE=application/msword:http://example.com/templates/agenda.doc
+END:VALARM
diff -pruN 6.0.1-3/src/icalendar/tests/alarms/start_date.ics 6.3.1-1/src/icalendar/tests/alarms/start_date.ics
--- 6.0.1-3/src/icalendar/tests/alarms/start_date.ics	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/alarms/start_date.ics	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,8 @@
+BEGIN:VALARM
+TRIGGER;RELATED=START:-P2D
+ACTION:EMAIL
+ATTENDEE:mailto:john_doe@example.com
+SUMMARY:*** REMINDER: SEND AGENDA FOR WEEKLY STAFF MEETING ***
+DESCRIPTION:A draft agenda needs to be sent out to the attendees to the weekly managers meeting (MGR-LIST). Attached is a pointer the document template for the agenda file.
+ATTACH;FMTTYPE=application/msword:http://example.com/templates/agenda.doc
+END:VALARM
diff -pruN 6.0.1-3/src/icalendar/tests/attr/__init__.py 6.3.1-1/src/icalendar/tests/attr/__init__.py
--- 6.0.1-3/src/icalendar/tests/attr/__init__.py	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/attr/__init__.py	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1 @@
+"""Test the getters/setters of components."""
\ No newline at end of file
diff -pruN 6.0.1-3/src/icalendar/tests/attr/test_alarm.py 6.3.1-1/src/icalendar/tests/attr/test_alarm.py
--- 6.0.1-3/src/icalendar/tests/attr/test_alarm.py	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/attr/test_alarm.py	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,54 @@
+"""Test the properties of the alarm."""
+
+import pytest
+
+from icalendar.cal import Alarm
+from icalendar.error import InvalidCalendar
+
+
+def test_repeat_absent():
+    """Test the absence of REPEAT."""
+    assert Alarm().REPEAT == 0
+
+
+def test_repeat_number():
+    """Test the absence of REPEAT."""
+    assert Alarm({"REPEAT": 10}).REPEAT == 10
+
+
+def test_set_REPEAT():
+    """Check setting the value."""
+    a = Alarm()
+    a.REPEAT = 10
+    assert a.REPEAT == 10
+
+
+def test_set_REPEAT_twice():
+    """Check setting the value."""
+    a = Alarm()
+    a.REPEAT = 10
+    a.REPEAT = 20
+    assert a.REPEAT == 20
+
+
+def test_add_REPEAT():
+    """Check setting the value."""
+    a = Alarm()
+    a.add("REPEAT", 10)
+    assert a.REPEAT == 10
+
+
+def test_invalid_repeat_value():
+    """Check setting the value."""
+    a = Alarm()
+    with pytest.raises(ValueError):
+        a.REPEAT = "asd"
+    a["REPEAT"] = "asd"
+    with pytest.raises(InvalidCalendar):
+        a.REPEAT  # noqa: B018
+
+
+def test_alarm_to_string():
+    a = Alarm()
+    a.REPEAT = 11
+    assert a.to_ical() == b"BEGIN:VALARM\r\nREPEAT:11\r\nEND:VALARM\r\n"
diff -pruN 6.0.1-3/src/icalendar/tests/attr/test_component.py 6.3.1-1/src/icalendar/tests/attr/test_component.py
--- 6.0.1-3/src/icalendar/tests/attr/test_component.py	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/attr/test_component.py	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,92 @@
+"""Test common properties of components."""
+
+from datetime import date, datetime, timedelta
+
+import pytest
+
+from icalendar import Event, FreeBusy, Journal, Todo, vDDDTypes
+from icalendar.cal import Component
+from icalendar.error import InvalidCalendar
+
+
+@pytest.fixture(params=[Event, Todo, Journal, FreeBusy])
+def dtstamp_comp(request):
+    """a component to test"""
+    return request.param()
+
+
+def test_no_dtstamp(dtstamp_comp):
+    """We have None as a value."""
+    assert dtstamp_comp.DTSTAMP is None
+
+
+def set_dtstamp_attribute(component: Component, value: date):
+    """Use the setter."""
+    component.DTSTAMP = value
+
+
+def set_dtstamp_item(component: Component, value: date):
+    """Use setitem."""
+    component["DTSTAMP"] = vDDDTypes(value)
+
+
+def set_dtstamp_add(component: Component, value: date):
+    """Use add."""
+    component.add("DTSTAMP", value)
+
+
+@pytest.mark.parametrize(
+    ("value", "timezone", "expected"),
+    [
+        (datetime(2024, 10, 11, 23, 1), None, datetime(2024, 10, 11, 23, 1)),
+        (datetime(2024, 10, 11, 23, 1), "Europe/Berlin", datetime(2024, 10, 11, 21, 1)),
+        (datetime(2024, 10, 11, 22, 1), "UTC", datetime(2024, 10, 11, 22, 1)),
+        (date(2024, 10, 10), None, datetime(2024, 10, 10)),
+    ],
+)
+@pytest.mark.parametrize(
+    "set_dtstamp", [set_dtstamp_add, set_dtstamp_attribute, set_dtstamp_item]
+)
+def test_set_value_and_get_it(
+    dtstamp_comp, value, timezone, expected, tzp, set_dtstamp
+):
+    """Set and get the DTSTAMP value."""
+    dtstamp = value if timezone is None else tzp.localize(value, timezone)
+    set_dtstamp(dtstamp_comp, dtstamp)
+    in_utc = tzp.localize_utc(expected)
+    get_value = dtstamp_comp.get("DTSTAMP").dt
+    assert in_utc == get_value or set_dtstamp != set_dtstamp_attribute
+    assert in_utc == dtstamp_comp.DTSTAMP
+
+
+@pytest.mark.parametrize("invalid_value", [None, timedelta()])
+def test_set_invalid_value(invalid_value, dtstamp_comp):
+    """Check handling of invalid values."""
+    with pytest.raises(TypeError) as e:
+        dtstamp_comp.DTSTAMP = invalid_value
+    assert e.value.args[0] == f"DTSTAMP takes a datetime in UTC, not {invalid_value}"
+
+
+@pytest.mark.parametrize("invalid_value", [None, vDDDTypes(timedelta())])
+def test_get_invalid_value(invalid_value, dtstamp_comp):
+    """Check handling of invalid values."""
+    dtstamp_comp["DTSTAMP"] = invalid_value
+    with pytest.raises(InvalidCalendar) as e:
+        dtstamp_comp.DTSTAMP  # noqa: B018
+    assert (
+        e.value.args[0]
+        == f"DTSTAMP must be a datetime in UTC, not {getattr(invalid_value, 'dt', invalid_value)}"
+    )
+
+
+def test_set_twice(dtstamp_comp, tzp):
+    """Set the value twice."""
+    dtstamp_comp.DTSTAMP = date(2014, 1, 1)
+    dtstamp_comp.DTSTAMP = date(2014, 1, 2)
+    assert tzp.localize_utc(datetime(2014, 1, 2)) == dtstamp_comp.DTSTAMP
+
+
+def test_last_modified(dtstamp_comp, tzp):
+    """Check we can set LAST_MODIFIED in the same way as DTSTAMP"""
+    dtstamp_comp.LAST_MODIFIED = date(2014, 1, 2)
+    assert tzp.localize_utc(datetime(2014, 1, 2)) == dtstamp_comp.LAST_MODIFIED
diff -pruN 6.0.1-3/src/icalendar/tests/attr/test_exdates.py 6.3.1-1/src/icalendar/tests/attr/test_exdates.py
--- 6.0.1-3/src/icalendar/tests/attr/test_exdates.py	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/attr/test_exdates.py	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,62 @@
+"""This tests the exdate property.
+"""
+from __future__ import annotations
+
+from datetime import date, datetime
+from pprint import pprint
+from typing import Union
+
+import pytest
+
+from icalendar import (
+    Calendar,
+    Event,
+    Journal,
+    TimezoneDaylight,
+    TimezoneStandard,
+    Todo,
+)
+
+C_EXDATE = Union[Event, Todo, Journal, TimezoneDaylight, TimezoneStandard]
+
+@pytest.fixture(params = [Event, Todo, Journal, TimezoneDaylight, TimezoneStandard])
+def c_exdate(request) -> C_EXDATE:
+    """Return a component that uses exdate."""
+    return request.param()
+
+
+
+@pytest.fixture(
+    params=[
+        lambda _tzp: date(2019, 10, 11),
+        lambda _tzp: datetime(2000, 1, 13, 12, 1),
+        lambda tzp: tzp.localize_utc(datetime(2031, 12, 1, 23, 59)),
+        lambda tzp: tzp.localize(datetime(1984, 1, 13, 13, 1), "Europe/Athens"),
+    ]
+)
+def exdate(request, tzp):
+    """Possible values for an exdate."""
+    return request.param(tzp)
+
+def test_no_exdates_by_default(c_exdate):
+    """We expect no exdate by default."""
+    assert c_exdate.exdates == []
+
+def test_set_and_retrieve_exdate(exdate, c_exdate):
+    """Set the attribute and get the value."""
+    c_exdate.add("exdate", [exdate])
+    result = [exdate]
+    assert c_exdate.exdates == result
+
+def test_set_and_retrieve_exdates_in_list(exdate, c_exdate):
+    """Set the attribute and get the value."""
+    c_exdate.add("exdate", [exdate, exdate])
+    result = [exdate, exdate]
+    assert c_exdate.exdates == result
+
+def test_set_and_retrieve_exdates_twice(exdate, c_exdate):
+    """Set the attribute and get the value."""
+    c_exdate.add("exdate", [exdate])
+    c_exdate.add("exdate", [exdate])
+    result = [exdate, exdate]
+    assert c_exdate.exdates == result
diff -pruN 6.0.1-3/src/icalendar/tests/attr/test_rdate.py 6.3.1-1/src/icalendar/tests/attr/test_rdate.py
--- 6.0.1-3/src/icalendar/tests/attr/test_rdate.py	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/attr/test_rdate.py	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,111 @@
+"""This tests the RDATE property.
+"""
+from __future__ import annotations
+
+from datetime import date, datetime
+from pprint import pprint
+from typing import Union
+
+import pytest
+
+from icalendar import (
+    Calendar,
+    Event,
+    Journal,
+    TimezoneDaylight,
+    TimezoneStandard,
+    Todo,
+)
+
+C_RDATE = Union[Event, Todo, Journal, TimezoneDaylight, TimezoneStandard]
+
+@pytest.fixture(params = [Event, Todo, Journal, TimezoneDaylight, TimezoneStandard])
+def c_rdate(request) -> C_RDATE:
+    """Return a component that uses RDATE."""
+    return request.param()
+
+
+@pytest.fixture(
+    params=[
+        lambda _tzp: date(2019, 10, 11),
+        lambda _tzp: datetime(2000, 1, 13, 12, 1),
+        lambda tzp: tzp.localize_utc(datetime(2031, 12, 1, 23, 59)),
+        lambda tzp: tzp.localize(datetime(1984, 1, 13, 13, 1), "Europe/Athens"),
+        lambda _tzp: ((datetime(2000, 1, 13, 12, 1), datetime(2000, 1, 13, 12, 2))),
+        lambda tzp: ((tzp.localize_utc(datetime(2001, 1, 13, 12, 1)), tzp.localize_utc(datetime(2001, 1, 13, 12, 2)))),
+    ]
+)
+def rdate(request, tzp):
+    """Possible values for an rdate."""
+    return request.param(tzp)
+
+def test_no_rdates_by_default(c_rdate):
+    """We expect no rdate by default."""
+    assert c_rdate.rdates == []
+
+
+def test_set_and_retrieve_rdate(rdate, c_rdate):
+    """Set the attribute and get the value."""
+    c_rdate.add("RDATE", [rdate])
+    result = [rdate if isinstance(rdate, tuple) else (rdate, None)]
+    assert c_rdate.rdates == result
+
+
+def test_get_example_0(calendars):
+    """Test an example rdate."""
+    cal : Calendar = calendars.rfc_5545_RDATE_example
+    event = cal.events[0]
+    assert event.rdates == [(datetime(1997, 7, 14, 12, 30), None)]
+
+
+def test_get_example_1(calendars, tzp):
+    """Test an example rdate."""
+    cal : Calendar = calendars.rfc_5545_RDATE_example
+    event = cal.events[1]
+    assert event.rdates == [(tzp.localize_utc(datetime(1997, 7, 14, 12, 30)), None)]
+
+def test_get_example_2(calendars, tzp):
+    """Test an example rdate."""
+    cal : Calendar = calendars.rfc_5545_RDATE_example
+    event = cal.events[2]
+    assert event.rdates == [(tzp.localize(datetime(1997, 7, 14, 8, 30), "America/New_York"),None)]
+
+def test_get_example_3(calendars, tzp):
+    """Test an example rdate."""
+    cal : Calendar = calendars.rfc_5545_RDATE_example
+    event = cal.events[3]
+    rdates_3 = [
+        (tzp.localize_utc(datetime(1996, 4, 3, 2)), tzp.localize_utc(datetime(1996, 4, 3, 4))),
+        (tzp.localize_utc(datetime(1996, 4, 4, 1)), tzp.localize_utc(datetime(1996, 4, 4, 4))),
+    ]
+    pprint(event.rdates)
+    pprint(rdates_3)
+    assert event.rdates == rdates_3
+
+def d(i:int) -> tuple[date, None]:
+    s = str(i)
+    return (date(int(s[:4]), int(s[4:6].lstrip("0")), int(s[6:].lstrip("0"))), None)
+
+
+RDATES_4 = list(map(d, (
+        19970101,
+        19970120,
+        19970217,
+        19970421,
+        19970526,
+        19970704,
+        19970901,
+        19971014,
+        19971128,
+        19971129,
+        19971225,
+    )))
+
+
+def test_get_example_4(calendars, tzp):
+    """Test an example rdate."""
+    cal : Calendar = calendars.rfc_5545_RDATE_example
+    event = cal.events[4]
+    pprint(event.rdates)
+    pprint(RDATES_4)
+    assert event.rdates == RDATES_4
diff -pruN 6.0.1-3/src/icalendar/tests/attr/test_rrule.py 6.3.1-1/src/icalendar/tests/attr/test_rrule.py
--- 6.0.1-3/src/icalendar/tests/attr/test_rrule.py	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/attr/test_rrule.py	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,45 @@
+"""Test getting the rrules from a component."""
+
+import pytest
+
+from icalendar import (
+    Component,
+    Event,
+    Journal,
+    TimezoneDaylight,
+    TimezoneStandard,
+    Todo,
+    vRecur,
+)
+
+RRULE_0 = vRecur.from_ical("FREQ=DAILY;COUNT=10")
+RRULE_1 = vRecur.from_ical("FREQ=DAILY;UNTIL=19971224T000000Z")
+RRULE_2 = vRecur.from_ical("FREQ=DAILY;INTERVAL=2")
+RRULE_3 = vRecur.from_ical("FREQ=DAILY;INTERVAL=10;COUNT=5")
+RRULE_4 = vRecur.from_ical("FREQ=YEARLY;UNTIL=20000131T140000Z;BYMONTH=1;BYDAY=SU,MO,TU,WE,TH,FR,SA")
+
+@pytest.fixture(params=[RRULE_0, RRULE_1, RRULE_2, RRULE_3, RRULE_4])
+def rrule(request) -> str:
+    """An rrule."""
+    return request.param
+
+@pytest.fixture(params = [Event, Todo, Journal, TimezoneDaylight, TimezoneStandard])
+def c_rrule(request) -> Component:
+    """Return a component that uses RDATE."""
+    return request.param()
+
+def test_no_rrules_by_default(c_rrule):
+    """We expect no rdate by default."""
+    assert c_rrule.rrules == []
+
+
+def test_one_rrule(c_rrule, rrule):
+    """Add one rrule."""
+    c_rrule.add("rrule", rrule)
+    assert c_rrule.rrules == [rrule]
+
+def test_two_rrules(c_rrule, rrule):
+    """Add two rrules."""
+    c_rrule.add("rrule", rrule)
+    c_rrule.add("rrule", RRULE_3)
+    assert c_rrule.rrules == [rrule, RRULE_3]
diff -pruN 6.0.1-3/src/icalendar/tests/calendars/alarm_etar_future.ics 6.3.1-1/src/icalendar/tests/calendars/alarm_etar_future.ics
--- 6.0.1-3/src/icalendar/tests/calendars/alarm_etar_future.ics	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/calendars/alarm_etar_future.ics	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,235 @@
+BEGIN:VCALENDAR
+PRODID:-//Offline Calendar//iCal Import/Export 2.8.1//EN
+VERSION:2.0
+METHOD:PUBLISH
+CALSCALE:GREGORIAN
+BEGIN:VTIMEZONE
+TZID:Europe/London
+TZURL:http://tzurl.org/zoneinfo/Europe/London
+X-LIC-LOCATION:Europe/London
+BEGIN:DAYLIGHT
+TZOFFSETFROM:+0000
+TZOFFSETTO:+0100
+TZNAME:BST
+DTSTART:19810329T010000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETFROM:+0100
+TZOFFSETTO:+0000
+TZNAME:GMT
+DTSTART:19961027T020000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETFROM:-000115
+TZOFFSETTO:+0000
+TZNAME:GMT
+DTSTART:18471201T000115
+RDATE:18471201T000115
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETFROM:+0000
+TZOFFSETTO:+0100
+TZNAME:BST
+DTSTART:19160521T020000
+RDATE:19160521T020000
+RDATE:19170408T020000
+RDATE:19180324T020000
+RDATE:19190330T020000
+RDATE:19200328T020000
+RDATE:19210403T020000
+RDATE:19220326T020000
+RDATE:19230422T020000
+RDATE:19240413T020000
+RDATE:19250419T020000
+RDATE:19260418T020000
+RDATE:19270410T020000
+RDATE:19280422T020000
+RDATE:19290421T020000
+RDATE:19300413T020000
+RDATE:19310419T020000
+RDATE:19320417T020000
+RDATE:19330409T020000
+RDATE:19340422T020000
+RDATE:19350414T020000
+RDATE:19360419T020000
+RDATE:19370418T020000
+RDATE:19380410T020000
+RDATE:19390416T020000
+RDATE:19400225T020000
+RDATE:19460414T020000
+RDATE:19470316T020000
+RDATE:19480314T020000
+RDATE:19490403T020000
+RDATE:19500416T020000
+RDATE:19510415T020000
+RDATE:19520420T020000
+RDATE:19530419T020000
+RDATE:19540411T020000
+RDATE:19550417T020000
+RDATE:19560422T020000
+RDATE:19570414T020000
+RDATE:19580420T020000
+RDATE:19590419T020000
+RDATE:19600410T020000
+RDATE:19610326T020000
+RDATE:19620325T020000
+RDATE:19630331T020000
+RDATE:19640322T020000
+RDATE:19650321T020000
+RDATE:19660320T020000
+RDATE:19670319T020000
+RDATE:19680218T020000
+RDATE:19720319T020000
+RDATE:19730318T020000
+RDATE:19740317T020000
+RDATE:19750316T020000
+RDATE:19760321T020000
+RDATE:19770320T020000
+RDATE:19780319T020000
+RDATE:19790318T020000
+RDATE:19800316T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETFROM:+0100
+TZOFFSETTO:+0000
+TZNAME:GMT
+DTSTART:19161001T030000
+RDATE:19161001T030000
+RDATE:19170917T030000
+RDATE:19180930T030000
+RDATE:19190929T030000
+RDATE:19201025T030000
+RDATE:19211003T030000
+RDATE:19221008T030000
+RDATE:19230916T030000
+RDATE:19240921T030000
+RDATE:19251004T030000
+RDATE:19261003T030000
+RDATE:19271002T030000
+RDATE:19281007T030000
+RDATE:19291006T030000
+RDATE:19301005T030000
+RDATE:19311004T030000
+RDATE:19321002T030000
+RDATE:19331008T030000
+RDATE:19341007T030000
+RDATE:19351006T030000
+RDATE:19361004T030000
+RDATE:19371003T030000
+RDATE:19381002T030000
+RDATE:19391119T030000
+RDATE:19451007T030000
+RDATE:19461006T030000
+RDATE:19471102T030000
+RDATE:19481031T030000
+RDATE:19491030T030000
+RDATE:19501022T030000
+RDATE:19511021T030000
+RDATE:19521026T030000
+RDATE:19531004T030000
+RDATE:19541003T030000
+RDATE:19551002T030000
+RDATE:19561007T030000
+RDATE:19571006T030000
+RDATE:19581005T030000
+RDATE:19591004T030000
+RDATE:19601002T030000
+RDATE:19611029T030000
+RDATE:19621028T030000
+RDATE:19631027T030000
+RDATE:19641025T030000
+RDATE:19651024T030000
+RDATE:19661023T030000
+RDATE:19671029T030000
+RDATE:19711031T030000
+RDATE:19721029T030000
+RDATE:19731028T030000
+RDATE:19741027T030000
+RDATE:19751026T030000
+RDATE:19761024T030000
+RDATE:19771023T030000
+RDATE:19781029T030000
+RDATE:19791028T030000
+RDATE:19801026T030000
+RDATE:19811025T020000
+RDATE:19821024T020000
+RDATE:19831023T020000
+RDATE:19841028T020000
+RDATE:19851027T020000
+RDATE:19861026T020000
+RDATE:19871025T020000
+RDATE:19881023T020000
+RDATE:19891029T020000
+RDATE:19901028T020000
+RDATE:19911027T020000
+RDATE:19921025T020000
+RDATE:19931024T020000
+RDATE:19941023T020000
+RDATE:19951022T020000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETFROM:+0100
+TZOFFSETTO:+0200
+TZNAME:BDST
+DTSTART:19410504T010000
+RDATE:19410504T010000
+RDATE:19420405T010000
+RDATE:19430404T010000
+RDATE:19440402T010000
+RDATE:19450402T010000
+RDATE:19470413T010000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETFROM:+0200
+TZOFFSETTO:+0100
+TZNAME:BST
+DTSTART:19410810T030000
+RDATE:19410810T030000
+RDATE:19420809T030000
+RDATE:19430815T030000
+RDATE:19440917T030000
+RDATE:19450715T030000
+RDATE:19470810T030000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETFROM:+0100
+TZOFFSETTO:+0100
+TZNAME:BST
+DTSTART:19681026T230000
+RDATE:19681026T230000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETFROM:+0000
+TZOFFSETTO:+0000
+TZNAME:GMT
+DTSTART:19960101T000000
+RDATE:19960101T000000
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+DTSTAMP:20241005T112701Z
+UID:17281276213728ad54d03afa44d1ca60b8c52afaece9e@sufficientlysecure.org
+SUMMARY:event with alarms android
+STATUS:CONFIRMED
+DTSTART;TZID=Europe/London:20241005T130000
+DTEND:20241005T130000Z
+LAST-MODIFIED:20241005T112701Z
+BEGIN:VALARM
+TRIGGER:-PT30M
+ACTION:DISPLAY
+DESCRIPTION:event with alarms android
+END:VALARM
+BEGIN:VALARM
+TRIGGER:-PT25M
+ACTION:DISPLAY
+DESCRIPTION:event with alarms android
+END:VALARM
+BEGIN:VALARM
+TRIGGER:-PT5M
+ACTION:DISPLAY
+DESCRIPTION:event with alarms android
+END:VALARM
+END:VEVENT
+END:VCALENDAR
diff -pruN 6.0.1-3/src/icalendar/tests/calendars/alarm_etar_notification.ics 6.3.1-1/src/icalendar/tests/calendars/alarm_etar_notification.ics
--- 6.0.1-3/src/icalendar/tests/calendars/alarm_etar_notification.ics	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/calendars/alarm_etar_notification.ics	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,235 @@
+BEGIN:VCALENDAR
+PRODID:-//Offline Calendar//iCal Import/Export 2.8.1//EN
+VERSION:2.0
+METHOD:PUBLISH
+CALSCALE:GREGORIAN
+BEGIN:VTIMEZONE
+TZID:Europe/London
+TZURL:http://tzurl.org/zoneinfo/Europe/London
+X-LIC-LOCATION:Europe/London
+BEGIN:DAYLIGHT
+TZOFFSETFROM:+0000
+TZOFFSETTO:+0100
+TZNAME:BST
+DTSTART:19810329T010000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETFROM:+0100
+TZOFFSETTO:+0000
+TZNAME:GMT
+DTSTART:19961027T020000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETFROM:-000115
+TZOFFSETTO:+0000
+TZNAME:GMT
+DTSTART:18471201T000115
+RDATE:18471201T000115
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETFROM:+0000
+TZOFFSETTO:+0100
+TZNAME:BST
+DTSTART:19160521T020000
+RDATE:19160521T020000
+RDATE:19170408T020000
+RDATE:19180324T020000
+RDATE:19190330T020000
+RDATE:19200328T020000
+RDATE:19210403T020000
+RDATE:19220326T020000
+RDATE:19230422T020000
+RDATE:19240413T020000
+RDATE:19250419T020000
+RDATE:19260418T020000
+RDATE:19270410T020000
+RDATE:19280422T020000
+RDATE:19290421T020000
+RDATE:19300413T020000
+RDATE:19310419T020000
+RDATE:19320417T020000
+RDATE:19330409T020000
+RDATE:19340422T020000
+RDATE:19350414T020000
+RDATE:19360419T020000
+RDATE:19370418T020000
+RDATE:19380410T020000
+RDATE:19390416T020000
+RDATE:19400225T020000
+RDATE:19460414T020000
+RDATE:19470316T020000
+RDATE:19480314T020000
+RDATE:19490403T020000
+RDATE:19500416T020000
+RDATE:19510415T020000
+RDATE:19520420T020000
+RDATE:19530419T020000
+RDATE:19540411T020000
+RDATE:19550417T020000
+RDATE:19560422T020000
+RDATE:19570414T020000
+RDATE:19580420T020000
+RDATE:19590419T020000
+RDATE:19600410T020000
+RDATE:19610326T020000
+RDATE:19620325T020000
+RDATE:19630331T020000
+RDATE:19640322T020000
+RDATE:19650321T020000
+RDATE:19660320T020000
+RDATE:19670319T020000
+RDATE:19680218T020000
+RDATE:19720319T020000
+RDATE:19730318T020000
+RDATE:19740317T020000
+RDATE:19750316T020000
+RDATE:19760321T020000
+RDATE:19770320T020000
+RDATE:19780319T020000
+RDATE:19790318T020000
+RDATE:19800316T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETFROM:+0100
+TZOFFSETTO:+0000
+TZNAME:GMT
+DTSTART:19161001T030000
+RDATE:19161001T030000
+RDATE:19170917T030000
+RDATE:19180930T030000
+RDATE:19190929T030000
+RDATE:19201025T030000
+RDATE:19211003T030000
+RDATE:19221008T030000
+RDATE:19230916T030000
+RDATE:19240921T030000
+RDATE:19251004T030000
+RDATE:19261003T030000
+RDATE:19271002T030000
+RDATE:19281007T030000
+RDATE:19291006T030000
+RDATE:19301005T030000
+RDATE:19311004T030000
+RDATE:19321002T030000
+RDATE:19331008T030000
+RDATE:19341007T030000
+RDATE:19351006T030000
+RDATE:19361004T030000
+RDATE:19371003T030000
+RDATE:19381002T030000
+RDATE:19391119T030000
+RDATE:19451007T030000
+RDATE:19461006T030000
+RDATE:19471102T030000
+RDATE:19481031T030000
+RDATE:19491030T030000
+RDATE:19501022T030000
+RDATE:19511021T030000
+RDATE:19521026T030000
+RDATE:19531004T030000
+RDATE:19541003T030000
+RDATE:19551002T030000
+RDATE:19561007T030000
+RDATE:19571006T030000
+RDATE:19581005T030000
+RDATE:19591004T030000
+RDATE:19601002T030000
+RDATE:19611029T030000
+RDATE:19621028T030000
+RDATE:19631027T030000
+RDATE:19641025T030000
+RDATE:19651024T030000
+RDATE:19661023T030000
+RDATE:19671029T030000
+RDATE:19711031T030000
+RDATE:19721029T030000
+RDATE:19731028T030000
+RDATE:19741027T030000
+RDATE:19751026T030000
+RDATE:19761024T030000
+RDATE:19771023T030000
+RDATE:19781029T030000
+RDATE:19791028T030000
+RDATE:19801026T030000
+RDATE:19811025T020000
+RDATE:19821024T020000
+RDATE:19831023T020000
+RDATE:19841028T020000
+RDATE:19851027T020000
+RDATE:19861026T020000
+RDATE:19871025T020000
+RDATE:19881023T020000
+RDATE:19891029T020000
+RDATE:19901028T020000
+RDATE:19911027T020000
+RDATE:19921025T020000
+RDATE:19931024T020000
+RDATE:19941023T020000
+RDATE:19951022T020000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETFROM:+0100
+TZOFFSETTO:+0200
+TZNAME:BDST
+DTSTART:19410504T010000
+RDATE:19410504T010000
+RDATE:19420405T010000
+RDATE:19430404T010000
+RDATE:19440402T010000
+RDATE:19450402T010000
+RDATE:19470413T010000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETFROM:+0200
+TZOFFSETTO:+0100
+TZNAME:BST
+DTSTART:19410810T030000
+RDATE:19410810T030000
+RDATE:19420809T030000
+RDATE:19430815T030000
+RDATE:19440917T030000
+RDATE:19450715T030000
+RDATE:19470810T030000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETFROM:+0100
+TZOFFSETTO:+0100
+TZNAME:BST
+DTSTART:19681026T230000
+RDATE:19681026T230000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETFROM:+0000
+TZOFFSETTO:+0000
+TZNAME:GMT
+DTSTART:19960101T000000
+RDATE:19960101T000000
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+DTSTAMP:20241005T113036Z
+UID:17281276213728ad54d03afa44d1ca60b8c52afaece9e@sufficientlysecure.org
+SUMMARY:event with alarms android
+STATUS:CONFIRMED
+DTSTART;TZID=Europe/London:20241005T130000
+DTEND:20241005T130000Z
+LAST-MODIFIED:20241005T112701Z
+BEGIN:VALARM
+TRIGGER:-PT30M
+ACTION:DISPLAY
+DESCRIPTION:event with alarms android
+END:VALARM
+BEGIN:VALARM
+TRIGGER:-PT25M
+ACTION:DISPLAY
+DESCRIPTION:event with alarms android
+END:VALARM
+BEGIN:VALARM
+TRIGGER:-PT5M
+ACTION:DISPLAY
+DESCRIPTION:event with alarms android
+END:VALARM
+END:VEVENT
+END:VCALENDAR
diff -pruN 6.0.1-3/src/icalendar/tests/calendars/alarm_etar_notification_clicked.ics 6.3.1-1/src/icalendar/tests/calendars/alarm_etar_notification_clicked.ics
--- 6.0.1-3/src/icalendar/tests/calendars/alarm_etar_notification_clicked.ics	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/calendars/alarm_etar_notification_clicked.ics	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,225 @@
+BEGIN:VCALENDAR
+PRODID:-//Offline Calendar//iCal Import/Export 2.8.1//EN
+VERSION:2.0
+METHOD:PUBLISH
+CALSCALE:GREGORIAN
+BEGIN:VTIMEZONE
+TZID:Europe/London
+TZURL:http://tzurl.org/zoneinfo/Europe/London
+X-LIC-LOCATION:Europe/London
+BEGIN:DAYLIGHT
+TZOFFSETFROM:+0000
+TZOFFSETTO:+0100
+TZNAME:BST
+DTSTART:19810329T010000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETFROM:+0100
+TZOFFSETTO:+0000
+TZNAME:GMT
+DTSTART:19961027T020000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETFROM:-000115
+TZOFFSETTO:+0000
+TZNAME:GMT
+DTSTART:18471201T000115
+RDATE:18471201T000115
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETFROM:+0000
+TZOFFSETTO:+0100
+TZNAME:BST
+DTSTART:19160521T020000
+RDATE:19160521T020000
+RDATE:19170408T020000
+RDATE:19180324T020000
+RDATE:19190330T020000
+RDATE:19200328T020000
+RDATE:19210403T020000
+RDATE:19220326T020000
+RDATE:19230422T020000
+RDATE:19240413T020000
+RDATE:19250419T020000
+RDATE:19260418T020000
+RDATE:19270410T020000
+RDATE:19280422T020000
+RDATE:19290421T020000
+RDATE:19300413T020000
+RDATE:19310419T020000
+RDATE:19320417T020000
+RDATE:19330409T020000
+RDATE:19340422T020000
+RDATE:19350414T020000
+RDATE:19360419T020000
+RDATE:19370418T020000
+RDATE:19380410T020000
+RDATE:19390416T020000
+RDATE:19400225T020000
+RDATE:19460414T020000
+RDATE:19470316T020000
+RDATE:19480314T020000
+RDATE:19490403T020000
+RDATE:19500416T020000
+RDATE:19510415T020000
+RDATE:19520420T020000
+RDATE:19530419T020000
+RDATE:19540411T020000
+RDATE:19550417T020000
+RDATE:19560422T020000
+RDATE:19570414T020000
+RDATE:19580420T020000
+RDATE:19590419T020000
+RDATE:19600410T020000
+RDATE:19610326T020000
+RDATE:19620325T020000
+RDATE:19630331T020000
+RDATE:19640322T020000
+RDATE:19650321T020000
+RDATE:19660320T020000
+RDATE:19670319T020000
+RDATE:19680218T020000
+RDATE:19720319T020000
+RDATE:19730318T020000
+RDATE:19740317T020000
+RDATE:19750316T020000
+RDATE:19760321T020000
+RDATE:19770320T020000
+RDATE:19780319T020000
+RDATE:19790318T020000
+RDATE:19800316T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETFROM:+0100
+TZOFFSETTO:+0000
+TZNAME:GMT
+DTSTART:19161001T030000
+RDATE:19161001T030000
+RDATE:19170917T030000
+RDATE:19180930T030000
+RDATE:19190929T030000
+RDATE:19201025T030000
+RDATE:19211003T030000
+RDATE:19221008T030000
+RDATE:19230916T030000
+RDATE:19240921T030000
+RDATE:19251004T030000
+RDATE:19261003T030000
+RDATE:19271002T030000
+RDATE:19281007T030000
+RDATE:19291006T030000
+RDATE:19301005T030000
+RDATE:19311004T030000
+RDATE:19321002T030000
+RDATE:19331008T030000
+RDATE:19341007T030000
+RDATE:19351006T030000
+RDATE:19361004T030000
+RDATE:19371003T030000
+RDATE:19381002T030000
+RDATE:19391119T030000
+RDATE:19451007T030000
+RDATE:19461006T030000
+RDATE:19471102T030000
+RDATE:19481031T030000
+RDATE:19491030T030000
+RDATE:19501022T030000
+RDATE:19511021T030000
+RDATE:19521026T030000
+RDATE:19531004T030000
+RDATE:19541003T030000
+RDATE:19551002T030000
+RDATE:19561007T030000
+RDATE:19571006T030000
+RDATE:19581005T030000
+RDATE:19591004T030000
+RDATE:19601002T030000
+RDATE:19611029T030000
+RDATE:19621028T030000
+RDATE:19631027T030000
+RDATE:19641025T030000
+RDATE:19651024T030000
+RDATE:19661023T030000
+RDATE:19671029T030000
+RDATE:19711031T030000
+RDATE:19721029T030000
+RDATE:19731028T030000
+RDATE:19741027T030000
+RDATE:19751026T030000
+RDATE:19761024T030000
+RDATE:19771023T030000
+RDATE:19781029T030000
+RDATE:19791028T030000
+RDATE:19801026T030000
+RDATE:19811025T020000
+RDATE:19821024T020000
+RDATE:19831023T020000
+RDATE:19841028T020000
+RDATE:19851027T020000
+RDATE:19861026T020000
+RDATE:19871025T020000
+RDATE:19881023T020000
+RDATE:19891029T020000
+RDATE:19901028T020000
+RDATE:19911027T020000
+RDATE:19921025T020000
+RDATE:19931024T020000
+RDATE:19941023T020000
+RDATE:19951022T020000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETFROM:+0100
+TZOFFSETTO:+0200
+TZNAME:BDST
+DTSTART:19410504T010000
+RDATE:19410504T010000
+RDATE:19420405T010000
+RDATE:19430404T010000
+RDATE:19440402T010000
+RDATE:19450402T010000
+RDATE:19470413T010000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETFROM:+0200
+TZOFFSETTO:+0100
+TZNAME:BST
+DTSTART:19410810T030000
+RDATE:19410810T030000
+RDATE:19420809T030000
+RDATE:19430815T030000
+RDATE:19440917T030000
+RDATE:19450715T030000
+RDATE:19470810T030000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETFROM:+0100
+TZOFFSETTO:+0100
+TZNAME:BST
+DTSTART:19681026T230000
+RDATE:19681026T230000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETFROM:+0000
+TZOFFSETTO:+0000
+TZNAME:GMT
+DTSTART:19960101T000000
+RDATE:19960101T000000
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+DTSTAMP:20241005T130738Z
+UID:17281336589228ad54d03afa44d1ca60b8c52afaece9e@sufficientlysecure.org
+SUMMARY:event with alarm acknowledged
+STATUS:CONFIRMED
+DTSTART;TZID=Europe/London:20241005T141700
+DTEND:20241005T141700Z
+LAST-MODIFIED:20241005T130738Z
+BEGIN:VALARM
+TRIGGER:-PT10M
+ACTION:DISPLAY
+DESCRIPTION:event with alarm acknowledged
+END:VALARM
+END:VEVENT
+END:VCALENDAR
diff -pruN 6.0.1-3/src/icalendar/tests/calendars/alarm_google_acknowledged.ics 6.3.1-1/src/icalendar/tests/calendars/alarm_google_acknowledged.ics
--- 6.0.1-3/src/icalendar/tests/calendars/alarm_google_acknowledged.ics	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/calendars/alarm_google_acknowledged.ics	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,60 @@
+BEGIN:VCALENDAR
+PRODID:-//Google Inc//Google Calendar 70.9054//EN
+VERSION:2.0
+CALSCALE:GREGORIAN
+METHOD:PUBLISH
+X-WR-CALNAME:Nicco Kunzmann
+X-WR-TIMEZONE:Europe/London
+BEGIN:VTIMEZONE
+TZID:Europe/Berlin
+X-LIC-LOCATION:Europe/Berlin
+BEGIN:DAYLIGHT
+TZOFFSETFROM:+0100
+TZOFFSETTO:+0200
+TZNAME:GMT+2
+DTSTART:19700329T020000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETFROM:+0200
+TZOFFSETTO:+0100
+TZNAME:GMT+1
+DTSTART:19701025T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+DTSTART:20241004T181500Z
+DTEND:20241004T190000Z
+DTSTAMP:20241004T180026Z
+UID:79fs7pkqvht9m5igs0vjv1sfra@google.com
+CREATED:20241004T175920Z
+LAST-MODIFIED:20241004T175928Z
+SEQUENCE:0
+STATUS:CONFIRMED
+SUMMARY:event with alarms
+TRANSP:OPAQUE
+BEGIN:VALARM
+ACTION:DISPLAY
+TRIGGER:-P0DT0H10M0S
+DESCRIPTION:This is an event reminder
+END:VALARM
+BEGIN:VALARM
+ACTION:DISPLAY
+TRIGGER:-P0DT0H14M0S
+DESCRIPTION:This is an event reminder
+END:VALARM
+BEGIN:VALARM
+ACTION:EMAIL
+ATTENDEE:mailto:niccokunzmann@googlemail.com
+TRIGGER:-P0DT0H15M0S
+DESCRIPTION:This is an event reminder
+SUMMARY:Alarm notification
+END:VALARM
+BEGIN:VALARM
+ACTION:DISPLAY
+TRIGGER:-P0DT0H15M0S
+DESCRIPTION:This is an event reminder
+END:VALARM
+END:VEVENT
+END:VCALENDAR
diff -pruN 6.0.1-3/src/icalendar/tests/calendars/alarm_google_future.ics 6.3.1-1/src/icalendar/tests/calendars/alarm_google_future.ics
--- 6.0.1-3/src/icalendar/tests/calendars/alarm_google_future.ics	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/calendars/alarm_google_future.ics	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,60 @@
+BEGIN:VCALENDAR
+PRODID:-//Google Inc//Google Calendar 70.9054//EN
+VERSION:2.0
+CALSCALE:GREGORIAN
+METHOD:PUBLISH
+X-WR-CALNAME:Nicco Kunzmann
+X-WR-TIMEZONE:Europe/London
+BEGIN:VTIMEZONE
+TZID:Europe/Berlin
+X-LIC-LOCATION:Europe/Berlin
+BEGIN:DAYLIGHT
+TZOFFSETFROM:+0100
+TZOFFSETTO:+0200
+TZNAME:GMT+2
+DTSTART:19700329T020000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETFROM:+0200
+TZOFFSETTO:+0100
+TZNAME:GMT+1
+DTSTART:19701025T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+DTSTART:20241004T181500Z
+DTEND:20241004T190000Z
+DTSTAMP:20241004T175945Z
+UID:79fs7pkqvht9m5igs0vjv1sfra@google.com
+CREATED:20241004T175920Z
+LAST-MODIFIED:20241004T175928Z
+SEQUENCE:0
+STATUS:CONFIRMED
+SUMMARY:event with alarms
+TRANSP:OPAQUE
+BEGIN:VALARM
+ACTION:DISPLAY
+TRIGGER:-P0DT0H10M0S
+DESCRIPTION:This is an event reminder
+END:VALARM
+BEGIN:VALARM
+ACTION:DISPLAY
+TRIGGER:-P0DT0H14M0S
+DESCRIPTION:This is an event reminder
+END:VALARM
+BEGIN:VALARM
+ACTION:EMAIL
+ATTENDEE:mailto:niccokunzmann@googlemail.com
+TRIGGER:-P0DT0H15M0S
+DESCRIPTION:This is an event reminder
+SUMMARY:Alarm notification
+END:VALARM
+BEGIN:VALARM
+ACTION:DISPLAY
+TRIGGER:-P0DT0H15M0S
+DESCRIPTION:This is an event reminder
+END:VALARM
+END:VEVENT
+END:VCALENDAR
diff -pruN 6.0.1-3/src/icalendar/tests/calendars/alarm_thunderbird_2_future.ics 6.3.1-1/src/icalendar/tests/calendars/alarm_thunderbird_2_future.ics
--- 6.0.1-3/src/icalendar/tests/calendars/alarm_thunderbird_2_future.ics	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/calendars/alarm_thunderbird_2_future.ics	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,624 @@
+BEGIN:VCALENDAR
+PRODID:-//Mozilla.org/NONSGML Mozilla Calendar V1.1//EN
+VERSION:2.0
+BEGIN:VTIMEZONE
+TZID:Europe/London
+X-TZINFO:Europe/London[2024a]
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:-000115
+TZNAME:Europe/London(STD)
+DTSTART:18471201T000000
+RDATE:18471201T000000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19160521T020000
+RDATE:19160521T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19161001T030000
+RDATE:19161001T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19170408T020000
+RDATE:19170408T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19170917T030000
+RDATE:19170917T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19180324T020000
+RDATE:19180324T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19180930T030000
+RRULE:FREQ=YEARLY;BYMONTH=9;BYDAY=-1MO;UNTIL=19190929T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19190330T020000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU;UNTIL=19200328T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19201025T030000
+RDATE:19201025T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19210403T020000
+RDATE:19210403T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19211003T030000
+RDATE:19211003T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19220326T020000
+RDATE:19220326T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19221008T030000
+RDATE:19221008T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19230422T020000
+RDATE:19230422T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19240413T020000
+RDATE:19240413T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19230916T030000
+RRULE:FREQ=YEARLY;BYMONTH=9;BYDAY=3SU;UNTIL=19240921T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19250419T020000
+RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=3SU;UNTIL=19260418T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19270410T020000
+RDATE:19270410T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19280422T020000
+RDATE:19280422T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19290421T020000
+RDATE:19290421T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19300413T020000
+RDATE:19300413T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19310419T020000
+RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=3SU;UNTIL=19320417T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19251004T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=1SU;UNTIL=19321002T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19330409T020000
+RDATE:19330409T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19331008T030000
+RDATE:19331008T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19340422T020000
+RDATE:19340422T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19350414T020000
+RDATE:19350414T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19360419T020000
+RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=3SU;UNTIL=19370418T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19380410T020000
+RDATE:19380410T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19341007T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=1SU;UNTIL=19381002T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19390416T020000
+RDATE:19390416T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19400225T020000
+RDATE:19400225T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+020000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(DST)
+DTSTART:19410504T020000
+RDATE:19410504T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+020000
+TZNAME:Europe/London(DST)
+DTSTART:19410810T030000
+RDATE:19410810T030000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+020000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(DST)
+DTSTART:19420405T020000
+RDATE:19420405T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+020000
+TZNAME:Europe/London(DST)
+DTSTART:19420809T030000
+RDATE:19420809T030000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+020000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(DST)
+DTSTART:19430404T020000
+RDATE:19430404T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+020000
+TZNAME:Europe/London(DST)
+DTSTART:19430815T030000
+RDATE:19430815T030000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+020000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(DST)
+DTSTART:19440402T020000
+RDATE:19440402T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+020000
+TZNAME:Europe/London(DST)
+DTSTART:19440917T030000
+RDATE:19440917T030000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+020000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(DST)
+DTSTART:19450402T020000
+RDATE:19450402T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19391119T030000
+RDATE:19391119T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+020000
+TZNAME:Europe/London(DST)
+DTSTART:19450715T030000
+RDATE:19450715T030000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19460414T020000
+RDATE:19460414T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19470316T020000
+RDATE:19470316T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+020000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(DST)
+DTSTART:19470413T020000
+RDATE:19470413T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19451007T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=1SU;UNTIL=19461006T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+020000
+TZNAME:Europe/London(DST)
+DTSTART:19470810T030000
+RDATE:19470810T030000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19471102T030000
+RDATE:19471102T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19480314T020000
+RDATE:19480314T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19490403T020000
+RDATE:19490403T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19481031T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU;UNTIL=19491030T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19501022T030000
+RDATE:19501022T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19511021T030000
+RDATE:19511021T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19521026T030000
+RDATE:19521026T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19500416T020000
+RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=3SU;UNTIL=19530419T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19540411T020000
+RDATE:19540411T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19550417T020000
+RDATE:19550417T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19560422T020000
+RDATE:19560422T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19570414T020000
+RDATE:19570414T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19580420T020000
+RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=3SU;UNTIL=19590419T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19600410T020000
+RDATE:19600410T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19531004T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=1SU;UNTIL=19601002T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19610326T020000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU;UNTIL=19630331T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19640322T020000
+RDATE:19640322T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19611029T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU;UNTIL=19641025T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19651024T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=4SU;UNTIL=19661023T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19650321T020000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=3SU;UNTIL=19670319T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19671029T030000
+RDATE:19671029T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+010000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19681027T000000
+RDATE:19681027T000000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19680218T020000
+RDATE:19680218T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19711031T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU;UNTIL=19751026T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19761024T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=4SU;UNTIL=19771023T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19720319T020000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=3SU;UNTIL=19800316T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19781029T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU;UNTIL=19801026T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19811025T020000
+RDATE:19811025T020000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19821024T020000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=4SU;UNTIL=19831023T020000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19841028T020000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU;UNTIL=19871025T020000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19881023T020000
+RDATE:19881023T020000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19891029T020000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU;UNTIL=19921025T020000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19931024T020000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=4SU;UNTIL=19951022T020000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19810329T010000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU;UNTIL=19960331T010000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19961027T020000
+RDATE:19961027T020000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:(DST)
+DTSTART:19970330T010000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:(STD)
+DTSTART:19971026T020000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+CREATED:20241023T173412Z
+LAST-MODIFIED:20241023T173453Z
+DTSTAMP:20241023T173453Z
+UID:731b9b91-cf72-499b-bbc9-c53c28e21fc7
+SUMMARY:event
+DTSTART;TZID=Europe/London:20241023T190000
+DTEND;TZID=Europe/London:20241023T200000
+TRANSP:OPAQUE
+X-MOZ-GENERATION:2
+BEGIN:VALARM
+ACTION:DISPLAY
+TRIGGER:-PT1M
+DESCRIPTION:Mozilla Standardbeschreibung
+END:VALARM
+BEGIN:VALARM
+ACTION:DISPLAY
+TRIGGER:-PT24M
+DESCRIPTION:Mozilla Standardbeschreibung
+END:VALARM
+END:VEVENT
+END:VCALENDAR
diff -pruN 6.0.1-3/src/icalendar/tests/calendars/alarm_thunderbird_2_notification_5_min_postponed.ics 6.3.1-1/src/icalendar/tests/calendars/alarm_thunderbird_2_notification_5_min_postponed.ics
--- 6.0.1-3/src/icalendar/tests/calendars/alarm_thunderbird_2_notification_5_min_postponed.ics	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/calendars/alarm_thunderbird_2_notification_5_min_postponed.ics	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,626 @@
+BEGIN:VCALENDAR
+PRODID:-//Mozilla.org/NONSGML Mozilla Calendar V1.1//EN
+VERSION:2.0
+BEGIN:VTIMEZONE
+TZID:Europe/London
+X-TZINFO:Europe/London[2024a]
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:-000115
+TZNAME:Europe/London(STD)
+DTSTART:18471201T000000
+RDATE:18471201T000000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19160521T020000
+RDATE:19160521T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19161001T030000
+RDATE:19161001T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19170408T020000
+RDATE:19170408T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19170917T030000
+RDATE:19170917T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19180324T020000
+RDATE:19180324T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19180930T030000
+RRULE:FREQ=YEARLY;BYMONTH=9;BYDAY=-1MO;UNTIL=19190929T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19190330T020000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU;UNTIL=19200328T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19201025T030000
+RDATE:19201025T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19210403T020000
+RDATE:19210403T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19211003T030000
+RDATE:19211003T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19220326T020000
+RDATE:19220326T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19221008T030000
+RDATE:19221008T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19230422T020000
+RDATE:19230422T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19240413T020000
+RDATE:19240413T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19230916T030000
+RRULE:FREQ=YEARLY;BYMONTH=9;BYDAY=3SU;UNTIL=19240921T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19250419T020000
+RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=3SU;UNTIL=19260418T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19270410T020000
+RDATE:19270410T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19280422T020000
+RDATE:19280422T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19290421T020000
+RDATE:19290421T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19300413T020000
+RDATE:19300413T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19310419T020000
+RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=3SU;UNTIL=19320417T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19251004T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=1SU;UNTIL=19321002T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19330409T020000
+RDATE:19330409T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19331008T030000
+RDATE:19331008T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19340422T020000
+RDATE:19340422T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19350414T020000
+RDATE:19350414T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19360419T020000
+RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=3SU;UNTIL=19370418T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19380410T020000
+RDATE:19380410T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19341007T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=1SU;UNTIL=19381002T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19390416T020000
+RDATE:19390416T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19400225T020000
+RDATE:19400225T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+020000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(DST)
+DTSTART:19410504T020000
+RDATE:19410504T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+020000
+TZNAME:Europe/London(DST)
+DTSTART:19410810T030000
+RDATE:19410810T030000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+020000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(DST)
+DTSTART:19420405T020000
+RDATE:19420405T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+020000
+TZNAME:Europe/London(DST)
+DTSTART:19420809T030000
+RDATE:19420809T030000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+020000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(DST)
+DTSTART:19430404T020000
+RDATE:19430404T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+020000
+TZNAME:Europe/London(DST)
+DTSTART:19430815T030000
+RDATE:19430815T030000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+020000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(DST)
+DTSTART:19440402T020000
+RDATE:19440402T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+020000
+TZNAME:Europe/London(DST)
+DTSTART:19440917T030000
+RDATE:19440917T030000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+020000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(DST)
+DTSTART:19450402T020000
+RDATE:19450402T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19391119T030000
+RDATE:19391119T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+020000
+TZNAME:Europe/London(DST)
+DTSTART:19450715T030000
+RDATE:19450715T030000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19460414T020000
+RDATE:19460414T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19470316T020000
+RDATE:19470316T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+020000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(DST)
+DTSTART:19470413T020000
+RDATE:19470413T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19451007T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=1SU;UNTIL=19461006T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+020000
+TZNAME:Europe/London(DST)
+DTSTART:19470810T030000
+RDATE:19470810T030000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19471102T030000
+RDATE:19471102T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19480314T020000
+RDATE:19480314T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19490403T020000
+RDATE:19490403T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19481031T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU;UNTIL=19491030T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19501022T030000
+RDATE:19501022T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19511021T030000
+RDATE:19511021T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19521026T030000
+RDATE:19521026T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19500416T020000
+RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=3SU;UNTIL=19530419T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19540411T020000
+RDATE:19540411T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19550417T020000
+RDATE:19550417T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19560422T020000
+RDATE:19560422T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19570414T020000
+RDATE:19570414T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19580420T020000
+RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=3SU;UNTIL=19590419T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19600410T020000
+RDATE:19600410T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19531004T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=1SU;UNTIL=19601002T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19610326T020000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU;UNTIL=19630331T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19640322T020000
+RDATE:19640322T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19611029T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU;UNTIL=19641025T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19651024T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=4SU;UNTIL=19661023T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19650321T020000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=3SU;UNTIL=19670319T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19671029T030000
+RDATE:19671029T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+010000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19681027T000000
+RDATE:19681027T000000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19680218T020000
+RDATE:19680218T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19711031T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU;UNTIL=19751026T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19761024T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=4SU;UNTIL=19771023T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19720319T020000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=3SU;UNTIL=19800316T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19781029T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU;UNTIL=19801026T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19811025T020000
+RDATE:19811025T020000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19821024T020000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=4SU;UNTIL=19831023T020000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19841028T020000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU;UNTIL=19871025T020000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19881023T020000
+RDATE:19881023T020000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19891029T020000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU;UNTIL=19921025T020000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19931024T020000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=4SU;UNTIL=19951022T020000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19810329T010000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU;UNTIL=19960331T010000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19961027T020000
+RDATE:19961027T020000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:(DST)
+DTSTART:19970330T010000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:(STD)
+DTSTART:19971026T020000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+CREATED:20241023T173412Z
+LAST-MODIFIED:20241023T173630Z
+DTSTAMP:20241023T173630Z
+UID:731b9b91-cf72-499b-bbc9-c53c28e21fc7
+SUMMARY:event
+X-MOZ-LASTACK:20241023T173630Z
+DTSTART;TZID=Europe/London:20241023T190000
+DTEND;TZID=Europe/London:20241023T200000
+TRANSP:OPAQUE
+X-MOZ-GENERATION:3
+X-MOZ-SNOOZE-TIME:20241023T174130Z
+BEGIN:VALARM
+ACTION:DISPLAY
+TRIGGER:-PT1M
+DESCRIPTION:Mozilla Standardbeschreibung
+END:VALARM
+BEGIN:VALARM
+ACTION:DISPLAY
+TRIGGER:-PT24M
+DESCRIPTION:Mozilla Standardbeschreibung
+END:VALARM
+END:VEVENT
+END:VCALENDAR
diff -pruN 6.0.1-3/src/icalendar/tests/calendars/alarm_thunderbird_2_notification_5_min_postponed_and_closed.ics 6.3.1-1/src/icalendar/tests/calendars/alarm_thunderbird_2_notification_5_min_postponed_and_closed.ics
--- 6.0.1-3/src/icalendar/tests/calendars/alarm_thunderbird_2_notification_5_min_postponed_and_closed.ics	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/calendars/alarm_thunderbird_2_notification_5_min_postponed_and_closed.ics	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,625 @@
+BEGIN:VCALENDAR
+PRODID:-//Mozilla.org/NONSGML Mozilla Calendar V1.1//EN
+VERSION:2.0
+BEGIN:VTIMEZONE
+TZID:Europe/London
+X-TZINFO:Europe/London[2024a]
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:-000115
+TZNAME:Europe/London(STD)
+DTSTART:18471201T000000
+RDATE:18471201T000000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19160521T020000
+RDATE:19160521T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19161001T030000
+RDATE:19161001T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19170408T020000
+RDATE:19170408T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19170917T030000
+RDATE:19170917T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19180324T020000
+RDATE:19180324T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19180930T030000
+RRULE:FREQ=YEARLY;BYMONTH=9;BYDAY=-1MO;UNTIL=19190929T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19190330T020000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU;UNTIL=19200328T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19201025T030000
+RDATE:19201025T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19210403T020000
+RDATE:19210403T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19211003T030000
+RDATE:19211003T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19220326T020000
+RDATE:19220326T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19221008T030000
+RDATE:19221008T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19230422T020000
+RDATE:19230422T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19240413T020000
+RDATE:19240413T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19230916T030000
+RRULE:FREQ=YEARLY;BYMONTH=9;BYDAY=3SU;UNTIL=19240921T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19250419T020000
+RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=3SU;UNTIL=19260418T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19270410T020000
+RDATE:19270410T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19280422T020000
+RDATE:19280422T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19290421T020000
+RDATE:19290421T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19300413T020000
+RDATE:19300413T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19310419T020000
+RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=3SU;UNTIL=19320417T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19251004T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=1SU;UNTIL=19321002T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19330409T020000
+RDATE:19330409T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19331008T030000
+RDATE:19331008T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19340422T020000
+RDATE:19340422T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19350414T020000
+RDATE:19350414T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19360419T020000
+RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=3SU;UNTIL=19370418T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19380410T020000
+RDATE:19380410T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19341007T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=1SU;UNTIL=19381002T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19390416T020000
+RDATE:19390416T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19400225T020000
+RDATE:19400225T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+020000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(DST)
+DTSTART:19410504T020000
+RDATE:19410504T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+020000
+TZNAME:Europe/London(DST)
+DTSTART:19410810T030000
+RDATE:19410810T030000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+020000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(DST)
+DTSTART:19420405T020000
+RDATE:19420405T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+020000
+TZNAME:Europe/London(DST)
+DTSTART:19420809T030000
+RDATE:19420809T030000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+020000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(DST)
+DTSTART:19430404T020000
+RDATE:19430404T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+020000
+TZNAME:Europe/London(DST)
+DTSTART:19430815T030000
+RDATE:19430815T030000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+020000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(DST)
+DTSTART:19440402T020000
+RDATE:19440402T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+020000
+TZNAME:Europe/London(DST)
+DTSTART:19440917T030000
+RDATE:19440917T030000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+020000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(DST)
+DTSTART:19450402T020000
+RDATE:19450402T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19391119T030000
+RDATE:19391119T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+020000
+TZNAME:Europe/London(DST)
+DTSTART:19450715T030000
+RDATE:19450715T030000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19460414T020000
+RDATE:19460414T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19470316T020000
+RDATE:19470316T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+020000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(DST)
+DTSTART:19470413T020000
+RDATE:19470413T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19451007T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=1SU;UNTIL=19461006T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+020000
+TZNAME:Europe/London(DST)
+DTSTART:19470810T030000
+RDATE:19470810T030000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19471102T030000
+RDATE:19471102T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19480314T020000
+RDATE:19480314T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19490403T020000
+RDATE:19490403T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19481031T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU;UNTIL=19491030T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19501022T030000
+RDATE:19501022T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19511021T030000
+RDATE:19511021T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19521026T030000
+RDATE:19521026T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19500416T020000
+RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=3SU;UNTIL=19530419T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19540411T020000
+RDATE:19540411T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19550417T020000
+RDATE:19550417T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19560422T020000
+RDATE:19560422T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19570414T020000
+RDATE:19570414T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19580420T020000
+RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=3SU;UNTIL=19590419T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19600410T020000
+RDATE:19600410T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19531004T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=1SU;UNTIL=19601002T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19610326T020000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU;UNTIL=19630331T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19640322T020000
+RDATE:19640322T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19611029T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU;UNTIL=19641025T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19651024T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=4SU;UNTIL=19661023T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19650321T020000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=3SU;UNTIL=19670319T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19671029T030000
+RDATE:19671029T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+010000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19681027T000000
+RDATE:19681027T000000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19680218T020000
+RDATE:19680218T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19711031T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU;UNTIL=19751026T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19761024T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=4SU;UNTIL=19771023T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19720319T020000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=3SU;UNTIL=19800316T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19781029T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU;UNTIL=19801026T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19811025T020000
+RDATE:19811025T020000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19821024T020000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=4SU;UNTIL=19831023T020000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19841028T020000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU;UNTIL=19871025T020000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19881023T020000
+RDATE:19881023T020000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19891029T020000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU;UNTIL=19921025T020000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19931024T020000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=4SU;UNTIL=19951022T020000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19810329T010000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU;UNTIL=19960331T010000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19961027T020000
+RDATE:19961027T020000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:(DST)
+DTSTART:19970330T010000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:(STD)
+DTSTART:19971026T020000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+CREATED:20241023T173412Z
+LAST-MODIFIED:20241023T174207Z
+DTSTAMP:20241023T174207Z
+UID:731b9b91-cf72-499b-bbc9-c53c28e21fc7
+SUMMARY:event
+X-MOZ-LASTACK:20241023T174207Z
+DTSTART;TZID=Europe/London:20241023T190000
+DTEND;TZID=Europe/London:20241023T200000
+TRANSP:OPAQUE
+X-MOZ-GENERATION:4
+BEGIN:VALARM
+ACTION:DISPLAY
+TRIGGER:-PT1M
+DESCRIPTION:Mozilla Standardbeschreibung
+END:VALARM
+BEGIN:VALARM
+ACTION:DISPLAY
+TRIGGER:-PT24M
+DESCRIPTION:Mozilla Standardbeschreibung
+END:VALARM
+END:VEVENT
+END:VCALENDAR
diff -pruN 6.0.1-3/src/icalendar/tests/calendars/alarm_thunderbird_2_notification_5_min_postponed_and_popped_up.ics 6.3.1-1/src/icalendar/tests/calendars/alarm_thunderbird_2_notification_5_min_postponed_and_popped_up.ics
--- 6.0.1-3/src/icalendar/tests/calendars/alarm_thunderbird_2_notification_5_min_postponed_and_popped_up.ics	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/calendars/alarm_thunderbird_2_notification_5_min_postponed_and_popped_up.ics	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,626 @@
+BEGIN:VCALENDAR
+PRODID:-//Mozilla.org/NONSGML Mozilla Calendar V1.1//EN
+VERSION:2.0
+BEGIN:VTIMEZONE
+TZID:Europe/London
+X-TZINFO:Europe/London[2024a]
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:-000115
+TZNAME:Europe/London(STD)
+DTSTART:18471201T000000
+RDATE:18471201T000000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19160521T020000
+RDATE:19160521T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19161001T030000
+RDATE:19161001T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19170408T020000
+RDATE:19170408T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19170917T030000
+RDATE:19170917T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19180324T020000
+RDATE:19180324T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19180930T030000
+RRULE:FREQ=YEARLY;BYMONTH=9;BYDAY=-1MO;UNTIL=19190929T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19190330T020000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU;UNTIL=19200328T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19201025T030000
+RDATE:19201025T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19210403T020000
+RDATE:19210403T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19211003T030000
+RDATE:19211003T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19220326T020000
+RDATE:19220326T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19221008T030000
+RDATE:19221008T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19230422T020000
+RDATE:19230422T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19240413T020000
+RDATE:19240413T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19230916T030000
+RRULE:FREQ=YEARLY;BYMONTH=9;BYDAY=3SU;UNTIL=19240921T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19250419T020000
+RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=3SU;UNTIL=19260418T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19270410T020000
+RDATE:19270410T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19280422T020000
+RDATE:19280422T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19290421T020000
+RDATE:19290421T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19300413T020000
+RDATE:19300413T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19310419T020000
+RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=3SU;UNTIL=19320417T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19251004T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=1SU;UNTIL=19321002T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19330409T020000
+RDATE:19330409T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19331008T030000
+RDATE:19331008T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19340422T020000
+RDATE:19340422T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19350414T020000
+RDATE:19350414T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19360419T020000
+RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=3SU;UNTIL=19370418T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19380410T020000
+RDATE:19380410T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19341007T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=1SU;UNTIL=19381002T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19390416T020000
+RDATE:19390416T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19400225T020000
+RDATE:19400225T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+020000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(DST)
+DTSTART:19410504T020000
+RDATE:19410504T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+020000
+TZNAME:Europe/London(DST)
+DTSTART:19410810T030000
+RDATE:19410810T030000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+020000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(DST)
+DTSTART:19420405T020000
+RDATE:19420405T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+020000
+TZNAME:Europe/London(DST)
+DTSTART:19420809T030000
+RDATE:19420809T030000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+020000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(DST)
+DTSTART:19430404T020000
+RDATE:19430404T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+020000
+TZNAME:Europe/London(DST)
+DTSTART:19430815T030000
+RDATE:19430815T030000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+020000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(DST)
+DTSTART:19440402T020000
+RDATE:19440402T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+020000
+TZNAME:Europe/London(DST)
+DTSTART:19440917T030000
+RDATE:19440917T030000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+020000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(DST)
+DTSTART:19450402T020000
+RDATE:19450402T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19391119T030000
+RDATE:19391119T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+020000
+TZNAME:Europe/London(DST)
+DTSTART:19450715T030000
+RDATE:19450715T030000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19460414T020000
+RDATE:19460414T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19470316T020000
+RDATE:19470316T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+020000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(DST)
+DTSTART:19470413T020000
+RDATE:19470413T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19451007T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=1SU;UNTIL=19461006T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+020000
+TZNAME:Europe/London(DST)
+DTSTART:19470810T030000
+RDATE:19470810T030000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19471102T030000
+RDATE:19471102T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19480314T020000
+RDATE:19480314T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19490403T020000
+RDATE:19490403T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19481031T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU;UNTIL=19491030T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19501022T030000
+RDATE:19501022T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19511021T030000
+RDATE:19511021T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19521026T030000
+RDATE:19521026T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19500416T020000
+RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=3SU;UNTIL=19530419T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19540411T020000
+RDATE:19540411T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19550417T020000
+RDATE:19550417T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19560422T020000
+RDATE:19560422T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19570414T020000
+RDATE:19570414T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19580420T020000
+RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=3SU;UNTIL=19590419T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19600410T020000
+RDATE:19600410T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19531004T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=1SU;UNTIL=19601002T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19610326T020000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU;UNTIL=19630331T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19640322T020000
+RDATE:19640322T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19611029T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU;UNTIL=19641025T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19651024T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=4SU;UNTIL=19661023T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19650321T020000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=3SU;UNTIL=19670319T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19671029T030000
+RDATE:19671029T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+010000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19681027T000000
+RDATE:19681027T000000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19680218T020000
+RDATE:19680218T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19711031T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU;UNTIL=19751026T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19761024T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=4SU;UNTIL=19771023T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19720319T020000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=3SU;UNTIL=19800316T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19781029T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU;UNTIL=19801026T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19811025T020000
+RDATE:19811025T020000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19821024T020000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=4SU;UNTIL=19831023T020000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19841028T020000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU;UNTIL=19871025T020000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19881023T020000
+RDATE:19881023T020000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19891029T020000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU;UNTIL=19921025T020000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19931024T020000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=4SU;UNTIL=19951022T020000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19810329T010000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU;UNTIL=19960331T010000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19961027T020000
+RDATE:19961027T020000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:(DST)
+DTSTART:19970330T010000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:(STD)
+DTSTART:19971026T020000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+CREATED:20241023T173412Z
+LAST-MODIFIED:20241023T173630Z
+DTSTAMP:20241023T173630Z
+UID:731b9b91-cf72-499b-bbc9-c53c28e21fc7
+SUMMARY:event
+X-MOZ-LASTACK:20241023T173630Z
+DTSTART;TZID=Europe/London:20241023T190000
+DTEND;TZID=Europe/London:20241023T200000
+TRANSP:OPAQUE
+X-MOZ-GENERATION:3
+X-MOZ-SNOOZE-TIME:20241023T174130Z
+BEGIN:VALARM
+ACTION:DISPLAY
+TRIGGER:-PT1M
+DESCRIPTION:Mozilla Standardbeschreibung
+END:VALARM
+BEGIN:VALARM
+ACTION:DISPLAY
+TRIGGER:-PT24M
+DESCRIPTION:Mozilla Standardbeschreibung
+END:VALARM
+END:VEVENT
+END:VCALENDAR
diff -pruN 6.0.1-3/src/icalendar/tests/calendars/alarm_thunderbird_2_notification_popped_up.ics 6.3.1-1/src/icalendar/tests/calendars/alarm_thunderbird_2_notification_popped_up.ics
--- 6.0.1-3/src/icalendar/tests/calendars/alarm_thunderbird_2_notification_popped_up.ics	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/calendars/alarm_thunderbird_2_notification_popped_up.ics	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,624 @@
+BEGIN:VCALENDAR
+PRODID:-//Mozilla.org/NONSGML Mozilla Calendar V1.1//EN
+VERSION:2.0
+BEGIN:VTIMEZONE
+TZID:Europe/London
+X-TZINFO:Europe/London[2024a]
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:-000115
+TZNAME:Europe/London(STD)
+DTSTART:18471201T000000
+RDATE:18471201T000000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19160521T020000
+RDATE:19160521T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19161001T030000
+RDATE:19161001T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19170408T020000
+RDATE:19170408T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19170917T030000
+RDATE:19170917T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19180324T020000
+RDATE:19180324T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19180930T030000
+RRULE:FREQ=YEARLY;BYMONTH=9;BYDAY=-1MO;UNTIL=19190929T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19190330T020000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU;UNTIL=19200328T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19201025T030000
+RDATE:19201025T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19210403T020000
+RDATE:19210403T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19211003T030000
+RDATE:19211003T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19220326T020000
+RDATE:19220326T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19221008T030000
+RDATE:19221008T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19230422T020000
+RDATE:19230422T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19240413T020000
+RDATE:19240413T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19230916T030000
+RRULE:FREQ=YEARLY;BYMONTH=9;BYDAY=3SU;UNTIL=19240921T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19250419T020000
+RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=3SU;UNTIL=19260418T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19270410T020000
+RDATE:19270410T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19280422T020000
+RDATE:19280422T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19290421T020000
+RDATE:19290421T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19300413T020000
+RDATE:19300413T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19310419T020000
+RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=3SU;UNTIL=19320417T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19251004T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=1SU;UNTIL=19321002T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19330409T020000
+RDATE:19330409T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19331008T030000
+RDATE:19331008T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19340422T020000
+RDATE:19340422T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19350414T020000
+RDATE:19350414T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19360419T020000
+RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=3SU;UNTIL=19370418T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19380410T020000
+RDATE:19380410T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19341007T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=1SU;UNTIL=19381002T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19390416T020000
+RDATE:19390416T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19400225T020000
+RDATE:19400225T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+020000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(DST)
+DTSTART:19410504T020000
+RDATE:19410504T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+020000
+TZNAME:Europe/London(DST)
+DTSTART:19410810T030000
+RDATE:19410810T030000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+020000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(DST)
+DTSTART:19420405T020000
+RDATE:19420405T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+020000
+TZNAME:Europe/London(DST)
+DTSTART:19420809T030000
+RDATE:19420809T030000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+020000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(DST)
+DTSTART:19430404T020000
+RDATE:19430404T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+020000
+TZNAME:Europe/London(DST)
+DTSTART:19430815T030000
+RDATE:19430815T030000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+020000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(DST)
+DTSTART:19440402T020000
+RDATE:19440402T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+020000
+TZNAME:Europe/London(DST)
+DTSTART:19440917T030000
+RDATE:19440917T030000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+020000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(DST)
+DTSTART:19450402T020000
+RDATE:19450402T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19391119T030000
+RDATE:19391119T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+020000
+TZNAME:Europe/London(DST)
+DTSTART:19450715T030000
+RDATE:19450715T030000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19460414T020000
+RDATE:19460414T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19470316T020000
+RDATE:19470316T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+020000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(DST)
+DTSTART:19470413T020000
+RDATE:19470413T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19451007T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=1SU;UNTIL=19461006T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+020000
+TZNAME:Europe/London(DST)
+DTSTART:19470810T030000
+RDATE:19470810T030000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19471102T030000
+RDATE:19471102T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19480314T020000
+RDATE:19480314T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19490403T020000
+RDATE:19490403T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19481031T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU;UNTIL=19491030T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19501022T030000
+RDATE:19501022T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19511021T030000
+RDATE:19511021T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19521026T030000
+RDATE:19521026T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19500416T020000
+RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=3SU;UNTIL=19530419T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19540411T020000
+RDATE:19540411T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19550417T020000
+RDATE:19550417T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19560422T020000
+RDATE:19560422T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19570414T020000
+RDATE:19570414T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19580420T020000
+RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=3SU;UNTIL=19590419T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19600410T020000
+RDATE:19600410T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19531004T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=1SU;UNTIL=19601002T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19610326T020000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU;UNTIL=19630331T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19640322T020000
+RDATE:19640322T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19611029T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU;UNTIL=19641025T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19651024T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=4SU;UNTIL=19661023T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19650321T020000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=3SU;UNTIL=19670319T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19671029T030000
+RDATE:19671029T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+010000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19681027T000000
+RDATE:19681027T000000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19680218T020000
+RDATE:19680218T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19711031T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU;UNTIL=19751026T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19761024T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=4SU;UNTIL=19771023T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19720319T020000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=3SU;UNTIL=19800316T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19781029T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU;UNTIL=19801026T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19811025T020000
+RDATE:19811025T020000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19821024T020000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=4SU;UNTIL=19831023T020000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19841028T020000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU;UNTIL=19871025T020000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19881023T020000
+RDATE:19881023T020000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19891029T020000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU;UNTIL=19921025T020000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19931024T020000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=4SU;UNTIL=19951022T020000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19810329T010000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU;UNTIL=19960331T010000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19961027T020000
+RDATE:19961027T020000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:(DST)
+DTSTART:19970330T010000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:(STD)
+DTSTART:19971026T020000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+CREATED:20241023T173412Z
+LAST-MODIFIED:20241023T173453Z
+DTSTAMP:20241023T173453Z
+UID:731b9b91-cf72-499b-bbc9-c53c28e21fc7
+SUMMARY:event
+DTSTART;TZID=Europe/London:20241023T190000
+DTEND;TZID=Europe/London:20241023T200000
+TRANSP:OPAQUE
+X-MOZ-GENERATION:2
+BEGIN:VALARM
+ACTION:DISPLAY
+TRIGGER:-PT1M
+DESCRIPTION:Mozilla Standardbeschreibung
+END:VALARM
+BEGIN:VALARM
+ACTION:DISPLAY
+TRIGGER:-PT24M
+DESCRIPTION:Mozilla Standardbeschreibung
+END:VALARM
+END:VEVENT
+END:VCALENDAR
diff -pruN 6.0.1-3/src/icalendar/tests/calendars/alarm_thunderbird_closed.ics 6.3.1-1/src/icalendar/tests/calendars/alarm_thunderbird_closed.ics
--- 6.0.1-3/src/icalendar/tests/calendars/alarm_thunderbird_closed.ics	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/calendars/alarm_thunderbird_closed.ics	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,625 @@
+BEGIN:VCALENDAR
+PRODID:-//Mozilla.org/NONSGML Mozilla Calendar V1.1//EN
+VERSION:2.0
+BEGIN:VTIMEZONE
+TZID:Europe/London
+X-TZINFO:Europe/London[2024a]
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:-000115
+TZNAME:Europe/London(STD)
+DTSTART:18471201T000000
+RDATE:18471201T000000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19160521T020000
+RDATE:19160521T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19161001T030000
+RDATE:19161001T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19170408T020000
+RDATE:19170408T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19170917T030000
+RDATE:19170917T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19180324T020000
+RDATE:19180324T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19180930T030000
+RRULE:FREQ=YEARLY;BYMONTH=9;BYDAY=-1MO;UNTIL=19190929T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19190330T020000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU;UNTIL=19200328T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19201025T030000
+RDATE:19201025T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19210403T020000
+RDATE:19210403T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19211003T030000
+RDATE:19211003T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19220326T020000
+RDATE:19220326T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19221008T030000
+RDATE:19221008T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19230422T020000
+RDATE:19230422T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19240413T020000
+RDATE:19240413T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19230916T030000
+RRULE:FREQ=YEARLY;BYMONTH=9;BYDAY=3SU;UNTIL=19240921T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19250419T020000
+RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=3SU;UNTIL=19260418T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19270410T020000
+RDATE:19270410T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19280422T020000
+RDATE:19280422T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19290421T020000
+RDATE:19290421T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19300413T020000
+RDATE:19300413T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19310419T020000
+RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=3SU;UNTIL=19320417T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19251004T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=1SU;UNTIL=19321002T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19330409T020000
+RDATE:19330409T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19331008T030000
+RDATE:19331008T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19340422T020000
+RDATE:19340422T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19350414T020000
+RDATE:19350414T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19360419T020000
+RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=3SU;UNTIL=19370418T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19380410T020000
+RDATE:19380410T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19341007T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=1SU;UNTIL=19381002T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19390416T020000
+RDATE:19390416T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19400225T020000
+RDATE:19400225T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+020000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(DST)
+DTSTART:19410504T020000
+RDATE:19410504T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+020000
+TZNAME:Europe/London(DST)
+DTSTART:19410810T030000
+RDATE:19410810T030000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+020000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(DST)
+DTSTART:19420405T020000
+RDATE:19420405T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+020000
+TZNAME:Europe/London(DST)
+DTSTART:19420809T030000
+RDATE:19420809T030000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+020000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(DST)
+DTSTART:19430404T020000
+RDATE:19430404T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+020000
+TZNAME:Europe/London(DST)
+DTSTART:19430815T030000
+RDATE:19430815T030000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+020000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(DST)
+DTSTART:19440402T020000
+RDATE:19440402T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+020000
+TZNAME:Europe/London(DST)
+DTSTART:19440917T030000
+RDATE:19440917T030000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+020000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(DST)
+DTSTART:19450402T020000
+RDATE:19450402T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19391119T030000
+RDATE:19391119T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+020000
+TZNAME:Europe/London(DST)
+DTSTART:19450715T030000
+RDATE:19450715T030000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19460414T020000
+RDATE:19460414T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19470316T020000
+RDATE:19470316T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+020000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(DST)
+DTSTART:19470413T020000
+RDATE:19470413T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19451007T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=1SU;UNTIL=19461006T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+020000
+TZNAME:Europe/London(DST)
+DTSTART:19470810T030000
+RDATE:19470810T030000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19471102T030000
+RDATE:19471102T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19480314T020000
+RDATE:19480314T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19490403T020000
+RDATE:19490403T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19481031T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU;UNTIL=19491030T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19501022T030000
+RDATE:19501022T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19511021T030000
+RDATE:19511021T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19521026T030000
+RDATE:19521026T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19500416T020000
+RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=3SU;UNTIL=19530419T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19540411T020000
+RDATE:19540411T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19550417T020000
+RDATE:19550417T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19560422T020000
+RDATE:19560422T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19570414T020000
+RDATE:19570414T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19580420T020000
+RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=3SU;UNTIL=19590419T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19600410T020000
+RDATE:19600410T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19531004T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=1SU;UNTIL=19601002T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19610326T020000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU;UNTIL=19630331T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19640322T020000
+RDATE:19640322T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19611029T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU;UNTIL=19641025T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19651024T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=4SU;UNTIL=19661023T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19650321T020000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=3SU;UNTIL=19670319T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19671029T030000
+RDATE:19671029T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+010000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19681027T000000
+RDATE:19681027T000000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19680218T020000
+RDATE:19680218T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19711031T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU;UNTIL=19751026T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19761024T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=4SU;UNTIL=19771023T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19720319T020000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=3SU;UNTIL=19800316T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19781029T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU;UNTIL=19801026T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19811025T020000
+RDATE:19811025T020000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19821024T020000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=4SU;UNTIL=19831023T020000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19841028T020000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU;UNTIL=19871025T020000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19881023T020000
+RDATE:19881023T020000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19891029T020000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU;UNTIL=19921025T020000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19931024T020000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=4SU;UNTIL=19951022T020000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19810329T010000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU;UNTIL=19960331T010000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19961027T020000
+RDATE:19961027T020000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:(DST)
+DTSTART:19970330T010000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:(STD)
+DTSTART:19971026T020000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+CREATED:20241023T131035Z
+LAST-MODIFIED:20241023T141941Z
+DTSTAMP:20241023T141941Z
+UID:b9a23b47-f109-4e7a-908c-75e925b27def
+SUMMARY:event with alarms
+X-MOZ-LASTACK:20241023T141941Z
+DTSTART;TZID=Europe/London:20241023T150000
+DTEND;TZID=Europe/London:20241023T160000
+TRANSP:OPAQUE
+X-MOZ-GENERATION:6
+BEGIN:VALARM
+ACTION:DISPLAY
+TRIGGER:-PT15M
+DESCRIPTION:Mozilla Standardbeschreibung
+END:VALARM
+BEGIN:VALARM
+ACTION:DISPLAY
+TRIGGER:-PT45M
+DESCRIPTION:Mozilla Standardbeschreibung
+END:VALARM
+END:VEVENT
+END:VCALENDAR
diff -pruN 6.0.1-3/src/icalendar/tests/calendars/alarm_thunderbird_future.ics 6.3.1-1/src/icalendar/tests/calendars/alarm_thunderbird_future.ics
--- 6.0.1-3/src/icalendar/tests/calendars/alarm_thunderbird_future.ics	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/calendars/alarm_thunderbird_future.ics	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,624 @@
+BEGIN:VCALENDAR
+PRODID:-//Mozilla.org/NONSGML Mozilla Calendar V1.1//EN
+VERSION:2.0
+BEGIN:VTIMEZONE
+TZID:Europe/London
+X-TZINFO:Europe/London[2024a]
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:-000115
+TZNAME:Europe/London(STD)
+DTSTART:18471201T000000
+RDATE:18471201T000000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19160521T020000
+RDATE:19160521T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19161001T030000
+RDATE:19161001T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19170408T020000
+RDATE:19170408T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19170917T030000
+RDATE:19170917T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19180324T020000
+RDATE:19180324T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19180930T030000
+RRULE:FREQ=YEARLY;BYMONTH=9;BYDAY=-1MO;UNTIL=19190929T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19190330T020000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU;UNTIL=19200328T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19201025T030000
+RDATE:19201025T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19210403T020000
+RDATE:19210403T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19211003T030000
+RDATE:19211003T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19220326T020000
+RDATE:19220326T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19221008T030000
+RDATE:19221008T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19230422T020000
+RDATE:19230422T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19240413T020000
+RDATE:19240413T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19230916T030000
+RRULE:FREQ=YEARLY;BYMONTH=9;BYDAY=3SU;UNTIL=19240921T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19250419T020000
+RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=3SU;UNTIL=19260418T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19270410T020000
+RDATE:19270410T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19280422T020000
+RDATE:19280422T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19290421T020000
+RDATE:19290421T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19300413T020000
+RDATE:19300413T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19310419T020000
+RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=3SU;UNTIL=19320417T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19251004T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=1SU;UNTIL=19321002T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19330409T020000
+RDATE:19330409T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19331008T030000
+RDATE:19331008T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19340422T020000
+RDATE:19340422T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19350414T020000
+RDATE:19350414T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19360419T020000
+RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=3SU;UNTIL=19370418T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19380410T020000
+RDATE:19380410T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19341007T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=1SU;UNTIL=19381002T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19390416T020000
+RDATE:19390416T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19400225T020000
+RDATE:19400225T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+020000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(DST)
+DTSTART:19410504T020000
+RDATE:19410504T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+020000
+TZNAME:Europe/London(DST)
+DTSTART:19410810T030000
+RDATE:19410810T030000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+020000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(DST)
+DTSTART:19420405T020000
+RDATE:19420405T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+020000
+TZNAME:Europe/London(DST)
+DTSTART:19420809T030000
+RDATE:19420809T030000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+020000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(DST)
+DTSTART:19430404T020000
+RDATE:19430404T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+020000
+TZNAME:Europe/London(DST)
+DTSTART:19430815T030000
+RDATE:19430815T030000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+020000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(DST)
+DTSTART:19440402T020000
+RDATE:19440402T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+020000
+TZNAME:Europe/London(DST)
+DTSTART:19440917T030000
+RDATE:19440917T030000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+020000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(DST)
+DTSTART:19450402T020000
+RDATE:19450402T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19391119T030000
+RDATE:19391119T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+020000
+TZNAME:Europe/London(DST)
+DTSTART:19450715T030000
+RDATE:19450715T030000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19460414T020000
+RDATE:19460414T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19470316T020000
+RDATE:19470316T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+020000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(DST)
+DTSTART:19470413T020000
+RDATE:19470413T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19451007T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=1SU;UNTIL=19461006T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+020000
+TZNAME:Europe/London(DST)
+DTSTART:19470810T030000
+RDATE:19470810T030000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19471102T030000
+RDATE:19471102T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19480314T020000
+RDATE:19480314T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19490403T020000
+RDATE:19490403T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19481031T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU;UNTIL=19491030T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19501022T030000
+RDATE:19501022T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19511021T030000
+RDATE:19511021T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19521026T030000
+RDATE:19521026T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19500416T020000
+RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=3SU;UNTIL=19530419T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19540411T020000
+RDATE:19540411T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19550417T020000
+RDATE:19550417T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19560422T020000
+RDATE:19560422T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19570414T020000
+RDATE:19570414T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19580420T020000
+RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=3SU;UNTIL=19590419T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19600410T020000
+RDATE:19600410T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19531004T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=1SU;UNTIL=19601002T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19610326T020000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU;UNTIL=19630331T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19640322T020000
+RDATE:19640322T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19611029T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU;UNTIL=19641025T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19651024T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=4SU;UNTIL=19661023T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19650321T020000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=3SU;UNTIL=19670319T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19671029T030000
+RDATE:19671029T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+010000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19681027T000000
+RDATE:19681027T000000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19680218T020000
+RDATE:19680218T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19711031T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU;UNTIL=19751026T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19761024T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=4SU;UNTIL=19771023T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19720319T020000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=3SU;UNTIL=19800316T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19781029T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU;UNTIL=19801026T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19811025T020000
+RDATE:19811025T020000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19821024T020000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=4SU;UNTIL=19831023T020000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19841028T020000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU;UNTIL=19871025T020000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19881023T020000
+RDATE:19881023T020000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19891029T020000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU;UNTIL=19921025T020000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19931024T020000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=4SU;UNTIL=19951022T020000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19810329T010000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU;UNTIL=19960331T010000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19961027T020000
+RDATE:19961027T020000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:(DST)
+DTSTART:19970330T010000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:(STD)
+DTSTART:19971026T020000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+CREATED:20241023T131035Z
+LAST-MODIFIED:20241023T131141Z
+DTSTAMP:20241023T131141Z
+UID:b9a23b47-f109-4e7a-908c-75e925b27def
+SUMMARY:event with alarms
+DTSTART;TZID=Europe/London:20241023T150000
+DTEND;TZID=Europe/London:20241023T160000
+TRANSP:OPAQUE
+X-MOZ-GENERATION:2
+BEGIN:VALARM
+ACTION:DISPLAY
+TRIGGER:-PT15M
+DESCRIPTION:Mozilla Standardbeschreibung
+END:VALARM
+BEGIN:VALARM
+ACTION:DISPLAY
+TRIGGER:-PT45M
+DESCRIPTION:Mozilla Standardbeschreibung
+END:VALARM
+END:VEVENT
+END:VCALENDAR
diff -pruN 6.0.1-3/src/icalendar/tests/calendars/alarm_thunderbird_snoozed_until_1457.ics 6.3.1-1/src/icalendar/tests/calendars/alarm_thunderbird_snoozed_until_1457.ics
--- 6.0.1-3/src/icalendar/tests/calendars/alarm_thunderbird_snoozed_until_1457.ics	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/calendars/alarm_thunderbird_snoozed_until_1457.ics	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,626 @@
+BEGIN:VCALENDAR
+PRODID:-//Mozilla.org/NONSGML Mozilla Calendar V1.1//EN
+VERSION:2.0
+BEGIN:VTIMEZONE
+TZID:Europe/London
+X-TZINFO:Europe/London[2024a]
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:-000115
+TZNAME:Europe/London(STD)
+DTSTART:18471201T000000
+RDATE:18471201T000000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19160521T020000
+RDATE:19160521T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19161001T030000
+RDATE:19161001T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19170408T020000
+RDATE:19170408T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19170917T030000
+RDATE:19170917T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19180324T020000
+RDATE:19180324T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19180930T030000
+RRULE:FREQ=YEARLY;BYMONTH=9;BYDAY=-1MO;UNTIL=19190929T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19190330T020000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU;UNTIL=19200328T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19201025T030000
+RDATE:19201025T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19210403T020000
+RDATE:19210403T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19211003T030000
+RDATE:19211003T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19220326T020000
+RDATE:19220326T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19221008T030000
+RDATE:19221008T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19230422T020000
+RDATE:19230422T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19240413T020000
+RDATE:19240413T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19230916T030000
+RRULE:FREQ=YEARLY;BYMONTH=9;BYDAY=3SU;UNTIL=19240921T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19250419T020000
+RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=3SU;UNTIL=19260418T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19270410T020000
+RDATE:19270410T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19280422T020000
+RDATE:19280422T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19290421T020000
+RDATE:19290421T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19300413T020000
+RDATE:19300413T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19310419T020000
+RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=3SU;UNTIL=19320417T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19251004T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=1SU;UNTIL=19321002T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19330409T020000
+RDATE:19330409T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19331008T030000
+RDATE:19331008T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19340422T020000
+RDATE:19340422T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19350414T020000
+RDATE:19350414T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19360419T020000
+RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=3SU;UNTIL=19370418T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19380410T020000
+RDATE:19380410T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19341007T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=1SU;UNTIL=19381002T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19390416T020000
+RDATE:19390416T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19400225T020000
+RDATE:19400225T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+020000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(DST)
+DTSTART:19410504T020000
+RDATE:19410504T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+020000
+TZNAME:Europe/London(DST)
+DTSTART:19410810T030000
+RDATE:19410810T030000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+020000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(DST)
+DTSTART:19420405T020000
+RDATE:19420405T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+020000
+TZNAME:Europe/London(DST)
+DTSTART:19420809T030000
+RDATE:19420809T030000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+020000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(DST)
+DTSTART:19430404T020000
+RDATE:19430404T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+020000
+TZNAME:Europe/London(DST)
+DTSTART:19430815T030000
+RDATE:19430815T030000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+020000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(DST)
+DTSTART:19440402T020000
+RDATE:19440402T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+020000
+TZNAME:Europe/London(DST)
+DTSTART:19440917T030000
+RDATE:19440917T030000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+020000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(DST)
+DTSTART:19450402T020000
+RDATE:19450402T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19391119T030000
+RDATE:19391119T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+020000
+TZNAME:Europe/London(DST)
+DTSTART:19450715T030000
+RDATE:19450715T030000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19460414T020000
+RDATE:19460414T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19470316T020000
+RDATE:19470316T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+020000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(DST)
+DTSTART:19470413T020000
+RDATE:19470413T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19451007T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=1SU;UNTIL=19461006T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+020000
+TZNAME:Europe/London(DST)
+DTSTART:19470810T030000
+RDATE:19470810T030000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19471102T030000
+RDATE:19471102T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19480314T020000
+RDATE:19480314T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19490403T020000
+RDATE:19490403T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19481031T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU;UNTIL=19491030T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19501022T030000
+RDATE:19501022T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19511021T030000
+RDATE:19511021T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19521026T030000
+RDATE:19521026T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19500416T020000
+RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=3SU;UNTIL=19530419T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19540411T020000
+RDATE:19540411T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19550417T020000
+RDATE:19550417T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19560422T020000
+RDATE:19560422T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19570414T020000
+RDATE:19570414T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19580420T020000
+RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=3SU;UNTIL=19590419T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19600410T020000
+RDATE:19600410T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19531004T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=1SU;UNTIL=19601002T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19610326T020000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU;UNTIL=19630331T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19640322T020000
+RDATE:19640322T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19611029T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU;UNTIL=19641025T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19651024T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=4SU;UNTIL=19661023T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19650321T020000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=3SU;UNTIL=19670319T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19671029T030000
+RDATE:19671029T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+010000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19681027T000000
+RDATE:19681027T000000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19680218T020000
+RDATE:19680218T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19711031T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU;UNTIL=19751026T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19761024T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=4SU;UNTIL=19771023T030000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19720319T020000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=3SU;UNTIL=19800316T020000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19781029T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU;UNTIL=19801026T030000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19811025T020000
+RDATE:19811025T020000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19821024T020000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=4SU;UNTIL=19831023T020000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19841028T020000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU;UNTIL=19871025T020000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19881023T020000
+RDATE:19881023T020000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19891029T020000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU;UNTIL=19921025T020000
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19931024T020000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=4SU;UNTIL=19951022T020000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:Europe/London(DST)
+DTSTART:19810329T010000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU;UNTIL=19960331T010000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:Europe/London(STD)
+DTSTART:19961027T020000
+RDATE:19961027T020000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETTO:+010000
+TZOFFSETFROM:+000000
+TZNAME:(DST)
+DTSTART:19970330T010000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETTO:+000000
+TZOFFSETFROM:+010000
+TZNAME:(STD)
+DTSTART:19971026T020000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+CREATED:20241023T131035Z
+LAST-MODIFIED:20241023T135202Z
+DTSTAMP:20241023T135202Z
+UID:b9a23b47-f109-4e7a-908c-75e925b27def
+SUMMARY:event with alarms
+X-MOZ-LASTACK:20241023T135202Z
+DTSTART;TZID=Europe/London:20241023T150000
+DTEND;TZID=Europe/London:20241023T160000
+TRANSP:OPAQUE
+X-MOZ-GENERATION:4
+X-MOZ-SNOOZE-TIME:20241023T135702Z
+BEGIN:VALARM
+ACTION:DISPLAY
+TRIGGER:-PT15M
+DESCRIPTION:Mozilla Standardbeschreibung
+END:VALARM
+BEGIN:VALARM
+ACTION:DISPLAY
+TRIGGER:-PT45M
+DESCRIPTION:Mozilla Standardbeschreibung
+END:VALARM
+END:VEVENT
+END:VCALENDAR
diff -pruN 6.0.1-3/src/icalendar/tests/calendars/america_new_york.ics 6.3.1-1/src/icalendar/tests/calendars/america_new_york.ics
--- 6.0.1-3/src/icalendar/tests/calendars/america_new_york.ics	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/calendars/america_new_york.ics	2025-05-20 07:31:39.000000000 +0000
@@ -55,7 +55,7 @@ END:VTIMEZONE
 BEGIN:VEVENT
 UID:noend123
 DTSTART;TZID=custom_America/New_York;VALUE=DATE-TIME:20140829T080000
-DTSTART;TZID=custom_America/New_York;VALUE=DATE-TIME:20140829T100000
+DTEND;TZID=custom_America/New_York;VALUE=DATE-TIME:20140829T100000
 SUMMARY:an event with a custom tz name
 END:VEVENT
 END:VCALENDAR
diff -pruN 6.0.1-3/src/icalendar/tests/calendars/america_new_york_forward_reference.ics 6.3.1-1/src/icalendar/tests/calendars/america_new_york_forward_reference.ics
--- 6.0.1-3/src/icalendar/tests/calendars/america_new_york_forward_reference.ics	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/calendars/america_new_york_forward_reference.ics	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,61 @@
+BEGIN:VCALENDAR
+BEGIN:VEVENT
+UID:noend123
+DTSTART;TZID=custom_America/New_York_Forward_reference;VALUE=DATE-TIME:20140829T080000
+DTSTART;TZID=custom_America/New_York_Forward_reference;VALUE=DATE-TIME:20140829T100000
+SUMMARY:an event with a custom tz name
+END:VEVENT
+BEGIN:VTIMEZONE
+TZID:custom_America/New_York_Forward_reference
+LAST-MODIFIED:20050809T050000Z
+BEGIN:DAYLIGHT
+DTSTART:19670430T020000
+RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=-1SU;UNTIL=19730429T070000Z
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+TZNAME:EDT
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:19671029T020000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU;UNTIL=20061029T060000Z
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+TZNAME:EST
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:19740106T020000
+RDATE:19750223T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+TZNAME:EDT
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+DTSTART:19760425T020000
+RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=-1SU;UNTIL=19860427T070000Z
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+TZNAME:EDT
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+DTSTART:19870405T020000
+RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=1SU;UNTIL=20060402T070000Z
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+TZNAME:EDT
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+DTSTART:20070311T020000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+TZNAME:EDT
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:20071104T020000
+RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+TZNAME:EST
+END:STANDARD
+END:VTIMEZONE
+END:VCALENDAR
diff -pruN 6.0.1-3/src/icalendar/tests/calendars/issue_218_bad_tzid.ics 6.3.1-1/src/icalendar/tests/calendars/issue_218_bad_tzid.ics
--- 6.0.1-3/src/icalendar/tests/calendars/issue_218_bad_tzid.ics	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/calendars/issue_218_bad_tzid.ics	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,24 @@
+BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//TEST//TEST//EN
+BEGIN:VTIMEZONE
+TZID:UTC+11
+BEGIN:STANDARD
+DTSTART;VALUE=DATE:20170101
+TZNAME:UTC+11
+TZOFFSETFROM:+1100
+TZOFFSETTO:+1100
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+DESCRIPTION:TESTING
+DTEND;TZID=UTC+11:20170228T233000
+DTSTAMP:20170227T064302Z
+DTSTART;TZID=UTC+11:20170228T230000
+RESOURCES:Court 4
+SEQUENCE:0
+STATUS:Confirmed
+SUMMARY:TESTIN
+UID:1961094_636238800000000000
+END:VEVENT
+END:VCALENDAR
diff -pruN 6.0.1-3/src/icalendar/tests/calendars/issue_722_missing_VTIMEZONE_custom.ics 6.3.1-1/src/icalendar/tests/calendars/issue_722_missing_VTIMEZONE_custom.ics
--- 6.0.1-3/src/icalendar/tests/calendars/issue_722_missing_VTIMEZONE_custom.ics	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/calendars/issue_722_missing_VTIMEZONE_custom.ics	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,5 @@
+BEGIN:VCALENDAR
+BEGIN:VEVENT
+DTSTART;TZID=CUSTOM_tzid;VALUE=DATE-TIME:20140829T080000
+END:VEVENT
+END:VCALENDAR
diff -pruN 6.0.1-3/src/icalendar/tests/calendars/issue_722_missing_timezones.ics 6.3.1-1/src/icalendar/tests/calendars/issue_722_missing_timezones.ics
--- 6.0.1-3/src/icalendar/tests/calendars/issue_722_missing_timezones.ics	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/calendars/issue_722_missing_timezones.ics	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,20 @@
+BEGIN:VCALENDAR
+DESCRIPTION:We leave the timezones out but we use common names so that they are added.
+BEGIN:VEVENT
+DTSTART;TZID=America/New_York;VALUE=DATE-TIME:20140829T080000
+DTEND;TZID=America/Los_Angeles;VALUE=DATE-TIME:20140829T080000
+RDATE;VALUE=PERIOD;TZID=Europe/Berlin:20240913T120000/PT2H
+SUMMARY:an event with a custom tz name
+END:VEVENT
+BEGIN:VEVENT
+RECURRENCE-ID;TZID=Europe/Moscow:20190309T020000
+END:VEVENT
+BEGIN:VTODO
+DUE;TZID=Asia/Singapore;VALUE=DATE-TIME:20140829T080000
+END:VTODO
+BEGIN:VEVENT
+RDATE;TZID=Mexico/General:20190309T020000
+RDATE;TZID=America/Noronha:20190309T020000
+DTSTAMP:19920901T130000Z
+END:VEVENT
+END:VCALENDAR
diff -pruN 6.0.1-3/src/icalendar/tests/calendars/issue_722_timezone_transition_ambiguity.ics 6.3.1-1/src/icalendar/tests/calendars/issue_722_timezone_transition_ambiguity.ics
--- 6.0.1-3/src/icalendar/tests/calendars/issue_722_timezone_transition_ambiguity.ics	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/calendars/issue_722_timezone_transition_ambiguity.ics	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,44 @@
+BEGIN:VCALENDAR
+BEGIN:VTIMEZONE
+TZID:MyTimezone
+BEGIN:STANDARD
+COMMENT:The timezone starts at 2024-01-01 with +12h offset
+TZOFFSETFROM:+1000
+TZOFFSETTO:+1200
+DTSTART:20240101T000000
+TZNAME:winter
+END:STANDARD
+BEGIN:DAYLIGHT
+COMMENT:The timezone goes from +12h to +10h at 8 am
+TZOFFSETFROM:+1200
+TZOFFSETTO:+1000
+DTSTART:20240505T080000
+TZNAME:summer
+END:DAYLIGHT
+END:VTIMEZONE
+BEGIN:VEVENT
+UID:0
+SUMMARY:This event is clearly in winter
+DTSTART;TZID=MyTimezone;VALUE=DATE-TIME:20240303T080000
+X-TZNAME:winter
+END:VEVENT
+BEGIN:VEVENT
+UID:1
+SUMMARY:This event is clearly in summer
+X-TZNAME:summer
+DTSTART;TZID=MyTimezone;VALUE=DATE-TIME:20240803T080000
+END:VEVENT
+BEGIN:VEVENT
+UID:2
+SUMMARY:Transition is from 8am -> 6am, so 8:00:01 is summer
+X-TZNAME:summer
+DTSTART;TZID=MyTimezone;VALUE=DATE-TIME:20240505T080001
+END:VEVENT
+BEGIN:VEVENT
+UID:3
+SUMMARY:Transition is from 8am -> 6am, so 7:00:01 is winter
+  RFC5545 does not allow us to be at the later TZ.
+X-TZNAME:winter
+DTSTART;TZID=MyTimezone;VALUE=DATE-TIME:20240505T070001
+END:VEVENT
+END:VCALENDAR
\ No newline at end of file
diff -pruN 6.0.1-3/src/icalendar/tests/calendars/issue_798_freebusy.ics 6.3.1-1/src/icalendar/tests/calendars/issue_798_freebusy.ics
--- 6.0.1-3/src/icalendar/tests/calendars/issue_798_freebusy.ics	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/calendars/issue_798_freebusy.ics	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,12 @@
+BEGIN:VCALENDAR
+BEGIN:VFREEBUSY
+FREEBUSY;FBTYPE=BUSY-UNAVAILABLE:19970308T160000Z/PT8H30M
+END:VFREEBUSY
+BEGIN:VFREEBUSY
+FREEBUSY:19970308T160000Z/PT3H,19970308T200000Z/PT1H
+END:VFREEBUSY
+BEGIN:VFREEBUSY
+FREEBUSY;FBTYPE=FREE:19970308T160000Z/PT3H,19970308T200000Z/PT1H
+ ,19970308T230000Z/19970309T000000Z
+END:VFREEBUSY
+END:VCALENDAR
\ No newline at end of file
diff -pruN 6.0.1-3/src/icalendar/tests/calendars/issue_798_related_to.ics 6.3.1-1/src/icalendar/tests/calendars/issue_798_related_to.ics
--- 6.0.1-3/src/icalendar/tests/calendars/issue_798_related_to.ics	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/calendars/issue_798_related_to.ics	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,8 @@
+BEGIN:VCALENDAR
+BEGIN:VEVENT
+RELATED-TO:jsmith.part7.19960817T083000.xyzMail@example.com
+END:VEVENT
+BEGIN:VEVENT
+RELATED-TO;RELTYPE=SIBLING:19960401-080045-4000F192713@example.com
+END:VEVENT
+END:VCALENDAR
\ No newline at end of file
diff -pruN 6.0.1-3/src/icalendar/tests/calendars/issue_836_do_not_quote_tzid.ics 6.3.1-1/src/icalendar/tests/calendars/issue_836_do_not_quote_tzid.ics
--- 6.0.1-3/src/icalendar/tests/calendars/issue_836_do_not_quote_tzid.ics	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/calendars/issue_836_do_not_quote_tzid.ics	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,27 @@
+BEGIN:VCALENDAR
+METHOD:PUBLISH
+PRODID:Microsoft Exchange Server 2010
+VERSION:2.0
+BEGIN:VTIMEZONE
+TZID:Eastern Standard Time
+BEGIN:STANDARD
+DTSTART:16010101T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=1SU;BYMONTH=11
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:16010101T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=2SU;BYMONTH=3
+END:DAYLIGHT
+END:VTIMEZONE
+BEGIN:VEVENT
+UID:minimal-demo-event-est-20241028@example.com
+SUMMARY:Anonymous Test Event for TZID
+DTSTART;TZID=Eastern Standard Time:20241028T170000
+DTEND;TZID=Eastern Standard Time:20241028T180000
+DTSTAMP:20250514T023916Z
+END:VEVENT
+END:VCALENDAR
diff -pruN 6.0.1-3/src/icalendar/tests/calendars/rfc_5545_RDATE_example.ics 6.3.1-1/src/icalendar/tests/calendars/rfc_5545_RDATE_example.ics
--- 6.0.1-3/src/icalendar/tests/calendars/rfc_5545_RDATE_example.ics	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/calendars/rfc_5545_RDATE_example.ics	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,33 @@
+BEGIN:VCALENDAR
+BEGIN:VEVENT
+UID:0
+RDATE:19970714T123000
+END:VEVENT
+BEGIN:VEVENT
+UID:1
+RDATE:19970714T123000Z
+END:VEVENT
+BEGIN:VEVENT
+UID:2
+RDATE;TZID=America/New_York:19970714T083000
+END:VEVENT
+BEGIN:VEVENT
+UID:3
+RDATE;VALUE=PERIOD:19960403T020000Z/19960403T040000Z,
+ 19960404T010000Z/PT3H
+END:VEVENT
+BEGIN:VEVENT
+UID:4
+RDATE;VALUE=DATE:19970101,19970120,19970217,19970421,
+ 19970526,19970704,19970901,19971014,19971128,19971129,19971225
+END:VEVENT
+BEGIN:VEVENT
+UID:5
+RDATE;VALUE=DATE:19970101,19970120,19970217,19970421,
+ 19970526,19970704,19970901,19971014,19971128,19971129,19971225
+RDATE;VALUE=PERIOD:19960403T020000Z/19960403T040000Z,
+ 19960404T010000Z/PT3H
+RDATE:19970714T123000Z
+RDATE;TZID=America/New_York:19970714T083000
+END:VEVENT
+END:VCALENDAR
diff -pruN 6.0.1-3/src/icalendar/tests/calendars/rfc_6868.ics 6.3.1-1/src/icalendar/tests/calendars/rfc_6868.ics
--- 6.0.1-3/src/icalendar/tests/calendars/rfc_6868.ics	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/calendars/rfc_6868.ics	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,6 @@
+BEGIN:VCALENDAR
+X-PARAM;NEWLINE=^n;ALL=^^^'^n;UNKNOWN=^a^ ^asd:asd
+BEGIN:VEVENT
+ATTENDEE;CN=George Herman ^'Babe^' Ruth:mailto:babe@example.com
+END:VEVENT
+END:VCALENDAR
diff -pruN 6.0.1-3/src/icalendar/tests/conftest.py 6.3.1-1/src/icalendar/tests/conftest.py
--- 6.0.1-3/src/icalendar/tests/conftest.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/conftest.py	2025-05-20 07:31:39.000000000 +0000
@@ -1,27 +1,35 @@
 try:
-    from backports import zoneinfo
+    from backports import zoneinfo  # type: ignore  # noqa: PGH003
 except ImportError:
     import zoneinfo
+from typing import Generator
+
 import pytest
+
 import icalendar
+
+from . import timezone_ids
+
 try:
     import pytz
 except ImportError:
     pytz = None
-from datetime import datetime
-from dateutil import tz
-from icalendar.cal import Component, Calendar
-from icalendar.timezone import tzp as _tzp
-from icalendar.timezone import TZP
-from pathlib import Path
 import itertools
 import sys
+import uuid
+from pathlib import Path
+
+from dateutil import tz
+
+from icalendar.cal import Calendar, Component
+from icalendar.timezone import TZP
+from icalendar.timezone import tzp as _tzp
 
 HAS_PYTZ = pytz is not None
 if HAS_PYTZ:
     PYTZ_UTC = [
         pytz.utc,
-        pytz.timezone('UTC'),
+        pytz.timezone("UTC"),
     ]
     PYTZ_IN_TIMEZONE = [
         lambda dt, tzname: pytz.timezone(tzname).localize(dt),
@@ -34,14 +42,19 @@ else:
 
 
 class DataSource:
-    '''A collection of parsed ICS elements (e.g calendars, timezones, events)'''
-    def __init__(self, data_source_folder:Path, parser):
+    """A collection of parsed ICS elements (e.g calendars, timezones, events)"""
+
+    def __init__(self, data_source_folder: Path, parser):
         self._parser = parser
         self._data_source_folder = data_source_folder
 
     def keys(self):
         """Return all the files that could be used."""
-        return [p.stem for p in self._data_source_folder.iterdir() if p.suffix.lower() == ".ics"]
+        return [
+            p.stem
+            for p in self._data_source_folder.iterdir()
+            if p.suffix.lower() == ".ics"
+        ]
 
     def __getitem__(self, attribute):
         """Parse a file and return the result stored in the attribute."""
@@ -49,15 +62,16 @@ class DataSource:
             source_file = attribute
             attribute = attribute[:-4]
         else:
-            source_file = attribute + '.ics'
+            source_file = attribute + ".ics"
         source_path = self._data_source_folder / source_file
         if not source_path.is_file():
             raise AttributeError(f"{source_path} does not exist.")
-        with source_path.open('rb') as f:
+        with source_path.open("rb") as f:
             raw_ics = f.read()
         source = self._parser(raw_ics)
         if not isinstance(source, list):
             source.raw_ics = raw_ics
+            source.source_file = source_file
         self.__dict__[attribute] = source
         return source
 
@@ -76,51 +90,73 @@ class DataSource:
     @property
     def multiple(self):
         """Return a list of all components parsed."""
-        return self.__class__(self._data_source_folder, lambda data: self._parser(data, multiple=True))
+        return self.__class__(
+            self._data_source_folder, lambda data: self._parser(data, multiple=True)
+        )
+
 
 HERE = Path(__file__).parent
-CALENDARS_FOLDER = HERE / 'calendars'
-TIMEZONES_FOLDER = HERE / 'timezones'
-EVENTS_FOLDER = HERE / 'events'
+CALENDARS_FOLDER = HERE / "calendars"
+TIMEZONES_FOLDER = HERE / "timezones"
+EVENTS_FOLDER = HERE / "events"
+ALARMS_FOLDER = HERE / "alarms"
+
 
 @pytest.fixture(scope="module")
 def calendars(tzp):
     return DataSource(CALENDARS_FOLDER, icalendar.Calendar.from_ical)
 
+
 @pytest.fixture(scope="module")
 def timezones(tzp):
     return DataSource(TIMEZONES_FOLDER, icalendar.Timezone.from_ical)
 
+
 @pytest.fixture(scope="module")
 def events(tzp):
     return DataSource(EVENTS_FOLDER, icalendar.Event.from_ical)
 
-@pytest.fixture(params=PYTZ_UTC + [
-    zoneinfo.ZoneInfo('UTC'),
-    tz.UTC,
-    tz.gettz('UTC')])
+
+@pytest.fixture(scope="module")
+def alarms(tzp):
+    return DataSource(ALARMS_FOLDER, icalendar.Alarm.from_ical)
+
+
+@pytest.fixture(params=PYTZ_UTC + [zoneinfo.ZoneInfo("UTC"), tz.UTC, tz.gettz("UTC")])
 def utc(request, tzp):
     return request.param
 
-@pytest.fixture(params=PYTZ_IN_TIMEZONE + [
-    lambda dt, tzname: dt.replace(tzinfo=tz.gettz(tzname)),
-    lambda dt, tzname: dt.replace(tzinfo=zoneinfo.ZoneInfo(tzname))
-])
+
+@pytest.fixture(
+    params=PYTZ_IN_TIMEZONE
+    + [
+        lambda dt, tzname: dt.replace(tzinfo=tz.gettz(tzname)),
+        lambda dt, tzname: dt.replace(tzinfo=zoneinfo.ZoneInfo(tzname)),
+    ]
+)
 def in_timezone(request, tzp):
     return request.param
 
 
 # exclude broken calendars here
 ICS_FILES_EXCLUDE = (
-    "big_bad_calendar.ics", "issue_104_broken_calendar.ics", "small_bad_calendar.ics",
-    "multiple_calendar_components.ics", "pr_480_summary_with_colon.ics",
-    "parsing_error_in_UTC_offset.ics", "parsing_error.ics",
+    "big_bad_calendar.ics",
+    "issue_104_broken_calendar.ics",
+    "small_bad_calendar.ics",
+    "multiple_calendar_components.ics",
+    "pr_480_summary_with_colon.ics",
+    "parsing_error_in_UTC_offset.ics",
+    "parsing_error.ics",
 )
 ICS_FILES = [
-    file.name for file in
-    itertools.chain(CALENDARS_FOLDER.iterdir(), TIMEZONES_FOLDER.iterdir(), EVENTS_FOLDER.iterdir())
+    file.name
+    for file in itertools.chain(
+        CALENDARS_FOLDER.iterdir(), TIMEZONES_FOLDER.iterdir(), EVENTS_FOLDER.iterdir()
+    )
     if file.name not in ICS_FILES_EXCLUDE
 ]
+
+
 @pytest.fixture(params=ICS_FILES)
 def ics_file(tzp, calendars, timezones, events, request):
     """An example ICS file."""
@@ -133,63 +169,68 @@ def ics_file(tzp, calendars, timezones,
 
 
 FUZZ_V1 = [key for key in CALENDARS_FOLDER.iterdir() if "fuzz-testcase" in str(key)]
+
+
 @pytest.fixture(params=FUZZ_V1)
 def fuzz_v1_calendar(request):
     """Clusterfuzz calendars."""
     return request.param
 
 
-@pytest.fixture()
+@pytest.fixture
 def x_sometime():
     """Map x_sometime to time"""
-    icalendar.cal.types_factory.types_map['X-SOMETIME'] = 'time'
+    icalendar.cal.types_factory.types_map["X-SOMETIME"] = "time"
     yield
-    icalendar.cal.types_factory.types_map.pop('X-SOMETIME')
+    icalendar.cal.types_factory.types_map.pop("X-SOMETIME")
 
 
-@pytest.fixture()
+@pytest.fixture
 def factory():
     """Return a new component factory."""
     return icalendar.ComponentFactory()
 
 
-@pytest.fixture()
+@pytest.fixture
 def vUTCOffset_ignore_exceptions():
     icalendar.vUTCOffset.ignore_exceptions = True
     yield
     icalendar.vUTCOffset.ignore_exceptions = False
 
 
-@pytest.fixture()
+@pytest.fixture
 def event_component(tzp):
     """Return an event component."""
     c = Component()
-    c.name = 'VEVENT'
+    c.name = "VEVENT"
     return c
 
 
-@pytest.fixture()
+@pytest.fixture
 def c(tzp):
     """Return an empty component."""
     c = Component()
     return c
+
+
 comp = c
 
-@pytest.fixture()
+
+@pytest.fixture
 def calendar_component(tzp):
     """Return an empty component."""
     c = Component()
-    c.name = 'VCALENDAR'
+    c.name = "VCALENDAR"
     return c
 
 
-@pytest.fixture()
+@pytest.fixture
 def filled_event_component(c, calendar_component):
     """Return an event with some values and add it to calendar_component."""
-    e = Component(summary='A brief history of time')
-    e.name = 'VEVENT'
-    e.add('dtend', '20000102T000000', encode=0)
-    e.add('dtstart', '20000101T000000', encode=0)
+    e = Component(summary="A brief history of time")
+    e.name = "VEVENT"
+    e.add("dtend", "20000102T000000", encode=0)
+    e.add("dtstart", "20000101T000000", encode=0)
     calendar_component.add_component(e)
     return e
 
@@ -197,12 +238,12 @@ def filled_event_component(c, calendar_c
 @pytest.fixture()
 def calendar_with_resources(tzp):
     c = Calendar()
-    c['resources'] = 'Chair, Table, "Room: 42"'
+    c["resources"] = 'Chair, Table, "Room: 42"'
     return c
 
 
 @pytest.fixture(scope="module")
-def tzp(tzp_name):
+def tzp(tzp_name) -> Generator[TZP, None, None]:
     """The timezone provider."""
     _tzp.use(tzp_name)
     yield _tzp
@@ -216,20 +257,35 @@ def other_tzp(request, tzp):
     The purpose here is to cross test: pytz <-> zoneinfo.
     tzp as parameter makes sure we test the cross product.
     """
-    tzp = TZP(request.param)
-    return tzp
+    return TZP(request.param)
 
 
-@pytest.fixture()
-def pytz_only(tzp):
+@pytest.fixture
+def pytz_only(tzp, tzp_name) -> str:
     """Skip tests that are not running under pytz."""
     assert tzp.uses_pytz()
+    return tzp_name
 
 
-@pytest.fixture()
-def zoneinfo_only(tzp, request, tzp_name):
+@pytest.fixture
+def zoneinfo_only(tzp, request, tzp_name) -> str:
     """Skip tests that are not running under zoneinfo."""
     assert tzp.uses_zoneinfo()
+    return tzp_name
+
+
+@pytest.fixture
+def no_pytz(tzp_name) -> str:
+    """Do not run tests with pytz."""
+    assert tzp_name != "pytz"
+    return tzp_name
+
+
+@pytest.fixture
+def no_zoneinfo(tzp_name) -> str:
+    """Do not run tests with zoneinfo."""
+    assert tzp_name != "zoneinfo"
+    return tzp_name
 
 
 def pytest_generate_tests(metafunc):
@@ -238,6 +294,8 @@ def pytest_generate_tests(metafunc):
     tzp_name will be parametrized according to the use of
     - pytz_only
     - zoneinfo_only
+    - no_pytz
+    - no_zoneinfo
 
     See https://docs.pytest.org/en/6.2.x/example/parametrize.html#deferring-the-setup-of-parametrized-resources
     """
@@ -247,14 +305,21 @@ def pytest_generate_tests(metafunc):
             tzp_names = ["zoneinfo"]
         if "pytz_only" in metafunc.fixturenames:
             tzp_names = PYTZ_TZP
-        assert not ("zoneinfo_only" in metafunc.fixturenames and "pytz_only" in metafunc.fixturenames), "Use pytz_only or zoneinfo_only but not both!"
+        assert not (
+            "zoneinfo_only" in metafunc.fixturenames
+            and "pytz_only" in metafunc.fixturenames
+        ), "Use pytz_only or zoneinfo_only but not both!"
+        for name in ["pytz", "zoneinfo"]:
+            if f"no_{name}" in metafunc.fixturenames and name in tzp_names:
+                tzp_names.remove(name)
         metafunc.parametrize("tzp_name", tzp_names, scope="module")
 
 
 class DoctestZoneInfo(zoneinfo.ZoneInfo):
     """Constent ZoneInfo representation for tests."""
+
     def __repr__(self):
-        return f"ZoneInfo(key={repr(self.key)})"
+        return f"ZoneInfo(key={self.key!r})"
 
 
 def doctest_print(obj):
@@ -270,13 +335,24 @@ def doctest_import(name, *args, **kw):
         return pytz
     return __import__(name, *args, **kw)
 
-@pytest.fixture()
+
+@pytest.fixture
 def env_for_doctest(monkeypatch):
     """Modify the environment to make doctests run."""
     monkeypatch.setitem(sys.modules, "zoneinfo", zoneinfo)
     monkeypatch.setattr(zoneinfo, "ZoneInfo", DoctestZoneInfo)
     from icalendar.timezone.zoneinfo import ZONEINFO
+    uid = uuid.UUID("d755cef5-2311-46ed-a0e1-6733c9e15c63", version=4)
+    monkeypatch.setattr(uuid, "uuid4", lambda: uid)
+
     monkeypatch.setattr(ZONEINFO, "utc", zoneinfo.ZoneInfo("UTC"))
-    return {
-        "print": doctest_print
-    }
+    return {"print": doctest_print}
+
+
+@pytest.fixture(params=timezone_ids.TZIDS)
+def tzid(request: pytest.FixtureRequest) -> str:
+    """Return a timezone id to be used with pytz or zoneinfo.
+
+    This goes through all the different timezones possible.
+    """
+    return request.param
diff -pruN 6.0.1-3/src/icalendar/tests/events/rfc_9074_example_1.ics 6.3.1-1/src/icalendar/tests/events/rfc_9074_example_1.ics
--- 6.0.1-3/src/icalendar/tests/events/rfc_9074_example_1.ics	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/events/rfc_9074_example_1.ics	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,16 @@
+BEGIN:VEVENT
+CREATED:20210302T151004Z
+UID:AC67C078-CED3-4BF5-9726-832C3749F627
+DTSTAMP:20210302T151004Z
+DTSTART;TZID=America/New_York:20210302T103000
+DTEND;TZID=America/New_York:20210302T113000
+SUMMARY:Meeting
+
+BEGIN:VALARM
+UID:8297C37D-BA2D-4476-91AE-C1EAA364F8E1
+TRIGGER:-PT15M
+DESCRIPTION:Event reminder
+ACTION:DISPLAY
+END:VALARM
+
+END:VEVENT
\ No newline at end of file
diff -pruN 6.0.1-3/src/icalendar/tests/events/rfc_9074_example_2.ics 6.3.1-1/src/icalendar/tests/events/rfc_9074_example_2.ics
--- 6.0.1-3/src/icalendar/tests/events/rfc_9074_example_2.ics	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/events/rfc_9074_example_2.ics	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,25 @@
+BEGIN:VEVENT
+CREATED:20210302T151004Z
+UID:AC67C078-CED3-4BF5-9726-832C3749F627
+DTSTAMP:20210302T151516Z
+DTSTART;TZID=America/New_York:20210302T103000
+DTEND;TZID=America/New_York:20210302T113000
+SUMMARY:Meeting
+
+BEGIN:VALARM
+UID:8297C37D-BA2D-4476-91AE-C1EAA364F8E1
+TRIGGER:-PT15M
+DESCRIPTION:Event reminder
+ACTION:DISPLAY
+ACKNOWLEDGED:20210302T151514Z
+END:VALARM
+
+BEGIN:VALARM
+UID:DE7B5C34-83FF-47FE-BE9E-FF41AE6DD097
+TRIGGER;VALUE=DATE-TIME:20210302T152000Z
+RELATED-TO;RELTYPE=SNOOZE:8297C37D-BA2D-4476-91AE-C1EAA364F8E1
+DESCRIPTION:Event reminder
+ACTION:DISPLAY
+END:VALARM
+
+END:VEVENT
diff -pruN 6.0.1-3/src/icalendar/tests/events/rfc_9074_example_3.ics 6.3.1-1/src/icalendar/tests/events/rfc_9074_example_3.ics
--- 6.0.1-3/src/icalendar/tests/events/rfc_9074_example_3.ics	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/events/rfc_9074_example_3.ics	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,25 @@
+BEGIN:VEVENT
+CREATED:20210302T151004Z
+UID:AC67C078-CED3-4BF5-9726-832C3749F627
+DTSTAMP:20210302T152026Z
+DTSTART;TZID=America/New_York:20210302T103000
+DTEND;TZID=America/New_York:20210302T113000
+SUMMARY:Meeting
+
+BEGIN:VALARM
+UID:8297C37D-BA2D-4476-91AE-C1EAA364F8E1
+TRIGGER:-PT15M
+DESCRIPTION:Event reminder
+ACTION:DISPLAY
+ACKNOWLEDGED:20210302T152024Z
+END:VALARM
+
+BEGIN:VALARM
+UID:87D690A7-B5E8-4EB4-8500-491F50AFE394
+TRIGGER;VALUE=DATE-TIME:20210302T152500Z
+RELATED-TO;RELTYPE=SNOOZE:8297C37D-BA2D-4476-91AE-C1EAA364F8E1
+DESCRIPTION:Event reminder
+ACTION:DISPLAY
+END:VALARM
+
+END:VEVENT
diff -pruN 6.0.1-3/src/icalendar/tests/events/rfc_9074_example_4.ics 6.3.1-1/src/icalendar/tests/events/rfc_9074_example_4.ics
--- 6.0.1-3/src/icalendar/tests/events/rfc_9074_example_4.ics	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/events/rfc_9074_example_4.ics	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,26 @@
+BEGIN:VEVENT
+CREATED:20210302T151004Z
+UID:AC67C078-CED3-4BF5-9726-832C3749F627
+DTSTAMP:20210302T152508Z
+DTSTART;TZID=America/New_York:20210302T103000
+DTEND;TZID=America/New_York:20210302T113000
+SUMMARY:Meeting
+
+BEGIN:VALARM
+UID:8297C37D-BA2D-4476-91AE-C1EAA364F8E1
+TRIGGER:-PT15M
+DESCRIPTION:Event reminder
+ACTION:DISPLAY
+ACKNOWLEDGED:20210302T152507Z
+END:VALARM
+
+BEGIN:VALARM
+UID:87D690A7-B5E8-4EB4-8500-491F50AFE394
+TRIGGER;VALUE=DATE-TIME:20210302T152500Z
+RELATED-TO;RELTYPE=SNOOZE:8297C37D-BA2D-4476-91AE-C1EAA364F8E1
+DESCRIPTION:Event reminder
+ACTION:DISPLAY
+ACKNOWLEDGED:20210302T152507Z
+END:VALARM
+
+END:VEVENT
\ No newline at end of file
diff -pruN 6.0.1-3/src/icalendar/tests/events/rfc_9074_example_proximity.ics 6.3.1-1/src/icalendar/tests/events/rfc_9074_example_proximity.ics
--- 6.0.1-3/src/icalendar/tests/events/rfc_9074_example_proximity.ics	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/events/rfc_9074_example_proximity.ics	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,14 @@
+BEGIN:VEVENT
+BEGIN:VALARM
+UID:77D80D14-906B-4257-963F-85B1E734DBB6
+ACTION:DISPLAY
+TRIGGER;VALUE=DATE-TIME:19760401T005545Z
+DESCRIPTION:Remember to buy milk
+PROXIMITY:DEPART
+BEGIN:VLOCATION
+UID:123456-abcdef-98765432
+NAME:Office
+URL:geo:40.443,-79.945;u=10
+END:VLOCATION
+END:VALARM
+END:VEVENT
diff -pruN 6.0.1-3/src/icalendar/tests/fuzzed/__init__.py 6.3.1-1/src/icalendar/tests/fuzzed/__init__.py
--- 6.0.1-3/src/icalendar/tests/fuzzed/__init__.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/fuzzed/__init__.py	2025-05-20 07:31:39.000000000 +0000
@@ -5,7 +5,10 @@ These test cases reproduce the failure.
 Some more tests can be added to make sure that the behavior works properly.
 """
 
-def fuzz_calendar_v1(from_ical, calendar_string: str, multiple: bool, should_walk: bool):
+
+def fuzz_calendar_v1(
+    from_ical, calendar_string: str, multiple: bool, should_walk: bool
+):
     """Take a from_ical function and reproduce the error.
 
     The calendar_string is a fuzzed input.
@@ -16,7 +19,7 @@ def fuzz_calendar_v1(from_ical, calendar
         cal = [cal]
     for c in cal:
         if should_walk:
-            for event in cal.walk('VEVENT'):
+            for event in c.walk("VEVENT"):
                 event.to_ical()
         else:
-            cal.to_ical()
+            c.to_ical()
diff -pruN 6.0.1-3/src/icalendar/tests/fuzzed/test_fuzzed_calendars.py 6.3.1-1/src/icalendar/tests/fuzzed/test_fuzzed_calendars.py
--- 6.0.1-3/src/icalendar/tests/fuzzed/test_fuzzed_calendars.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/fuzzed/test_fuzzed_calendars.py	2025-05-20 07:31:39.000000000 +0000
@@ -1,13 +1,12 @@
 """This test tests all fuzzed calendars."""
-from icalendar.tests.fuzzed import fuzz_calendar_v1
+
 import icalendar
+from icalendar.tests.fuzzed import fuzz_calendar_v1
+
 
 def test_fuzz_v1(fuzz_v1_calendar):
     """Test a calendar."""
     with open(fuzz_v1_calendar, "rb") as f:
         fuzz_calendar_v1(
-            icalendar.Calendar.from_ical,
-            f.read(),
-            multiple=True,
-            should_walk=True
+            icalendar.Calendar.from_ical, f.read(), multiple=True, should_walk=True
         )
diff -pruN 6.0.1-3/src/icalendar/tests/hypothesis/test_fuzzing.py 6.3.1-1/src/icalendar/tests/hypothesis/test_fuzzing.py
--- 6.0.1-3/src/icalendar/tests/hypothesis/test_fuzzing.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/hypothesis/test_fuzzing.py	2025-05-20 07:31:39.000000000 +0000
@@ -1,28 +1,24 @@
 import string
+import unittest
 
-from hypothesis import given, settings
 import hypothesis.strategies as st
+from hypothesis import given, settings
 
 from icalendar.parser import Contentline, Contentlines, Parameters
-import unittest
 
 
 def printable_characters(**kw):
-    return st.text(
-        st.characters(blacklist_categories=(
-            'Cc', 'Cs'
-        ), **kw)
-    )
+    return st.text(st.characters(blacklist_categories=("Cc", "Cs"), **kw))
+
 
 key = st.text(string.ascii_letters + string.digits, min_size=1)
-value = printable_characters(blacklist_characters='\\;:\"')
+value = printable_characters(blacklist_characters='\\;:"')
 
-class TestFuzzing(unittest.TestCase):
 
-    @given(lines=st.lists(
-        st.tuples(key, st.dictionaries(key, value), value),
-        min_size=1
-    ))
+class TestFuzzing(unittest.TestCase):
+    @given(
+        lines=st.lists(st.tuples(key, st.dictionaries(key, value), value), min_size=1)
+    )
     @settings(max_examples=10**3)
     def test_main(self, lines):
         cl = Contentlines()
@@ -33,6 +29,6 @@ class TestFuzzing(unittest.TestCase):
                 # Happens when there is a random parameter 'self'...
                 continue
             cl.append(Contentline.from_parts(key, params, value))
-        cl.append('')
+        cl.append("")
 
         assert Contentlines.from_ical(cl.to_ical()) == cl
diff -pruN 6.0.1-3/src/icalendar/tests/prop/__init__.py 6.3.1-1/src/icalendar/tests/prop/__init__.py
--- 6.0.1-3/src/icalendar/tests/prop/__init__.py	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/prop/__init__.py	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1 @@
+"""Test the value types of properties."""
diff -pruN 6.0.1-3/src/icalendar/tests/prop/test_constructors.py 6.3.1-1/src/icalendar/tests/prop/test_constructors.py
--- 6.0.1-3/src/icalendar/tests/prop/test_constructors.py	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/prop/test_constructors.py	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,120 @@
+from icalendar.prop import (
+    vBoolean,
+    vInline,
+    vUTCOffset,
+    vCategory,
+    vCalAddress,
+    vWeekday,
+    vDuration,
+    vFloat,
+    vGeo,
+    vInt,
+    vText,
+    vMonth,
+    vUTCOffset,
+    vFrequency,
+    vRecur,
+    vDatetime,
+    vUri,
+)
+import datetime
+
+
+def test_param_vCategory():
+    obj = vCategory(["Work", "Personal"], params={"SOME_PARAM": "VALUE"})
+    assert isinstance(obj, vCategory)
+    assert obj.params["SOME_PARAM"] == "VALUE"
+
+
+def test_param_vCalAddress():
+    obj = vCalAddress("mailto:jane_doe@example.com", params={"SOME_PARAM": "VALUE"})
+    assert isinstance(obj, vCalAddress)
+    assert obj.params["SOME_PARAM"] == "VALUE"
+
+
+def test_param_vWeekday():
+    obj = vWeekday("2FR", params={"SOME_PARAM": "VALUE"})
+    assert isinstance(obj, vWeekday)
+    assert obj.params["SOME_PARAM"] == "VALUE"
+
+
+def test_param_vBoolean():
+    obj = vBoolean(True, params={"SOME_PARAM": "VALUE"})
+    assert isinstance(obj, vBoolean)
+    assert obj.params["SOME_PARAM"] == "VALUE"
+
+
+def test_param_vDuration():
+    td = datetime.timedelta(days=15, seconds=18020)
+    obj = vDuration(td, params={"SOME_PARAM": "VALUE"})
+    assert isinstance(obj, vDuration)
+    assert obj.params["SOME_PARAM"] == "VALUE"
+
+
+def test_param_vFloat():
+    obj = vFloat("1.333", params={"SOME_PARAM": "VALUE"})
+    assert isinstance(obj, vFloat)
+    assert obj.params["SOME_PARAM"] == "VALUE"
+
+
+def test_param_vGeo():
+    obj = vGeo((37.386013, -122.082932), params={"SOME_PARAM": "VALUE"})
+    assert isinstance(obj, vGeo)
+    assert obj.params["SOME_PARAM"] == "VALUE"
+
+
+def test_param_vInt():
+    obj = vInt("87", params={"SOME_PARAM": "VALUE"})
+    assert isinstance(obj, vInt)
+    assert obj.params["SOME_PARAM"] == "VALUE"
+
+
+def test_param_vInline():
+    obj = vInline("sometxt", params={"SOME_PARAM": "VALUE"})
+    assert isinstance(obj, vInline)
+    assert obj.params["SOME_PARAM"] == "VALUE"
+
+
+def test_param_vText():
+    obj = vText("sometxt", params={"SOME_PARAM": "VALUE"})
+    assert isinstance(obj, vText)
+    assert obj.params["SOME_PARAM"] == "VALUE"
+
+
+def test_param_vMonth():
+    obj = vMonth(1, params={"SOME_PARAM": "VALUE"})
+    assert isinstance(obj, vMonth)
+    assert obj.params["SOME_PARAM"] == "VALUE"
+
+
+def test_param_vUTCOffset():
+    obj = vUTCOffset(
+        datetime.timedelta(days=-1, seconds=68400), params={"SOME_PARAM": "VALUE"}
+    )
+    assert isinstance(obj, vUTCOffset)
+    assert obj.params["SOME_PARAM"] == "VALUE"
+
+
+def test_param_vFrequency():
+    obj = vFrequency("DAILY", params={"SOME_PARAM": "VALUE"})
+    assert isinstance(obj, vFrequency)
+    assert obj.params["SOME_PARAM"] == "VALUE"
+
+
+def test_param_vRecur():
+    obj = vRecur({"FREQ": ["DAILY"], "COUNT": [10]}, params={"SOME_PARAM": "VALUE"})
+    assert isinstance(obj, vRecur)
+    assert obj.params["SOME_PARAM"] == "VALUE"
+
+
+def test_param_vDatetime():
+    dt = datetime.datetime(2025, 3, 16, 14, 30, 0, tzinfo=datetime.timezone.utc)
+    obj = vDatetime(dt, params={"SOME_PARAM": "VALUE"})
+    assert isinstance(obj, vDatetime)
+    assert obj.params["SOME_PARAM"] == "VALUE"
+
+
+def test_param_vUri():
+    obj = vUri("WWW.WESBITE.COM", params={"SOME_PARAM": "VALUE"})
+    assert isinstance(obj, vUri)
+    assert obj.params["SOME_PARAM"] == "VALUE"
diff -pruN 6.0.1-3/src/icalendar/tests/prop/test_identity_and_equality.py 6.3.1-1/src/icalendar/tests/prop/test_identity_and_equality.py
--- 6.0.1-3/src/icalendar/tests/prop/test_identity_and_equality.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/prop/test_identity_and_equality.py	2025-05-20 07:31:39.000000000 +0000
@@ -1,47 +1,70 @@
 """Test the identity and equality between properties."""
+
+from datetime import date, datetime, time
+
 from icalendar import vDDDTypes
-from datetime import datetime, date, time
 from icalendar.timezone.zoneinfo import zoneinfo
+
 try:
     import pytz
 except ImportError:
     pytz = None
-from dateutil import tz
-import pytest
 from copy import deepcopy
 
-
+import pytest
+from dateutil import tz
 
 vDDDTypes_list = [
-    vDDDTypes(datetime(year=2022, month=7, day=22, hour=12, minute=7, tzinfo=zoneinfo.ZoneInfo("Europe/London"))),
+    vDDDTypes(
+        datetime(
+            year=2022,
+            month=7,
+            day=22,
+            hour=12,
+            minute=7,
+            tzinfo=zoneinfo.ZoneInfo("Europe/London"),
+        )
+    ),
     vDDDTypes(datetime(year=2022, month=7, day=22, hour=12, minute=7)),
     vDDDTypes(datetime(year=2022, month=7, day=22, hour=12, minute=7, tzinfo=tz.UTC)),
     vDDDTypes(date(year=2022, month=7, day=22)),
     vDDDTypes(date(year=2022, month=7, day=23)),
-    vDDDTypes(time(hour=22, minute=7, second=2))
+    vDDDTypes(time(hour=22, minute=7, second=2)),
 ]
 if pytz:
-    vDDDTypes_list.append(vDDDTypes(pytz.timezone('EST').localize(datetime(year=2022, month=7, day=22, hour=12, minute=7))),)
+    vDDDTypes_list.append(
+        vDDDTypes(
+            pytz.timezone("EST").localize(
+                datetime(year=2022, month=7, day=22, hour=12, minute=7)
+            )
+        ),
+    )
+
 
 def identity(x):
     return x
 
-@pytest.mark.parametrize("map", [
-    deepcopy,
-    identity,
-    hash,
-])
+
+@pytest.mark.parametrize(
+    "map",
+    [
+        deepcopy,
+        identity,
+        hash,
+    ],
+)
 @pytest.mark.parametrize("v_type", vDDDTypes_list)
 @pytest.mark.parametrize("other", vDDDTypes_list)
 def test_vDDDTypes_equivalance(map, v_type, other):
     if v_type is other:
         assert map(v_type) == map(other), f"identity implies equality: {map.__name__}()"
-        assert not (map(v_type) != map(other)), f"identity implies equality: {map.__name__}()"
+        assert map(v_type) == map(other), f"identity implies equality: {map.__name__}()"
     else:
         assert map(v_type) != map(other), f"expected inequality: {map.__name__}()"
-        assert not (map(v_type) == map(other)), f"expected inequality: {map.__name__}()"
+        assert map(v_type) != map(other), f"expected inequality: {map.__name__}()"
+
 
 @pytest.mark.parametrize("v_type", vDDDTypes_list)
 def test_inequality_with_different_types(v_type):
     assert v_type != 42
-    assert v_type != 'test'
+    assert v_type != "test"
diff -pruN 6.0.1-3/src/icalendar/tests/prop/test_property_values.py 6.3.1-1/src/icalendar/tests/prop/test_property_values.py
--- 6.0.1-3/src/icalendar/tests/prop/test_property_values.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/prop/test_property_values.py	2025-05-20 07:31:39.000000000 +0000
@@ -1,17 +1,19 @@
 """Test that composed values are properly converted."""
-from icalendar import Event
+
 from datetime import datetime
 
+from icalendar import Event
+
 
 def test_vDDDLists_timezone(tzp):
     """Test vDDDLists with timezone information."""
     vevent = Event()
-    dt1 = tzp.localize(datetime(2013, 1, 1), 'Europe/Vienna')
-    dt2 = tzp.localize(datetime(2013, 1, 2), 'Europe/Vienna')
-    dt3 = tzp.localize(datetime(2013, 1, 3), 'Europe/Vienna')
-    vevent.add('rdate', [dt1, dt2])
-    vevent.add('exdate', dt3)
+    dt1 = tzp.localize(datetime(2013, 1, 1), "Europe/Vienna")
+    dt2 = tzp.localize(datetime(2013, 1, 2), "Europe/Vienna")
+    dt3 = tzp.localize(datetime(2013, 1, 3), "Europe/Vienna")
+    vevent.add("rdate", [dt1, dt2])
+    vevent.add("exdate", dt3)
     ical = vevent.to_ical()
 
-    assert b'RDATE;TZID=Europe/Vienna:20130101T000000,20130102T000000' in ical
-    assert b'EXDATE;TZID=Europe/Vienna:20130103T000000' in ical
+    assert b"RDATE;TZID=Europe/Vienna:20130101T000000,20130102T000000" in ical
+    assert b"EXDATE;TZID=Europe/Vienna:20130103T000000" in ical
diff -pruN 6.0.1-3/src/icalendar/tests/prop/test_unit.py 6.3.1-1/src/icalendar/tests/prop/test_unit.py
--- 6.0.1-3/src/icalendar/tests/prop/test_unit.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/prop/test_unit.py	2025-05-20 07:31:39.000000000 +0000
@@ -1,118 +1,112 @@
-from datetime import date
-from datetime import datetime
-from datetime import time
-from datetime import timedelta
-from icalendar.parser import Parameters
 import unittest
+from datetime import date, datetime, time, timedelta
 
+from icalendar.parser import Parameters
 
-class TestProp(unittest.TestCase):
 
+class TestProp(unittest.TestCase):
     def test_prop_vFloat(self):
         from icalendar.prop import vFloat
-        self.assertEqual(vFloat(1.0).to_ical(), b'1.0')
-        self.assertEqual(vFloat.from_ical('42'), 42.0)
-        self.assertEqual(vFloat(42).to_ical(), b'42.0')
-        self.assertRaises(ValueError, vFloat.from_ical, '1s3')
+
+        self.assertEqual(vFloat(1.0).to_ical(), b"1.0")
+        self.assertEqual(vFloat.from_ical("42"), 42.0)
+        self.assertEqual(vFloat(42).to_ical(), b"42.0")
+        self.assertRaises(ValueError, vFloat.from_ical, "1s3")
 
     def test_prop_vInt(self):
         from icalendar.prop import vInt
-        self.assertEqual(vInt(42).to_ical(), b'42')
-        self.assertEqual(vInt.from_ical('13'), 13)
-        self.assertRaises(ValueError, vInt.from_ical, '1s3')
+
+        self.assertEqual(vInt(42).to_ical(), b"42")
+        self.assertEqual(vInt.from_ical("13"), 13)
+        self.assertRaises(ValueError, vInt.from_ical, "1s3")
 
     def test_prop_vDDDLists(self):
         from icalendar.prop import vDDDLists
 
-        dt_list = vDDDLists.from_ical('19960402T010000Z')
-        self.assertTrue(isinstance(dt_list, list))
+        dt_list = vDDDLists.from_ical("19960402T010000Z")
+        self.assertIsInstance(dt_list, list)
         self.assertEqual(len(dt_list), 1)
-        self.assertTrue(isinstance(dt_list[0], datetime))
-        self.assertEqual(str(dt_list[0]), '1996-04-02 01:00:00+00:00')
+        self.assertIsInstance(dt_list[0], datetime)
+        self.assertEqual(str(dt_list[0]), "1996-04-02 01:00:00+00:00")
 
-        p = '19960402T010000Z,19960403T010000Z,19960404T010000Z'
+        p = "19960402T010000Z,19960403T010000Z,19960404T010000Z"
         dt_list = vDDDLists.from_ical(p)
         self.assertEqual(len(dt_list), 3)
-        self.assertEqual(str(dt_list[0]), '1996-04-02 01:00:00+00:00')
-        self.assertEqual(str(dt_list[2]), '1996-04-04 01:00:00+00:00')
+        self.assertEqual(str(dt_list[0]), "1996-04-02 01:00:00+00:00")
+        self.assertEqual(str(dt_list[2]), "1996-04-04 01:00:00+00:00")
 
         dt_list = vDDDLists([])
-        self.assertEqual(dt_list.to_ical(), b'')
+        self.assertEqual(dt_list.to_ical(), b"")
 
         dt_list = vDDDLists([datetime(2000, 1, 1)])
-        self.assertEqual(dt_list.to_ical(), b'20000101T000000')
+        self.assertEqual(dt_list.to_ical(), b"20000101T000000")
 
         dt_list = vDDDLists([datetime(2000, 1, 1), datetime(2000, 11, 11)])
-        self.assertEqual(dt_list.to_ical(), b'20000101T000000,20001111T000000')
-        
+        self.assertEqual(dt_list.to_ical(), b"20000101T000000,20001111T000000")
+
         instance = vDDDLists([])
-        self.assertFalse(instance == "value")
+        self.assertNotEqual(instance, "value")
 
     def test_prop_vDate(self):
         from icalendar.prop import vDate
 
-        self.assertEqual(vDate(date(2001, 1, 1)).to_ical(), b'20010101')
-        self.assertEqual(vDate(date(1899, 1, 1)).to_ical(), b'18990101')
+        self.assertEqual(vDate(date(2001, 1, 1)).to_ical(), b"20010101")
+        self.assertEqual(vDate(date(1899, 1, 1)).to_ical(), b"18990101")
 
-        self.assertEqual(vDate.from_ical('20010102'), date(2001, 1, 2))
+        self.assertEqual(vDate.from_ical("20010102"), date(2001, 1, 2))
 
-        self.assertRaises(ValueError, vDate, 'd')
-        self.assertRaises(ValueError, vDate.from_ical, '200102')
+        self.assertRaises(ValueError, vDate, "d")
+        self.assertRaises(ValueError, vDate.from_ical, "200102")
 
     def test_prop_vDuration(self):
         from icalendar.prop import vDuration
 
-        self.assertEqual(vDuration(timedelta(11)).to_ical(), b'P11D')
-        self.assertEqual(vDuration(timedelta(-14)).to_ical(), b'-P14D')
-        self.assertEqual(
-            vDuration(timedelta(1, 7384)).to_ical(),
-            b'P1DT2H3M4S'
-        )
-        self.assertEqual(vDuration(timedelta(1, 7380)).to_ical(), b'P1DT2H3M')
-        self.assertEqual(vDuration(timedelta(1, 7200)).to_ical(), b'P1DT2H')
-        self.assertEqual(vDuration(timedelta(0, 7200)).to_ical(), b'PT2H')
-        self.assertEqual(vDuration(timedelta(0, 7384)).to_ical(), b'PT2H3M4S')
-        self.assertEqual(vDuration(timedelta(0, 184)).to_ical(), b'PT3M4S')
-        self.assertEqual(vDuration(timedelta(0, 22)).to_ical(), b'PT22S')
-        self.assertEqual(vDuration(timedelta(0, 3622)).to_ical(), b'PT1H0M22S')
-        self.assertEqual(vDuration(timedelta(days=1, hours=5)).to_ical(),
-                         b'P1DT5H')
-        self.assertEqual(vDuration(timedelta(hours=-5)).to_ical(), b'-PT5H')
-        self.assertEqual(vDuration(timedelta(days=-1, hours=-5)).to_ical(),
-                         b'-P1DT5H')
+        self.assertEqual(vDuration(timedelta(11)).to_ical(), b"P11D")
+        self.assertEqual(vDuration(timedelta(-14)).to_ical(), b"-P14D")
+        self.assertEqual(vDuration(timedelta(1, 7384)).to_ical(), b"P1DT2H3M4S")
+        self.assertEqual(vDuration(timedelta(1, 7380)).to_ical(), b"P1DT2H3M")
+        self.assertEqual(vDuration(timedelta(1, 7200)).to_ical(), b"P1DT2H")
+        self.assertEqual(vDuration(timedelta(0, 7200)).to_ical(), b"PT2H")
+        self.assertEqual(vDuration(timedelta(0, 7384)).to_ical(), b"PT2H3M4S")
+        self.assertEqual(vDuration(timedelta(0, 184)).to_ical(), b"PT3M4S")
+        self.assertEqual(vDuration(timedelta(0, 22)).to_ical(), b"PT22S")
+        self.assertEqual(vDuration(timedelta(0, 3622)).to_ical(), b"PT1H0M22S")
+        self.assertEqual(vDuration(timedelta(days=1, hours=5)).to_ical(), b"P1DT5H")
+        self.assertEqual(vDuration(timedelta(hours=-5)).to_ical(), b"-PT5H")
+        self.assertEqual(vDuration(timedelta(days=-1, hours=-5)).to_ical(), b"-P1DT5H")
 
         # How does the parsing work?
-        self.assertEqual(vDuration.from_ical('PT1H0M22S'), timedelta(0, 3622))
+        self.assertEqual(vDuration.from_ical("PT1H0M22S"), timedelta(0, 3622))
 
-        self.assertRaises(ValueError, vDuration.from_ical, 'kox')
+        self.assertRaises(ValueError, vDuration.from_ical, "kox")
 
-        self.assertEqual(vDuration.from_ical('-P14D'), timedelta(-14))
+        self.assertEqual(vDuration.from_ical("-P14D"), timedelta(-14))
 
         self.assertRaises(ValueError, vDuration, 11)
 
         # calling to_ical twice should result in same output
         duration = vDuration(timedelta(days=-1, hours=-5))
-        self.assertEqual(duration.to_ical(), b'-P1DT5H')
-        self.assertEqual(duration.to_ical(), b'-P1DT5H')
+        self.assertEqual(duration.to_ical(), b"-P1DT5H")
+        self.assertEqual(duration.to_ical(), b"-P1DT5H")
 
     def test_prop_vWeekday(self):
         from icalendar.prop import vWeekday
 
-        self.assertEqual(vWeekday('mo').to_ical(), b'MO')
-        self.assertRaises(ValueError, vWeekday, 'erwer')
-        self.assertEqual(vWeekday.from_ical('mo'), 'MO')
-        self.assertEqual(vWeekday.from_ical('+3mo'), '+3MO')
-        self.assertRaises(ValueError, vWeekday.from_ical, 'Saturday')
-        self.assertEqual(vWeekday('+mo').to_ical(), b'+MO')
-        self.assertEqual(vWeekday('+3mo').to_ical(), b'+3MO')
-        self.assertEqual(vWeekday('-tu').to_ical(), b'-TU')
+        self.assertEqual(vWeekday("mo").to_ical(), b"MO")
+        self.assertRaises(ValueError, vWeekday, "erwer")
+        self.assertEqual(vWeekday.from_ical("mo"), "MO")
+        self.assertEqual(vWeekday.from_ical("+3mo"), "+3MO")
+        self.assertRaises(ValueError, vWeekday.from_ical, "Saturday")
+        self.assertEqual(vWeekday("+mo").to_ical(), b"+MO")
+        self.assertEqual(vWeekday("+3mo").to_ical(), b"+3MO")
+        self.assertEqual(vWeekday("-tu").to_ical(), b"-TU")
 
     def test_prop_vFrequency(self):
         from icalendar.prop import vFrequency
 
-        self.assertRaises(ValueError, vFrequency, 'bad test')
-        self.assertEqual(vFrequency('daily').to_ical(), b'DAILY')
-        self.assertEqual(vFrequency('daily').from_ical('MONTHLY'), 'MONTHLY')
+        self.assertRaises(ValueError, vFrequency, "bad test")
+        self.assertEqual(vFrequency("daily").to_ical(), b"DAILY")
+        self.assertEqual(vFrequency("daily").from_ical("MONTHLY"), "MONTHLY")
         self.assertRaises(ValueError, vFrequency.from_ical, 234)
 
     def test_prop_vRecur(self):
@@ -121,123 +115,117 @@ class TestProp(unittest.TestCase):
         # Let's see how close we can get to one from the rfc:
         # FREQ=YEARLY;INTERVAL=2;BYMONTH=1;BYDAY=SU;BYHOUR=8,9;BYMINUTE=30
 
-        r = dict({'freq': 'yearly', 'interval': 2})
-        r.update({
-            'bymonth': 1,
-            'byday': 'su',
-            'byhour': [8, 9],
-            'byminute': 30
-        })
+        r = dict({"freq": "yearly", "interval": 2})
+        r.update({"bymonth": 1, "byday": "su", "byhour": [8, 9], "byminute": 30})
         self.assertEqual(
             vRecur(r).to_ical(),
-            b'FREQ=YEARLY;INTERVAL=2;BYMINUTE=30;BYHOUR=8,9;BYDAY=SU;BYMONTH=1'
+            b"FREQ=YEARLY;INTERVAL=2;BYMINUTE=30;BYHOUR=8,9;BYDAY=SU;BYMONTH=1",
         )
 
-        r = vRecur(FREQ='yearly', INTERVAL=2)
-        r.update({
-            'BYMONTH': 1,
-            'BYDAY': 'su',
-            'BYHOUR': [8, 9],
-            'BYMINUTE': 30,
-        })
+        r = vRecur(FREQ="yearly", INTERVAL=2)
+        r.update(
+            {
+                "BYMONTH": 1,
+                "BYDAY": "su",
+                "BYHOUR": [8, 9],
+                "BYMINUTE": 30,
+            }
+        )
         self.assertEqual(
             r.to_ical(),
-            b'FREQ=YEARLY;INTERVAL=2;BYMINUTE=30;BYHOUR=8,9;BYDAY=SU;BYMONTH=1'
+            b"FREQ=YEARLY;INTERVAL=2;BYMINUTE=30;BYHOUR=8,9;BYDAY=SU;BYMONTH=1",
         )
 
-        r = vRecur(freq='DAILY', count=10)
-        r['bysecond'] = [0, 15, 30, 45]
-        self.assertEqual(r.to_ical(),
-                         b'FREQ=DAILY;COUNT=10;BYSECOND=0,15,30,45')
+        r = vRecur(freq="DAILY", count=10)
+        r["bysecond"] = [0, 15, 30, 45]
+        self.assertEqual(r.to_ical(), b"FREQ=DAILY;COUNT=10;BYSECOND=0,15,30,45")
 
-        r = vRecur(freq='DAILY', until=datetime(2005, 1, 1, 12, 0, 0))
-        self.assertEqual(r.to_ical(), b'FREQ=DAILY;UNTIL=20050101T120000')
+        r = vRecur(freq="DAILY", until=datetime(2005, 1, 1, 12, 0, 0))
+        self.assertEqual(r.to_ical(), b"FREQ=DAILY;UNTIL=20050101T120000")
 
         # How do we fare with regards to parsing?
-        r = vRecur.from_ical('FREQ=DAILY;INTERVAL=2;COUNT=10')
-        self.assertEqual(r,
-                         {'COUNT': [10], 'FREQ': ['DAILY'], 'INTERVAL': [2]})
-        self.assertEqual(
-            vRecur(r).to_ical(),
-            b'FREQ=DAILY;COUNT=10;INTERVAL=2'
-        )
+        r = vRecur.from_ical("FREQ=DAILY;INTERVAL=2;COUNT=10")
+        self.assertEqual(r, {"COUNT": [10], "FREQ": ["DAILY"], "INTERVAL": [2]})
+        self.assertEqual(vRecur(r).to_ical(), b"FREQ=DAILY;COUNT=10;INTERVAL=2")
 
-        r = vRecur.from_ical('FREQ=YEARLY;INTERVAL=2;BYMONTH=1;BYDAY=-SU;'
-                             'BYHOUR=8,9;BYMINUTE=30')
+        r = vRecur.from_ical(
+            "FREQ=YEARLY;INTERVAL=2;BYMONTH=1;BYDAY=-SU;BYHOUR=8,9;BYMINUTE=30"
+        )
         self.assertEqual(
             r,
-            {'BYHOUR': [8, 9], 'BYDAY': ['-SU'], 'BYMINUTE': [30],
-             'BYMONTH': [1], 'FREQ': ['YEARLY'], 'INTERVAL': [2]}
+            {
+                "BYHOUR": [8, 9],
+                "BYDAY": ["-SU"],
+                "BYMINUTE": [30],
+                "BYMONTH": [1],
+                "FREQ": ["YEARLY"],
+                "INTERVAL": [2],
+            },
         )
 
         self.assertEqual(
             vRecur(r).to_ical(),
-            b'FREQ=YEARLY;INTERVAL=2;BYMINUTE=30;BYHOUR=8,9;BYDAY=-SU;'
-            b'BYMONTH=1'
+            b"FREQ=YEARLY;INTERVAL=2;BYMINUTE=30;BYHOUR=8,9;BYDAY=-SU;BYMONTH=1",
         )
 
-        r = vRecur.from_ical('FREQ=WEEKLY;INTERVAL=1;BYWEEKDAY=TH')
+        r = vRecur.from_ical("FREQ=WEEKLY;INTERVAL=1;BYWEEKDAY=TH")
 
-        self.assertEqual(
-            r,
-            {'FREQ': ['WEEKLY'], 'INTERVAL': [1], 'BYWEEKDAY': ['TH']}
-        )
+        self.assertEqual(r, {"FREQ": ["WEEKLY"], "INTERVAL": [1], "BYWEEKDAY": ["TH"]})
 
-        self.assertEqual(
-            vRecur(r).to_ical(),
-            b'FREQ=WEEKLY;INTERVAL=1;BYWEEKDAY=TH'
-        )
+        self.assertEqual(vRecur(r).to_ical(), b"FREQ=WEEKLY;INTERVAL=1;BYWEEKDAY=TH")
 
         # Some examples from the spec
-        r = vRecur.from_ical('FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-1')
-        self.assertEqual(vRecur(r).to_ical(),
-                         b'FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-1')
+        r = vRecur.from_ical("FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-1")
+        self.assertEqual(
+            vRecur(r).to_ical(), b"FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-1"
+        )
 
-        p = 'FREQ=YEARLY;INTERVAL=2;BYMONTH=1;BYDAY=SU;BYHOUR=8,9;BYMINUTE=30'
+        p = "FREQ=YEARLY;INTERVAL=2;BYMONTH=1;BYDAY=SU;BYHOUR=8,9;BYMINUTE=30"
         r = vRecur.from_ical(p)
         self.assertEqual(
             vRecur(r).to_ical(),
-            b'FREQ=YEARLY;INTERVAL=2;BYMINUTE=30;BYHOUR=8,9;BYDAY=SU;BYMONTH=1'
+            b"FREQ=YEARLY;INTERVAL=2;BYMINUTE=30;BYHOUR=8,9;BYDAY=SU;BYMONTH=1",
         )
 
         # and some errors
-        self.assertRaises(ValueError, vRecur.from_ical, 'BYDAY=12')
+        self.assertRaises(ValueError, vRecur.from_ical, "BYDAY=12")
 
         # when key is not RFC-compliant, parse it as vText
-        r = vRecur.from_ical('FREQ=MONTHLY;BYOTHER=TEXT;BYEASTER=-3')
-        self.assertEqual(vRecur(r).to_ical(),
-                         b'FREQ=MONTHLY;BYEASTER=-3;BYOTHER=TEXT')
+        r = vRecur.from_ical("FREQ=MONTHLY;BYOTHER=TEXT;BYEASTER=-3")
+        self.assertEqual(vRecur(r).to_ical(), b"FREQ=MONTHLY;BYEASTER=-3;BYOTHER=TEXT")
 
     def test_prop_vText(self):
         from icalendar.prop import vText
 
-        self.assertEqual(vText('Simple text').to_ical(), b'Simple text')
+        self.assertEqual(vText("Simple text").to_ical(), b"Simple text")
 
         # Escaped text
-        t = vText('Text ; with escaped, chars')
-        self.assertEqual(t.to_ical(), b'Text \\; with escaped\\, chars')
+        t = vText("Text ; with escaped, chars")
+        self.assertEqual(t.to_ical(), b"Text \\; with escaped\\, chars")
 
         # Escaped newlines
-        self.assertEqual(vText('Text with escaped\\N chars').to_ical(),
-                         b'Text with escaped\\n chars')
+        self.assertEqual(
+            vText("Text with escaped\\N chars").to_ical(), b"Text with escaped\\n chars"
+        )
 
         # If you pass a unicode object, it will be utf-8 encoded. As this is
         # the (only) standard that RFC 5545 support.
-        t = vText('international chars \xe4\xf6\xfc')
-        self.assertEqual(t.to_ical(),
-                         b'international chars \xc3\xa4\xc3\xb6\xc3\xbc')
+        t = vText("international chars \xe4\xf6\xfc")
+        self.assertEqual(t.to_ical(), b"international chars \xc3\xa4\xc3\xb6\xc3\xbc")
 
         # and parsing?
-        self.assertEqual(vText.from_ical('Text \\; with escaped\\, chars'),
-                         'Text ; with escaped, chars')
+        self.assertEqual(
+            vText.from_ical("Text \\; with escaped\\, chars"),
+            "Text ; with escaped, chars",
+        )
 
-        t = vText.from_ical('A string with\\; some\\\\ characters in\\it')
+        t = vText.from_ical("A string with\\; some\\\\ characters in\\it")
         self.assertEqual(t, "A string with; some\\ characters in\\it")
 
         # We are forgiving to utf-8 encoding errors:
         # We intentionally use a string with unexpected encoding
         #
-        self.assertEqual(vText.from_ical(b'Ol\xe9'), 'Ol\ufffd')
+        self.assertEqual(vText.from_ical(b"Ol\xe9"), "Ol\ufffd")
 
         # Notice how accented E character, encoded with latin-1, got replaced
         # with the official U+FFFD REPLACEMENT CHARACTER.
@@ -245,100 +233,96 @@ class TestProp(unittest.TestCase):
     def test_prop_vTime(self):
         from icalendar.prop import vTime
 
-        self.assertEqual(vTime(12, 30, 0).to_ical(), '123000')
-        self.assertEqual(vTime.from_ical('123000'), time(12, 30))
+        self.assertEqual(vTime(12, 30, 0).to_ical(), "123000")
+        self.assertEqual(vTime.from_ical("123000"), time(12, 30))
 
         # We should also fail, right?
-        self.assertRaises(ValueError, vTime.from_ical, '263000')
+        self.assertRaises(ValueError, vTime.from_ical, "263000")
 
-        self.assertRaises(ValueError, vTime, '263000')
+        self.assertRaises(ValueError, vTime, "263000")
 
     def test_prop_vUri(self):
         from icalendar.prop import vUri
 
-        self.assertEqual(vUri('http://www.example.com/').to_ical(),
-                         b'http://www.example.com/')
-        self.assertEqual(vUri.from_ical('http://www.example.com/'),
-                         'http://www.example.com/')
+        self.assertEqual(
+            vUri("http://www.example.com/").to_ical(), b"http://www.example.com/"
+        )
+        self.assertEqual(
+            vUri.from_ical("http://www.example.com/"), "http://www.example.com/"
+        )
 
     def test_prop_vGeo(self):
         from icalendar.prop import vGeo
 
         # Pass a list
-        self.assertEqual(vGeo([1.2, 3.0]).to_ical(), '1.2;3.0')
+        self.assertEqual(vGeo([1.2, 3.0]).to_ical(), "1.2;3.0")
 
         # Pass a tuple
-        self.assertEqual(vGeo((1.2, 3.0)).to_ical(), '1.2;3.0')
+        self.assertEqual(vGeo((1.2, 3.0)).to_ical(), "1.2;3.0")
 
-        g = vGeo.from_ical('37.386013;-122.082932')
-        self.assertEqual(g, (float('37.386013'), float('-122.082932')))
+        g = vGeo.from_ical("37.386013;-122.082932")
+        self.assertEqual(g, (float("37.386013"), float("-122.082932")))
 
-        self.assertEqual(vGeo(g).to_ical(), '37.386013;-122.082932')
+        self.assertEqual(vGeo(g).to_ical(), "37.386013;-122.082932")
 
-        self.assertRaises(ValueError, vGeo, 'g')
-        self.assertRaises(ValueError, vGeo.from_ical, '1s3;1s3')
+        self.assertRaises(ValueError, vGeo, "g")
+        self.assertRaises(ValueError, vGeo.from_ical, "1s3;1s3")
 
     def test_prop_vUTCOffset(self):
         from icalendar.prop import vUTCOffset
 
-        self.assertEqual(vUTCOffset(timedelta(hours=2)).to_ical(), '+0200')
+        self.assertEqual(vUTCOffset(timedelta(hours=2)).to_ical(), "+0200")
 
-        self.assertEqual(vUTCOffset(timedelta(hours=-5)).to_ical(), '-0500')
+        self.assertEqual(vUTCOffset(timedelta(hours=-5)).to_ical(), "-0500")
 
-        self.assertEqual(vUTCOffset(timedelta()).to_ical(), '+0000')
+        self.assertEqual(vUTCOffset(timedelta()).to_ical(), "+0000")
 
-        self.assertEqual(vUTCOffset(timedelta(minutes=-30)).to_ical(),
-                         '-0030')
+        self.assertEqual(vUTCOffset(timedelta(minutes=-30)).to_ical(), "-0030")
 
-        self.assertEqual(
-            vUTCOffset(timedelta(hours=2, minutes=-30)).to_ical(),
-            '+0130'
-        )
+        self.assertEqual(vUTCOffset(timedelta(hours=2, minutes=-30)).to_ical(), "+0130")
 
-        self.assertEqual(vUTCOffset(timedelta(hours=1, minutes=30)).to_ical(),
-                         '+0130')
+        self.assertEqual(vUTCOffset(timedelta(hours=1, minutes=30)).to_ical(), "+0130")
 
         # Support seconds
-        self.assertEqual(vUTCOffset(timedelta(hours=1,
-                                              minutes=30,
-                                              seconds=7)).to_ical(), '+013007')
+        self.assertEqual(
+            vUTCOffset(timedelta(hours=1, minutes=30, seconds=7)).to_ical(), "+013007"
+        )
 
         # Parsing
 
-        self.assertEqual(vUTCOffset.from_ical('0000'), timedelta(0))
-        self.assertEqual(vUTCOffset.from_ical('-0030'), timedelta(-1, 84600))
-        self.assertEqual(vUTCOffset.from_ical('+0200'), timedelta(0, 7200))
-        self.assertEqual(vUTCOffset.from_ical('+023040'), timedelta(0, 9040))
+        self.assertEqual(vUTCOffset.from_ical("0000"), timedelta(0))
+        self.assertEqual(vUTCOffset.from_ical("-0030"), timedelta(-1, 84600))
+        self.assertEqual(vUTCOffset.from_ical("+0200"), timedelta(0, 7200))
+        self.assertEqual(vUTCOffset.from_ical("+023040"), timedelta(0, 9040))
 
-        self.assertEqual(vUTCOffset(vUTCOffset.from_ical('+0230')).to_ical(),
-                         '+0230')
+        self.assertEqual(vUTCOffset(vUTCOffset.from_ical("+0230")).to_ical(), "+0230")
 
         # And a few failures
-        self.assertRaises(ValueError, vUTCOffset.from_ical, '+323k')
+        self.assertRaises(ValueError, vUTCOffset.from_ical, "+323k")
 
-        self.assertRaises(ValueError, vUTCOffset.from_ical, '+2400')
+        self.assertRaises(ValueError, vUTCOffset.from_ical, "+2400")
 
-        self.assertRaises(ValueError, vUTCOffset, '0:00:00')
+        self.assertRaises(ValueError, vUTCOffset, "0:00:00")
 
     def test_prop_vInline(self):
         from icalendar.prop import vInline
 
-        self.assertEqual(vInline('Some text'), 'Some text')
-        self.assertEqual(vInline('Some text').to_ical(), b'Some text')
-        self.assertEqual(vInline.from_ical('Some text'), 'Some text')
+        self.assertEqual(vInline("Some text"), "Some text")
+        self.assertEqual(vInline("Some text").to_ical(), b"Some text")
+        self.assertEqual(vInline.from_ical("Some text"), "Some text")
 
-        t2 = vInline('other text')
-        t2.params['cn'] = 'Test Osterone'
+        t2 = vInline("other text")
+        t2.params["cn"] = "Test Osterone"
         self.assertIsInstance(t2.params, Parameters)
-        self.assertEqual(t2.params, {'CN': 'Test Osterone'})
+        self.assertEqual(t2.params, {"CN": "Test Osterone"})
 
     def test_prop_vCategory(self):
         from icalendar.prop import vCategory
 
-        catz = ['cat 1', 'cat 2', 'cat 3']
+        catz = ["cat 1", "cat 2", "cat 3"]
         v_cat = vCategory(catz)
 
-        self.assertEqual(v_cat.to_ical(), b'cat 1,cat 2,cat 3')
+        self.assertEqual(v_cat.to_ical(), b"cat 1,cat 2,cat 3")
         self.assertEqual(vCategory.from_ical(v_cat.to_ical()), catz)
         c = vCategory(vCategory.from_ical("APPOINTMENT,EDUCATION"))
         cats = list(c)
@@ -349,27 +333,31 @@ class TestProp(unittest.TestCase):
 
         # To get a type you can use it like this.
         factory = TypesFactory()
-        datetime_parser = factory['date-time']
-        self.assertEqual(datetime_parser(datetime(2001, 1, 1)).to_ical(),
-                         b'20010101T000000')
+        datetime_parser = factory["date-time"]
+        self.assertEqual(
+            datetime_parser(datetime(2001, 1, 1)).to_ical(), b"20010101T000000"
+        )
 
         # A typical use is when the parser tries to find a content type and use
         # text as the default
-        value = '20050101T123000'
-        value_type = 'date-time'
-        self.assertEqual(factory.get(value_type, 'text').from_ical(value),
-                         datetime(2005, 1, 1, 12, 30))
+        value = "20050101T123000"
+        value_type = "date-time"
+        self.assertEqual(
+            factory.get(value_type, "text").from_ical(value),
+            datetime(2005, 1, 1, 12, 30),
+        )
 
         # It can also be used to directly encode property and parameter values
         self.assertEqual(
-            factory.to_ical('comment', 'by Rasmussen, Max M\xfcller'),
-            b'by Rasmussen\\, Max M\xc3\xbcller'
+            factory.to_ical("comment", "by Rasmussen, Max M\xfcller"),
+            b"by Rasmussen\\, Max M\xc3\xbcller",
         )
-        self.assertEqual(factory.to_ical('priority', 1), b'1')
-        self.assertEqual(factory.to_ical('cn', 'Rasmussen, Max M\xfcller'),
-                         b'Rasmussen\\, Max M\xc3\xbcller')
+        self.assertEqual(factory.to_ical("priority", 1), b"1")
         self.assertEqual(
-            factory.from_ical('cn', b'Rasmussen\\, Max M\xc3\xb8ller'),
-            'Rasmussen, Max M\xf8ller'
+            factory.to_ical("cn", "Rasmussen, Max M\xfcller"),
+            b"Rasmussen\\, Max M\xc3\xbcller",
+        )
+        self.assertEqual(
+            factory.from_ical("cn", b"Rasmussen\\, Max M\xc3\xb8ller"),
+            "Rasmussen, Max M\xf8ller",
         )
-
diff -pruN 6.0.1-3/src/icalendar/tests/prop/test_vBinary.py 6.3.1-1/src/icalendar/tests/prop/test_vBinary.py
--- 6.0.1-3/src/icalendar/tests/prop/test_vBinary.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/prop/test_vBinary.py	2025-05-20 07:31:39.000000000 +0000
@@ -1,4 +1,5 @@
 """Test vBinary"""
+
 import pytest
 
 from icalendar import vBinary
@@ -6,36 +7,39 @@ from icalendar.parser import Parameters
 
 
 def test_text():
-    txt = b'This is gibberish'
-    txt_ical = b'VGhpcyBpcyBnaWJiZXJpc2g='
-    assert (vBinary(txt).to_ical() == txt_ical)
-    assert (vBinary.from_ical(txt_ical) == txt)
+    txt = b"This is gibberish"
+    txt_ical = b"VGhpcyBpcyBnaWJiZXJpc2g="
+    assert vBinary(txt).to_ical() == txt_ical
+    assert vBinary.from_ical(txt_ical) == txt
+
 
 def test_binary():
-    txt = b'Binary data \x13 \x56'
-    txt_ical = b'QmluYXJ5IGRhdGEgEyBW'
-    assert (vBinary(txt).to_ical() == txt_ical)
-    assert (vBinary.from_ical(txt_ical) == txt)
+    txt = b"Binary data \x13 \x56"
+    txt_ical = b"QmluYXJ5IGRhdGEgEyBW"
+    assert vBinary(txt).to_ical() == txt_ical
+    assert vBinary.from_ical(txt_ical) == txt
+
 
 def test_param():
-    assert isinstance(vBinary('txt').params, Parameters)
-    assert (
-        vBinary('txt').params == {'VALUE': 'BINARY', 'ENCODING': 'BASE64'}
-    )
+    assert isinstance(vBinary("txt").params, Parameters)
+    assert vBinary("txt").params == {"VALUE": "BINARY", "ENCODING": "BASE64"}
+
 
 def test_long_data():
     """Long data should not have line breaks, as that would interfere"""
-    txt = b'a' * 99
-    txt_ical = b'YWFh' * 33
-    assert (vBinary(txt).to_ical() == txt_ical)
-    assert (vBinary.from_ical(txt_ical) == txt)
-    
+    txt = b"a" * 99
+    txt_ical = b"YWFh" * 33
+    assert vBinary(txt).to_ical() == txt_ical
+    assert vBinary.from_ical(txt_ical) == txt
+
+
 def test_repr():
     instance = vBinary("value")
     assert repr(instance) == "vBinary(b'dmFsdWU=')"
-    
+
+
 def test_from_ical():
-    with pytest.raises(ValueError, match='Not valid base 64 encoding.'):
+    with pytest.raises(ValueError, match="Not valid base 64 encoding."):
         vBinary.from_ical("value")
-    with pytest.raises(ValueError, match='Not valid base 64 encoding.'):
-        vBinary.from_ical("áèਮ")
\ No newline at end of file
+    with pytest.raises(ValueError, match="Not valid base 64 encoding."):
+        vBinary.from_ical("áèਮ")
diff -pruN 6.0.1-3/src/icalendar/tests/prop/test_vBoolean.py 6.3.1-1/src/icalendar/tests/prop/test_vBoolean.py
--- 6.0.1-3/src/icalendar/tests/prop/test_vBoolean.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/prop/test_vBoolean.py	2025-05-20 07:31:39.000000000 +0000
@@ -1,17 +1,22 @@
-from icalendar.prop import vBoolean
 import pytest
 
+from icalendar.prop import vBoolean
+
+
 def test_true():
-    assert (vBoolean(True).to_ical() == b'TRUE')
+    assert vBoolean(True).to_ical() == b"TRUE"
+
 
 def test_false():
-    assert (vBoolean(0).to_ical() == b'FALSE')
+    assert vBoolean(0).to_ical() == b"FALSE"
+
 
 def test_roundtrip():
-    assert (vBoolean.from_ical(vBoolean(True).to_ical()) == True)
-    assert (vBoolean.from_ical('true') == True)
+    assert vBoolean.from_ical(vBoolean(True).to_ical()) == True
+    assert vBoolean.from_ical("true") == True
+
 
 def test_error():
     """Error: key not exists"""
     with pytest.raises(ValueError):
-        vBoolean.from_ical('ture')
+        vBoolean.from_ical("ture")
diff -pruN 6.0.1-3/src/icalendar/tests/prop/test_vCalAddress.py 6.3.1-1/src/icalendar/tests/prop/test_vCalAddress.py
--- 6.0.1-3/src/icalendar/tests/prop/test_vCalAddress.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/prop/test_vCalAddress.py	2025-05-20 07:31:39.000000000 +0000
@@ -1,9 +1,9 @@
-from icalendar.prop import vCalAddress
 from icalendar.parser import Parameters
+from icalendar.prop import vCalAddress
 
-txt = b'MAILTO:maxm@mxm.dk'
+txt = b"MAILTO:maxm@mxm.dk"
 a = vCalAddress(txt)
-a.params['cn'] = 'Max M'
+a.params["cn"] = "Max M"
 
 
 def test_to_ical():
@@ -11,14 +11,47 @@ def test_to_ical():
 
 
 def test_params():
-    assert isinstance(a.params,  Parameters)
-    assert a.params == {'CN': 'Max M'}
+    assert isinstance(a.params, Parameters)
+    assert a.params == {"CN": "Max M"}
 
 
 def test_from_ical():
-    assert vCalAddress.from_ical(txt) == 'MAILTO:maxm@mxm.dk'
-    
+    assert vCalAddress.from_ical(txt) == "MAILTO:maxm@mxm.dk"
+
 
 def test_repr():
     instance = vCalAddress("value")
-    assert repr(instance) == "vCalAddress('value')"
\ No newline at end of file
+    assert repr(instance) == "vCalAddress('value')"
+
+
+def test_email_malformed():
+    """Sometimes, people forget to add mailto that."""
+    address = vCalAddress("me@you.we")
+    assert address.email == "me@you.we"
+
+
+def test_email_mailto():
+    """Email with a normal mailto link."""
+    address = vCalAddress("mailto:icalendar@email.list")
+    assert address.email == "icalendar@email.list"
+
+
+def test_capital_email():
+    """mailto can be capital letters."""
+    address = vCalAddress("MAILTO:yemaya@posteo.net")
+    assert address.email == "yemaya@posteo.net"
+
+
+def test_name():
+    """We want the name, too!"""
+    address = vCalAddress("MAILTO:yemaya@posteo.net")
+    assert address.name == ""
+    address.params["CN"] = "name!"
+    assert address.name == "name!"
+
+
+def test_set_the_name():
+    address = vCalAddress("MAILTO:yemaya@posteo.net")
+    address.name = "Yemaya :)"
+    assert address.name == "Yemaya :)"
+    assert address.params["CN"] == "Yemaya :)"
diff -pruN 6.0.1-3/src/icalendar/tests/prop/test_vDDDTypes.py 6.3.1-1/src/icalendar/tests/prop/test_vDDDTypes.py
--- 6.0.1-3/src/icalendar/tests/prop/test_vDDDTypes.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/prop/test_vDDDTypes.py	2025-05-20 07:31:39.000000000 +0000
@@ -1,30 +1,35 @@
-from icalendar.prop import vDDDTypes
-from datetime import date, datetime, timedelta, time
+from datetime import date, datetime, time, timedelta
+
 import pytest
 
+from icalendar.prop import vDDDTypes
+
 
 def test_instance():
-    assert isinstance(vDDDTypes.from_ical('20010101T123000'), datetime)
-    assert isinstance(vDDDTypes.from_ical('20010101'), date)
+    assert isinstance(vDDDTypes.from_ical("20010101T123000"), datetime)
+    assert isinstance(vDDDTypes.from_ical("20010101"), date)
 
 
 def test_datetime_with_timezone(tzp):
-    assert vDDDTypes.from_ical('20010101T123000Z') == \
-                     tzp.localize_utc(datetime(2001, 1, 1, 12, 30))
+    assert vDDDTypes.from_ical("20010101T123000Z") == tzp.localize_utc(
+        datetime(2001, 1, 1, 12, 30)
+    )
 
 
 def test_timedelta():
-    assert vDDDTypes.from_ical('P31D') == timedelta(31)
-    assert vDDDTypes.from_ical('-P31D') == timedelta(-31)
+    assert vDDDTypes.from_ical("P31D") == timedelta(31)
+    assert vDDDTypes.from_ical("-P31D") == timedelta(-31)
 
 
 def test_bad_input():
     with pytest.raises(ValueError):
         vDDDTypes(42)
 
+
 def test_time_from_string():
-    assert vDDDTypes.from_ical('123000') == time(12, 30)
-    assert isinstance(vDDDTypes.from_ical('123000'), time)
+    assert vDDDTypes.from_ical("123000") == time(12, 30)
+    assert isinstance(vDDDTypes.from_ical("123000"), time)
+
 
 def test_invalid_period_to_ical():
     invalid_period = (datetime(2000, 1, 1), datetime(2000, 1, 2), datetime(2000, 1, 2))
diff -pruN 6.0.1-3/src/icalendar/tests/prop/test_vDatetime.py 6.3.1-1/src/icalendar/tests/prop/test_vDatetime.py
--- 6.0.1-3/src/icalendar/tests/prop/test_vDatetime.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/prop/test_vDatetime.py	2025-05-20 07:31:39.000000000 +0000
@@ -1,42 +1,47 @@
-from icalendar.prop import vDatetime
-import pytest
 from datetime import datetime
 
+import pytest
+
+from icalendar.prop import vDatetime
+
 
 def test_to_ical():
-    assert vDatetime(datetime(2001, 1, 1, 12, 30, 0)).to_ical() == b'20010101T123000'
+    assert vDatetime(datetime(2001, 1, 1, 12, 30, 0)).to_ical() == b"20010101T123000"
+
 
 def test_from_ical():
-    assert vDatetime.from_ical('20000101T120000') == datetime(2000, 1, 1, 12, 0)
-    assert vDatetime.from_ical('20010101T000000') == datetime(2001, 1, 1,  0, 0)
+    assert vDatetime.from_ical("20000101T120000") == datetime(2000, 1, 1, 12, 0)
+    assert vDatetime.from_ical("20010101T000000") == datetime(2001, 1, 1, 0, 0)
+
 
 def test_to_ical_utc(tzp):
     dutc = tzp.localize_utc(datetime(2001, 1, 1, 12, 30, 0))
-    assert vDatetime(dutc).to_ical() == b'20010101T123000Z'
+    assert vDatetime(dutc).to_ical() == b"20010101T123000Z"
+
 
 def test_to_ical_utc_1899(tzp):
     dutc = tzp.localize_utc(datetime(1899, 1, 1, 12, 30, 0))
-    assert vDatetime(dutc).to_ical() == b'18990101T123000Z'
+    assert vDatetime(dutc).to_ical() == b"18990101T123000Z"
 
 
 def test_bad_ical():
     with pytest.raises(ValueError):
-        vDatetime.from_ical('20010101T000000A')
+        vDatetime.from_ical("20010101T000000A")
 
 
 def test_roundtrip():
-    utc = vDatetime.from_ical('20010101T000000Z')
-    assert vDatetime(utc).to_ical() == b'20010101T000000Z'
+    utc = vDatetime.from_ical("20010101T000000Z")
+    assert vDatetime(utc).to_ical() == b"20010101T000000Z"
 
 
 def test_transition(tzp):
     # 1 minute before transition to DST
-    dat = vDatetime.from_ical('20120311T015959', 'America/Denver')
-    assert dat.strftime('%Y%m%d%H%M%S %z') =='20120311015959 -0700'
+    dat = vDatetime.from_ical("20120311T015959", "America/Denver")
+    assert dat.strftime("%Y%m%d%H%M%S %z") == "20120311015959 -0700"
 
     # After transition to DST
-    dat = vDatetime.from_ical('20120311T030000', 'America/Denver')
-    assert dat.strftime('%Y%m%d%H%M%S %z') == '20120311030000 -0600'
+    dat = vDatetime.from_ical("20120311T030000", "America/Denver")
+    assert dat.strftime("%Y%m%d%H%M%S %z") == "20120311030000 -0600"
 
-    dat = vDatetime.from_ical('20101010T000000', 'Europe/Vienna')
-    assert vDatetime(dat).to_ical() == b'20101010T000000'
+    dat = vDatetime.from_ical("20101010T000000", "Europe/Vienna")
+    assert vDatetime(dat).to_ical() == b"20101010T000000"
diff -pruN 6.0.1-3/src/icalendar/tests/prop/test_vPeriod.py 6.3.1-1/src/icalendar/tests/prop/test_vPeriod.py
--- 6.0.1-3/src/icalendar/tests/prop/test_vPeriod.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/prop/test_vPeriod.py	2025-05-20 07:31:39.000000000 +0000
@@ -1,63 +1,61 @@
 import unittest
-from icalendar.prop import vPeriod
 from datetime import datetime, timedelta
+
 import pytest
 
+from icalendar.prop import vPeriod
 
-class TestProp(unittest.TestCase):
 
+class TestProp(unittest.TestCase):
     def test_one_day(self):
         # One day in exact datetimes
         per = (datetime(2000, 1, 1), datetime(2000, 1, 2))
-        self.assertEqual(vPeriod(per).to_ical(),
-                         b'20000101T000000/20000102T000000')
+        self.assertEqual(vPeriod(per).to_ical(), b"20000101T000000/20000102T000000")
 
         per = (datetime(2000, 1, 1), timedelta(days=31))
-        self.assertEqual(vPeriod(per).to_ical(), b'20000101T000000/P31D')
+        self.assertEqual(vPeriod(per).to_ical(), b"20000101T000000/P31D")
 
     def test_roundtrip(self):
-        p = vPeriod.from_ical('20000101T000000/20000102T000000')
+        p = vPeriod.from_ical("20000101T000000/20000102T000000")
+        self.assertEqual(p, (datetime(2000, 1, 1, 0, 0), datetime(2000, 1, 2, 0, 0)))
+        self.assertEqual(vPeriod(p).to_ical(), b"20000101T000000/20000102T000000")
+
         self.assertEqual(
-            p,
-            (datetime(2000, 1, 1, 0, 0), datetime(2000, 1, 2, 0, 0))
+            vPeriod.from_ical("20000101T000000/P31D"),
+            (datetime(2000, 1, 1, 0, 0), timedelta(31)),
         )
-        self.assertEqual(vPeriod(p).to_ical(),
-                         b'20000101T000000/20000102T000000')
-
-        self.assertEqual(vPeriod.from_ical('20000101T000000/P31D'),
-                         (datetime(2000, 1, 1, 0, 0), timedelta(31)))
 
     def test_round_trip_with_absolute_time(self):
-        p = vPeriod.from_ical('20000101T000000Z/20000102T000000Z')
-        self.assertEqual(vPeriod(p).to_ical(),
-                         b'20000101T000000Z/20000102T000000Z')
+        p = vPeriod.from_ical("20000101T000000Z/20000102T000000Z")
+        self.assertEqual(vPeriod(p).to_ical(), b"20000101T000000Z/20000102T000000Z")
 
     def test_bad_input(self):
-        self.assertRaises(ValueError,
-                          vPeriod.from_ical, '20000101T000000/Psd31D')
+        self.assertRaises(ValueError, vPeriod.from_ical, "20000101T000000/Psd31D")
 
 
 def test_timezoned(tzp):
-    start = tzp.localize(datetime(2000, 1, 1), 'Europe/Copenhagen')
-    end = tzp.localize(datetime(2000, 1, 2), 'Europe/Copenhagen')
+    start = tzp.localize(datetime(2000, 1, 1), "Europe/Copenhagen")
+    end = tzp.localize(datetime(2000, 1, 2), "Europe/Copenhagen")
     per = (start, end)
-    assert vPeriod(per).to_ical() == b'20000101T000000/20000102T000000'
-    assert vPeriod(per).params['TZID'] == 'Europe/Copenhagen'
+    assert vPeriod(per).to_ical() == b"20000101T000000/20000102T000000"
+    assert vPeriod(per).params["TZID"] == "Europe/Copenhagen"
 
 
 def test_timezoned_with_timedelta(tzp):
-    p = vPeriod((tzp.localize(datetime(2000, 1, 1), 'Europe/Copenhagen'), timedelta(days=31)))
-    assert p.to_ical() == b'20000101T000000/P31D'
+    p = vPeriod(
+        (tzp.localize(datetime(2000, 1, 1), "Europe/Copenhagen"), timedelta(days=31))
+    )
+    assert p.to_ical() == b"20000101T000000/P31D"
 
 
 @pytest.mark.parametrize(
     "params",
     [
-        ('20000101T000000', datetime(2000, 1, 2)),
-        (datetime(2000, 1, 1), '20000102T000000'),
+        ("20000101T000000", datetime(2000, 1, 2)),
+        (datetime(2000, 1, 1), "20000102T000000"),
         (datetime(2000, 1, 2), datetime(2000, 1, 1)),
         (datetime(2000, 1, 2), timedelta(-1)),
-    ]
+    ],
 )
 def test_invalid_parameters(params):
     """The parameters are of wrong type or of wrong order."""
diff -pruN 6.0.1-3/src/icalendar/tests/prop/test_vWeekday.py 6.3.1-1/src/icalendar/tests/prop/test_vWeekday.py
--- 6.0.1-3/src/icalendar/tests/prop/test_vWeekday.py	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/prop/test_vWeekday.py	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,27 @@
+import pytest
+
+from icalendar.prop import vWeekday
+
+
+def test_simple():
+    weekday = vWeekday("SU")
+    assert weekday.to_ical() == b"SU"
+    assert weekday.weekday == "SU"
+    assert weekday.relative is None
+
+
+def test_relative():
+    weekday = vWeekday("-1MO")
+    assert weekday.to_ical() == b"-1MO"
+    assert weekday.weekday == "MO"
+    assert weekday.relative == -1
+
+
+def test_roundtrip():
+    assert vWeekday.from_ical(vWeekday("+2TH").to_ical()) == "+2TH"
+
+
+def test_error():
+    """Error: Expected weekday abbrevation, got: \"-100MO\" """
+    with pytest.raises(ValueError):
+        vWeekday.from_ical("-100MO")
diff -pruN 6.0.1-3/src/icalendar/tests/prop/test_windows_to_olson_mapping.py 6.3.1-1/src/icalendar/tests/prop/test_windows_to_olson_mapping.py
--- 6.0.1-3/src/icalendar/tests/prop/test_windows_to_olson_mapping.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/prop/test_windows_to_olson_mapping.py	2025-05-20 07:31:39.000000000 +0000
@@ -1,15 +1,18 @@
 """Test the mappings from windows to olson tzids"""
-from icalendar.timezone.windows_to_olson import WINDOWS_TO_OLSON
+
+from datetime import datetime
+
 import pytest
+
 from icalendar import vDatetime
-from datetime import datetime
+from icalendar.timezone.windows_to_olson import WINDOWS_TO_OLSON
 
 
 def test_windows_timezone(tzp):
     """Test that the timezone is mapped correctly to olson."""
-    dt = vDatetime.from_ical('20170507T181920', 'Eastern Standard Time')
-    expected = tzp.localize(datetime(2017, 5, 7, 18, 19, 20), 'America/New_York')
-    assert dt.tzinfo == dt.tzinfo
+    dt = vDatetime.from_ical("20170507T181920", "Eastern Standard Time")
+    expected = tzp.localize(datetime(2017, 5, 7, 18, 19, 20), "America/New_York")
+    assert dt.tzinfo == expected.tzinfo
     assert dt == expected
 
 
diff -pruN 6.0.1-3/src/icalendar/tests/test_bom_calendar.py 6.3.1-1/src/icalendar/tests/test_bom_calendar.py
--- 6.0.1-3/src/icalendar/tests/test_bom_calendar.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/test_bom_calendar.py	2025-05-20 07:31:39.000000000 +0000
@@ -1,2 +1,4 @@
 def test_bom_calendar(calendars):
-    assert calendars.bom_calendar.walk('VCALENDAR'), "Unable to parse a calendar starting with an Unicode BOM"
+    assert calendars.bom_calendar.walk(
+        "VCALENDAR"
+    ), "Unable to parse a calendar starting with an Unicode BOM"
diff -pruN 6.0.1-3/src/icalendar/tests/test_cli_tool.py 6.3.1-1/src/icalendar/tests/test_cli_tool.py
--- 6.0.1-3/src/icalendar/tests/test_cli_tool.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/test_cli_tool.py	2025-05-20 07:31:39.000000000 +0000
@@ -1,13 +1,14 @@
 import unittest
-
 from datetime import datetime
+
 from icalendar import Calendar, cli
+
 try:
     import zoneinfo
 except ModuleNotFoundError:
     from backports import zoneinfo
 
-INPUT = '''
+INPUT = """
 BEGIN:VCALENDAR
 VERSION:2.0
 CALSCALE:GREGORIAN
@@ -25,7 +26,6 @@ END:VEVENT
 BEGIN:VEVENT
 ORGANIZER:organizer@test.test
 ATTENDEE:attendee1@example.com
-ATTENDEE:attendee2@test.test
 SUMMARY:Test summary
 DTSTART;TZID=Europe/Warsaw:20220820T200000
 DTEND;TZID=Europe/Warsaw:20220820T203000
@@ -39,16 +39,23 @@ DTSTART:20220511
 DURATION:P5D
 END:VEVENT
 END:VCALENDAR
-'''
+"""
+
 
 def local_datetime(dt):
-    return datetime.strptime(dt, "%Y%m%dT%H%M%S").replace(tzinfo=zoneinfo.ZoneInfo("Europe/Warsaw")).astimezone().strftime('%c')
+    return (
+        datetime.strptime(dt, "%Y%m%dT%H%M%S")
+        .replace(tzinfo=zoneinfo.ZoneInfo("Europe/Warsaw"))
+        .astimezone()
+        .strftime("%c")
+    )
+
 
 # datetimes are displayed in the local timezone, so we cannot just hardcode them
-firststart = local_datetime('20220820T103400')
-firstend = local_datetime('20220820T113400')
-secondstart = local_datetime('20220820T200000')
-secondend = local_datetime('20220820T203000')
+firststart = local_datetime("20220820T103400")
+firstend = local_datetime("20220820T113400")
+secondstart = local_datetime("20220820T200000")
+secondend = local_datetime("20220820T203000")
 
 PROPER_OUTPUT = f"""    Organizer: organizer <organizer@test.test>
     Attendees:
@@ -66,7 +73,6 @@ PROPER_OUTPUT = f"""    Organizer: organ
     Organizer: organizer <organizer@test.test>
     Attendees:
      attendee1 <attendee1@example.com>
-     attendee2 <attendee2@test.test>
     Summary    : Test summary
     Starts     : {secondstart}
     End        : {secondend}
@@ -91,15 +97,16 @@ PROPER_OUTPUT = f"""    Organizer: organ
 
 """
 
+
 class CLIToolTest(unittest.TestCase):
     def test_output_is_proper(self):
         self.maxDiff = None
         calendar = Calendar.from_ical(INPUT)
-        output = ''
-        for event in calendar.walk('vevent'):
-            output += cli.view(event) + '\n\n'
+        output = ""
+        for event in calendar.walk("vevent"):
+            output += cli.view(event) + "\n\n"
         self.assertEqual(PROPER_OUTPUT, output)
 
-if __name__ == '__main__':
-    unittest.main()
 
+if __name__ == "__main__":
+    unittest.main()
diff -pruN 6.0.1-3/src/icalendar/tests/test_components_break_on_bad_ics.py 6.3.1-1/src/icalendar/tests/test_components_break_on_bad_ics.py
--- 6.0.1-3/src/icalendar/tests/test_components_break_on_bad_ics.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/test_components_break_on_bad_ics.py	2025-05-20 07:31:39.000000000 +0000
@@ -2,36 +2,47 @@ import pytest
 
 
 def test_ignore_exceptions_on_broken_events_issue_104(events):
-    ''' Issue #104 - line parsing error in a VEVENT
+    """Issue #104 - line parsing error in a VEVENT
     (which has ignore_exceptions). Should mark the event broken
     but not raise an exception.
 
     https://github.com/collective/icalendar/issues/104
-    '''
-    assert events.issue_104_mark_events_broken.errors == [(None, "Content line could not be parsed into parts: 'X': Invalid content line")]
+    """
+    assert events.issue_104_mark_events_broken.errors == [
+        (None, "Content line could not be parsed into parts: 'X': Invalid content line")
+    ]
+
 
 def test_dont_ignore_exceptions_on_broken_calendars_issue_104(calendars):
-    '''Issue #104 - line parsing error in a VCALENDAR
+    """Issue #104 - line parsing error in a VCALENDAR
     (which doesn't have ignore_exceptions). Should raise an exception.
-    '''
+    """
     with pytest.raises(ValueError):
         calendars.issue_104_broken_calendar
 
+
 def test_rdate_dosent_become_none_on_invalid_input_issue_464(events):
-    '''Issue #464 - [BUG] RDATE can become None if value is invalid
+    """Issue #464 - [BUG] RDATE can become None if value is invalid
     https://github.com/collective/icalendar/issues/464
-    '''
-    assert ('RDATE', 'Expected period format, got: 199709T180000Z/PT5H30M') in events.issue_464_invalid_rdate.errors
-    assert b'RDATE:None' not in events.issue_464_invalid_rdate.to_ical()
-
-@pytest.mark.parametrize('calendar_name', [
-    'big_bad_calendar',
-    'small_bad_calendar',
-    'multiple_calendar_components',
-    'pr_480_summary_with_colon',
-])
+    """
+    assert (
+        "RDATE",
+        "Expected period format, got: 199709T180000Z/PT5H30M",
+    ) in events.issue_464_invalid_rdate.errors
+    assert b"RDATE:None" not in events.issue_464_invalid_rdate.to_ical()
+
+
+@pytest.mark.parametrize(
+    "calendar_name",
+    [
+        "big_bad_calendar",
+        "small_bad_calendar",
+        "multiple_calendar_components",
+        "pr_480_summary_with_colon",
+    ],
+)
 def test_error_message_doesnt_get_too_big(calendars, calendar_name):
     with pytest.raises(ValueError) as exception:
         calendars[calendar_name]
     # Ignore part before first : for the test.
-    assert len(str(exception).split(': ', 1)[1]) <= 100
+    assert len(str(exception).split(": ", 1)[1]) <= 100
diff -pruN 6.0.1-3/src/icalendar/tests/test_encoding.py 6.3.1-1/src/icalendar/tests/test_encoding.py
--- 6.0.1-3/src/icalendar/tests/test_encoding.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/test_encoding.py	2025-05-20 07:31:39.000000000 +0000
@@ -1,71 +1,98 @@
-import pytest
 import datetime
 
-@pytest.mark.parametrize('field, expected_value', [
-    ('PRODID', '-//Plönë.org//NONSGML plone.app.event//EN'),
-    ('X-WR-CALDESC', 'test non ascii: äöü ÄÖÜ €'),
-])
+import pytest
+
+
+@pytest.mark.parametrize(
+    ("field", "expected_value"),
+    [
+        ("PRODID", "-//Plönë.org//NONSGML plone.app.event//EN"),
+        ("X-WR-CALDESC", "test non ascii: äöü ÄÖÜ €"),
+    ],
+)
 def test_calendar_from_ical_respects_unicode(field, expected_value, calendars):
     cal = calendars.calendar_with_unicode
-    assert cal[field].to_ical().decode('utf-8') == expected_value
+    assert cal[field].to_ical().decode("utf-8") == expected_value
+
 
-@pytest.mark.parametrize('test_input, field, expected_value', [
-    ('event_with_unicode_fields', 'SUMMARY', 'Non-ASCII Test: ÄÖÜ äöü €'),
-    ('event_with_unicode_fields', 'DESCRIPTION', 'icalendar should be able to handle non-ascii: €äüöÄÜÖ.'),
-    ('event_with_unicode_fields', 'LOCATION', 'Tribstrül'),
-    # Non-unicode characters in summary
-    # https://github.com/collective/icalendar/issues/64
-    ('issue_64_event_with_non_ascii_summary', 'SUMMARY', 'åäö'),
-    # Unicode characters in summary
-    ('issue_64_event_with_ascii_summary', 'SUMMARY', 'abcdef'),
-])
+@pytest.mark.parametrize(
+    ("test_input", "field", "expected_value"),
+    [
+        ("event_with_unicode_fields", "SUMMARY", "Non-ASCII Test: ÄÖÜ äöü €"),
+        (
+            "event_with_unicode_fields",
+            "DESCRIPTION",
+            "icalendar should be able to handle non-ascii: €äüöÄÜÖ.",
+        ),
+        ("event_with_unicode_fields", "LOCATION", "Tribstrül"),
+        # Non-unicode characters in summary
+        # https://github.com/collective/icalendar/issues/64
+        ("issue_64_event_with_non_ascii_summary", "SUMMARY", "åäö"),
+        # Unicode characters in summary
+        ("issue_64_event_with_ascii_summary", "SUMMARY", "abcdef"),
+    ],
+)
 def test_event_from_ical_respects_unicode(test_input, field, expected_value, events):
     event = events[test_input]
-    assert event[field].to_ical().decode('utf-8') == expected_value
+    assert event[field].to_ical().decode("utf-8") == expected_value
+
 
-@pytest.mark.parametrize('test_input, expected_output', [
-    # chokes on umlauts in ORGANIZER
-    # https://github.com/collective/icalendar/issues/101
-    ('issue_101_icalendar_chokes_on_umlauts_in_organizer', 'acme, ädmin'),
-    ('event_with_unicode_organizer', 'Джон Доу'),
-])
+@pytest.mark.parametrize(
+    ("test_input", "expected_output"),
+    [
+        # chokes on umlauts in ORGANIZER
+        # https://github.com/collective/icalendar/issues/101
+        ("issue_101_icalendar_chokes_on_umlauts_in_organizer", "acme, ädmin"),
+        ("event_with_unicode_organizer", "Джон Доу"),
+    ],
+)
 def test_events_parameter_unicoded(events, test_input, expected_output):
-    assert events[test_input]['ORGANIZER'].params['CN'] == expected_output
+    assert events[test_input]["ORGANIZER"].params["CN"] == expected_output
+
 
 def test_parses_event_with_non_ascii_tzid_issue_237(calendars, in_timezone):
     """Issue #237 - Fail to parse timezone with non-ascii TZID
     see https://github.com/collective/icalendar/issues/237
     """
-    start = calendars.issue_237_fail_to_parse_timezone_with_non_ascii_tzid.walk('VEVENT')[0].decoded('DTSTART')
-    expected = in_timezone(datetime.datetime(2017, 5, 11, 13, 30), 'America/Sao_Paulo')
+    start = calendars.issue_237_fail_to_parse_timezone_with_non_ascii_tzid.walk(
+        "VEVENT"
+    )[0].decoded("DTSTART")
+    expected = in_timezone(datetime.datetime(2017, 5, 11, 13, 30), "America/Sao_Paulo")
     assert not calendars.issue_237_fail_to_parse_timezone_with_non_ascii_tzid.errors
     assert start == expected
 
+
 def test_parses_timezone_with_non_ascii_tzid_issue_237(timezones):
     """Issue #237 - Fail to parse timezone with non-ascii TZID
     see https://github.com/collective/icalendar/issues/237
     """
-    assert timezones.issue_237_brazilia_standard['tzid'] == '(UTC-03:00) Brasília'
+    assert timezones.issue_237_brazilia_standard["tzid"] == "(UTC-03:00) Brasília"
+
 
-@pytest.mark.parametrize('timezone_name', ['standard', 'daylight'])
+@pytest.mark.parametrize("timezone_name", ["standard", "daylight"])
 def test_parses_timezone_with_non_ascii_tzname_issue_273(timezones, timezone_name):
     """Issue #237 - Fail to parse timezone with non-ascii TZID
     see https://github.com/collective/icalendar/issues/237
     """
-    assert timezones.issue_237_brazilia_standard.walk(timezone_name)[0]['TZNAME'] == f'Brasília {timezone_name}'
+    assert (
+        timezones.issue_237_brazilia_standard.walk(timezone_name)[0]["TZNAME"]
+        == f"Brasília {timezone_name}"
+    )
+
 
 def test_broken_property(calendars):
     """
     Test if error messages are encoded properly.
     """
-    for event in calendars.broken_ical.walk('vevent'):
-        assert len(event.errors) == 1, 'Not the right amount of errors.'
+    for event in calendars.broken_ical.walk("vevent"):
+        assert len(event.errors) == 1, "Not the right amount of errors."
         error = event.errors[0][1]
-        assert error.startswith('Content line could not be parsed into parts')
+        assert error.startswith("Content line could not be parsed into parts")
+
 
 def test_apple_xlocation(calendars):
     """
     Test if we support base64 encoded binary data in parameter values.
     """
-    for event in calendars.x_location.walk('vevent'):
-        assert len(event.errors) == 0, 'Got too many errors'
+    for event in calendars.x_location.walk("vevent"):
+        assert len(event.errors) == 0, "Got too many errors"
diff -pruN 6.0.1-3/src/icalendar/tests/test_equality.py 6.3.1-1/src/icalendar/tests/test_equality.py
--- 6.0.1-3/src/icalendar/tests/test_equality.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/test_equality.py	2025-05-20 07:31:39.000000000 +0000
@@ -1,23 +1,46 @@
 """Test the equality and inequality of components."""
+
+import contextlib
 import copy
+
 try:
-    import pytz
+    from pytz import UnknownTimeZoneError
 except ImportError:
-    pytz = None
-from icalendar.prop import *
-from datetime import datetime, date, time, timedelta
+
+    class UnknownTimeZoneError(Exception):
+        pass
+
+
+from datetime import date, datetime, time, timedelta
+
 import pytest
 
+from icalendar.prop import (
+    vBinary,
+    vBoolean,
+    vCategory,
+    vDate,
+    vDatetime,
+    vDDDLists,
+    vDDDTypes,
+    vDuration,
+    vGeo,
+    vPeriod,
+    vText,
+    vTime,
+)
+
+
 def assert_equal(actual_value, expected_value):
     """Make sure both values are equal"""
     assert actual_value == expected_value
-    assert not actual_value != expected_value
+    assert expected_value == actual_value
 
 
 def assert_not_equal(actual_value, expected_value):
     """Make sure both values are not equal"""
-    assert not actual_value == expected_value
     assert actual_value != expected_value
+    assert expected_value != actual_value
 
 
 def test_parsed_calendars_are_equal_if_parsed_again(ics_file, tzp):
@@ -42,8 +65,10 @@ def test_parsed_calendars_are_equal_if_f
 
 def test_copies_are_equal(ics_file, tzp):
     """Ensure that copies are equal."""
-    copy1 = ics_file.copy(); copy1.subcomponents = ics_file.subcomponents
-    copy2 = ics_file.copy();  copy2.subcomponents = ics_file.subcomponents[:]
+    copy1 = ics_file.copy()
+    copy1.subcomponents = ics_file.subcomponents
+    copy2 = ics_file.copy()
+    copy2.subcomponents = ics_file.subcomponents[:]
     assert_equal(copy1, copy2)
     assert_equal(copy1, ics_file)
     assert_equal(copy2, ics_file)
@@ -56,20 +81,20 @@ def test_copy_does_not_copy_subcomponent
 
 
 def test_deep_copies_are_equal(ics_file, tzp):
-    """Ensure that deep copies are equal."""
-    try:
+    """Ensure that deep copies are equal.
+
+    Ignore errors when a custom time zone is used.
+    This is still covered by the parsing test.
+    """
+    if (
+        ics_file.source_file == "issue_722_timezone_transition_ambiguity.ics"
+        and tzp.uses_zoneinfo()
+    ):
+        pytest.skip("This test fails for now.")
+    with contextlib.suppress(UnknownTimeZoneError):
         assert_equal(copy.deepcopy(ics_file), copy.deepcopy(ics_file))
-    except pytz.UnknownTimeZoneError:
-        # Ignore errors when a custom time zone is used.
-        # This is still covered by the parsing test.
-        pass
-    try:
+    with contextlib.suppress(UnknownTimeZoneError):
         assert_equal(copy.deepcopy(ics_file), ics_file)
-    except pytz.UnknownTimeZoneError:
-        # Ignore errors when a custom time zone is used.
-        # This is still covered by the parsing test.
-        pass
-
 
 
 def test_vGeo():
@@ -80,20 +105,20 @@ def test_vGeo():
 
 
 def test_vBinary():
-    assert_equal(vBinary('asd'), vBinary('asd'))
-    assert_not_equal(vBinary('asdf'), vBinary('asd'))
+    assert_equal(vBinary("asd"), vBinary("asd"))
+    assert_not_equal(vBinary("asdf"), vBinary("asd"))
 
 
 def test_vBoolean():
-    assert_equal(vBoolean.from_ical('TRUE'), vBoolean.from_ical('TRUE'))
-    assert_equal(vBoolean.from_ical('FALSE'), vBoolean.from_ical('FALSE'))
-    assert_not_equal(vBoolean.from_ical('TRUE'), vBoolean.from_ical('FALSE'))
+    assert_equal(vBoolean.from_ical("TRUE"), vBoolean.from_ical("TRUE"))
+    assert_equal(vBoolean.from_ical("FALSE"), vBoolean.from_ical("FALSE"))
+    assert_not_equal(vBoolean.from_ical("TRUE"), vBoolean.from_ical("FALSE"))
 
 
 def test_vCategory():
     assert_equal(vCategory("HELLO"), vCategory("HELLO"))
-    assert_equal(vCategory(["a","b"]), vCategory(["a","b"]))
-    assert_not_equal(vCategory(["a","b"]), vCategory(["a","b", "c"]))
+    assert_equal(vCategory(["a", "b"]), vCategory(["a", "b"]))
+    assert_not_equal(vCategory(["a", "b"]), vCategory(["a", "b", "c"]))
 
 
 def test_vText():
@@ -102,21 +127,33 @@ def test_vText():
 
 
 @pytest.mark.parametrize(
-    "vType,v1,v2",
+    ("vType", "v1", "v2"),
     [
         (vDatetime, datetime(2023, 11, 1, 10, 11), datetime(2023, 11, 1, 10, 10)),
         (vDate, date(2023, 11, 1), date(2023, 10, 31)),
         (vDuration, timedelta(3, 11, 1), timedelta(23, 10, 31)),
-        (vPeriod, (datetime(2023, 11, 1, 10, 11), timedelta(3, 11, 1)), (datetime(2023, 11, 1, 10, 11), timedelta(23, 10, 31))),
-        (vPeriod, (datetime(2023, 11, 1, 10, 1), timedelta(3, 11, 1)), (datetime(2023, 11, 1, 10, 11), timedelta(3, 11, 1))),
-        (vPeriod, (datetime(2023, 11, 1, 10, 1), datetime(2023, 11, 1, 10, 3)), (datetime(2023, 11, 1, 10, 1), datetime(2023, 11, 1, 10, 2))),
+        (
+            vPeriod,
+            (datetime(2023, 11, 1, 10, 11), timedelta(3, 11, 1)),
+            (datetime(2023, 11, 1, 10, 11), timedelta(23, 10, 31)),
+        ),
+        (
+            vPeriod,
+            (datetime(2023, 11, 1, 10, 1), timedelta(3, 11, 1)),
+            (datetime(2023, 11, 1, 10, 11), timedelta(3, 11, 1)),
+        ),
+        (
+            vPeriod,
+            (datetime(2023, 11, 1, 10, 1), datetime(2023, 11, 1, 10, 3)),
+            (datetime(2023, 11, 1, 10, 1), datetime(2023, 11, 1, 10, 2)),
+        ),
         (vTime, time(10, 10, 10), time(10, 10, 11)),
-    ]
+    ],
 )
 @pytest.mark.parametrize("eq", ["==", "!="])
 @pytest.mark.parametrize("cls1", [0, 1])
 @pytest.mark.parametrize("cls2", [0, 1])
-@pytest.mark.parametrize("hash", [lambda x:x, hash])
+@pytest.mark.parametrize("hash", [lambda x: x, hash])
 def test_vDDDTypes_and_others(vType, v1, v2, cls1, cls2, eq, hash):
     """Check equality and inequality."""
     t1 = (vType, vDDDTypes)[cls1]
@@ -124,7 +161,7 @@ def test_vDDDTypes_and_others(vType, v1,
     if eq == "==":
         assert hash(v1) == hash(v1)
         assert hash(t1(v1)) == hash(t2(v1))
-        assert not hash(t1(v1)) != hash(t2(v1))
+        assert hash(t1(v1)) == hash(t2(v1))
     else:
         assert hash(v1) != hash(v2)
         assert hash(t1(v1)) != hash(t2(v2))
@@ -134,11 +171,13 @@ def test_repr_vDDDTypes():
     assert "vDDDTypes" in repr(vDDDTypes(timedelta(3, 11, 1)))
 
 
-vDDDLists_examples = [
+vDDDLists_examples = [  # noqa: N816
     vDDDLists([]),
     vDDDLists([datetime(2023, 11, 1, 10, 1)]),
     vDDDLists([datetime(2023, 11, 1, 10, 1), date(2023, 11, 1)]),
 ]
+
+
 @pytest.mark.parametrize("l1", vDDDLists_examples)
 @pytest.mark.parametrize("l2", vDDDLists_examples)
 def test_vDDDLists(l1, l2):
diff -pruN 6.0.1-3/src/icalendar/tests/test_examples.py 6.3.1-1/src/icalendar/tests/test_examples.py
--- 6.0.1-3/src/icalendar/tests/test_examples.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/test_examples.py	2025-05-20 07:31:39.000000000 +0000
@@ -1,51 +1,54 @@
-'''tests ensuring that *the* way of doing things works'''
+"""tests ensuring that *the* way of doing things works"""
 
 import datetime
-from icalendar import Calendar, Event, Timezone
+
 import pytest
 
+from icalendar import Calendar, Event, Timezone
+
 
 def test_creating_calendar_with_unicode_fields(calendars, utc):
-    ''' create a calendar with events that contain unicode characters in their fields '''
+    """create a calendar with events that contain unicode characters in their fields"""
     cal = Calendar()
-    cal.add('PRODID', '-//Plönë.org//NONSGML plone.app.event//EN')
-    cal.add('VERSION', '2.0')
-    cal.add('X-WR-CALNAME', 'äöü ÄÖÜ €')
-    cal.add('X-WR-CALDESC', 'test non ascii: äöü ÄÖÜ €')
-    cal.add('X-WR-RELCALID', '12345')
+    cal.add("PRODID", "-//Plönë.org//NONSGML plone.app.event//EN")
+    cal.add("VERSION", "2.0")
+    cal.add("X-WR-CALNAME", "äöü ÄÖÜ €")
+    cal.add("X-WR-CALDESC", "test non ascii: äöü ÄÖÜ €")
+    cal.add("X-WR-RELCALID", "12345")
 
     event = Event()
-    event.add('DTSTART', datetime.datetime(2010, 10, 10, 10, 0, 0, tzinfo=utc))
-    event.add('DTEND', datetime.datetime(2010, 10, 10, 12, 0, 0, tzinfo=utc))
-    event.add('CREATED', datetime.datetime(2010, 10, 10, 0, 0, 0, tzinfo=utc))
-    event.add('UID', '123456')
-    event.add('SUMMARY', 'Non-ASCII Test: ÄÖÜ äöü €')
-    event.add('DESCRIPTION', 'icalendar should be able to de/serialize non-ascii.')
-    event.add('LOCATION', 'Tribstrül')
+    event.add("DTSTART", datetime.datetime(2010, 10, 10, 10, 0, 0, tzinfo=utc))
+    event.add("DTEND", datetime.datetime(2010, 10, 10, 12, 0, 0, tzinfo=utc))
+    event.add("CREATED", datetime.datetime(2010, 10, 10, 0, 0, 0, tzinfo=utc))
+    event.add("UID", "123456")
+    event.add("SUMMARY", "Non-ASCII Test: ÄÖÜ äöü €")
+    event.add("DESCRIPTION", "icalendar should be able to de/serialize non-ascii.")
+    event.add("LOCATION", "Tribstrül")
     cal.add_component(event)
 
     # test_create_event_simple
     event1 = Event()
-    event1.add('DTSTART', datetime.datetime(2010, 10, 10, 0, 0, 0, tzinfo=utc))
-    event1.add('SUMMARY', 'åäö')
+    event1.add("DTSTART", datetime.datetime(2010, 10, 10, 0, 0, 0, tzinfo=utc))
+    event1.add("SUMMARY", "åäö")
     cal.add_component(event1)
 
     # test_unicode_parameter_name
     # test for issue #80 https://github.com/collective/icalendar/issues/80
     event2 = Event()
-    event2.add('DESCRIPTION', 'äöüßÄÖÜ')
+    event2.add("DESCRIPTION", "äöüßÄÖÜ")
     cal.add_component(event2)
 
     assert cal.to_ical() == calendars.created_calendar_with_unicode_fields.raw_ics
 
 
-@pytest.mark.parametrize("component,example",
+@pytest.mark.parametrize(
+    ("component", "example"),
     [
         (Calendar, "example"),
         (Calendar, "example.ics"),
         (Event, "event_with_rsvp"),
         (Timezone, "pacific_fiji"),
-    ]
+    ],
 )
 def test_component_has_examples(tzp, calendars, timezones, events, component, example):
     """Check that the examples function works."""
@@ -60,3 +63,10 @@ def test_invalid_examples_lists_the_othe
     with pytest.raises(ValueError) as e:
         Calendar.example("does not exist")
     assert "example.ics" in str(e.value)
+
+
+@pytest.mark.parametrize("component", [Calendar, Event, Timezone])
+def test_default_example(component):
+    """Check that we have a default example."""
+    example = component.example()
+    assert isinstance(example, component)
diff -pruN 6.0.1-3/src/icalendar/tests/test_icalendar.py 6.3.1-1/src/icalendar/tests/test_icalendar.py
--- 6.0.1-3/src/icalendar/tests/test_icalendar.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/test_icalendar.py	2025-05-20 07:31:39.000000000 +0000
@@ -1,59 +1,73 @@
-from ..parser import Contentlines, Contentline, Parameters, foldline
-from ..parser import q_join, q_split, dquote
-from ..prop import vText
-
 import unittest
 
+from icalendar.parser import (
+    Contentline,
+    Contentlines,
+    Parameters,
+    dquote,
+    foldline,
+    q_join,
+    q_split,
+)
+from icalendar.prop import vText
 
-class IcalendarTestCase (unittest.TestCase):
 
+class IcalendarTestCase(unittest.TestCase):
     def setUp(self):
-        if not hasattr(self, 'assertRaisesRegex'):
+        if not hasattr(self, "assertRaisesRegex"):
             self.assertRaisesRegex = self.assertRaisesRegexp
 
     def test_long_lines(self):
-        c = Contentlines([Contentline('BEGIN:VEVENT')])
-        c.append(Contentline(''.join('123456789 ' * 10)))
+        c = Contentlines([Contentline("BEGIN:VEVENT")])
+        c.append(Contentline("".join("123456789 " * 10)))
         self.assertEqual(
             c.to_ical(),
-            b'BEGIN:VEVENT\r\n123456789 123456789 123456789 123456789 '
-            b'123456789 123456789 123456789 1234\r\n 56789 123456789 '
-            b'123456789 \r\n'
+            b"BEGIN:VEVENT\r\n123456789 123456789 123456789 123456789 "
+            b"123456789 123456789 123456789 1234\r\n 56789 123456789 "
+            b"123456789 \r\n",
         )
 
         # from doctests
         # Notice that there is an extra empty string in the end of the content
         # lines. That is so they can be easily joined with:
         # '\r\n'.join(contentlines))
-        self.assertEqual(Contentlines.from_ical('A short line\r\n'),
-                         ['A short line', ''])
-        self.assertEqual(Contentlines.from_ical('A faked\r\n  long line\r\n'),
-                         ['A faked long line', ''])
-        self.assertEqual(
-            Contentlines.from_ical('A faked\r\n  long line\r\nAnd another '
-                                   'lin\r\n\te that is folded\r\n'),
-            ['A faked long line', 'And another line that is folded', '']
+        self.assertEqual(
+            Contentlines.from_ical("A short line\r\n"), ["A short line", ""]
+        )
+        self.assertEqual(
+            Contentlines.from_ical("A faked\r\n  long line\r\n"),
+            ["A faked long line", ""],
+        )
+        self.assertEqual(
+            Contentlines.from_ical(
+                "A faked\r\n  long line\r\nAnd another lin\r\n\te that is folded\r\n"
+            ),
+            ["A faked long line", "And another line that is folded", ""],
         )
 
     def test_contentline_class(self):
         self.assertEqual(
-            Contentline('Si meliora dies, ut vina, poemata reddit').to_ical(),
-            b'Si meliora dies, ut vina, poemata reddit'
+            Contentline("Si meliora dies, ut vina, poemata reddit").to_ical(),
+            b"Si meliora dies, ut vina, poemata reddit",
         )
 
         # A long line gets folded
-        c = Contentline(''.join(['123456789 '] * 10)).to_ical()
+        c = Contentline("".join(["123456789 "] * 10)).to_ical()
         self.assertEqual(
             c,
-            (b'123456789 123456789 123456789 123456789 123456789 123456789 '
-             b'123456789 1234\r\n 56789 123456789 123456789 ')
+            (
+                b"123456789 123456789 123456789 123456789 123456789 123456789 "
+                b"123456789 1234\r\n 56789 123456789 123456789 "
+            ),
         )
 
         # A folded line gets unfolded
         self.assertEqual(
             Contentline.from_ical(c),
-            ('123456789 123456789 123456789 123456789 123456789 123456789 '
-             '123456789 123456789 123456789 123456789 ')
+            (
+                "123456789 123456789 123456789 123456789 123456789 123456789 "
+                "123456789 123456789 123456789 123456789 "
+            ),
         )
 
         # https://tools.ietf.org/html/rfc5545#section-3.3.11
@@ -63,219 +77,228 @@ class IcalendarTestCase (unittest.TestCa
         # N or a LATIN CAPITAL LETTER N, that is "\n" or "\N".
 
         # Newlines are not allowed in content lines
-        self.assertRaises(AssertionError, Contentline, b'1234\r\n\r\n1234')
+        self.assertRaises(AssertionError, Contentline, b"1234\r\n\r\n1234")
 
-        self.assertEqual(
-            Contentline('1234\\n\\n1234').to_ical(),
-            b'1234\\n\\n1234'
-        )
+        self.assertEqual(Contentline("1234\\n\\n1234").to_ical(), b"1234\\n\\n1234")
 
         # We do not fold within a UTF-8 character
-        c = Contentline(b'This line has a UTF-8 character where it should be '
-                        b'folded. Make sure it g\xc3\xabts folded before that '
-                        b'character.')
+        c = Contentline(
+            b"This line has a UTF-8 character where it should be "
+            b"folded. Make sure it g\xc3\xabts folded before that "
+            b"character."
+        )
 
-        self.assertIn(b'\xc3\xab', c.to_ical())
+        self.assertIn(b"\xc3\xab", c.to_ical())
 
         # Another test of the above
-        c = Contentline(b'x' * 73 + b'\xc3\xab' + b'\\n ' + b'y' * 10)
+        c = Contentline(b"x" * 73 + b"\xc3\xab" + b"\\n " + b"y" * 10)
 
-        self.assertEqual(c.to_ical().count(b'\xc3'), 1)
+        self.assertEqual(c.to_ical().count(b"\xc3"), 1)
 
         # Don't fail if we fold a line that is exactly X times 74 characters
         # long
-        c = Contentline(''.join(['x'] * 148)).to_ical()
+        c = Contentline("".join(["x"] * 148)).to_ical()
 
         # It can parse itself into parts,
         # which is a tuple of (name, params, vals)
         self.assertEqual(
-            Contentline('dtstart:20050101T120000').parts(),
-            ('dtstart', Parameters({}), '20050101T120000')
+            Contentline("dtstart:20050101T120000").parts(),
+            ("dtstart", Parameters({}), "20050101T120000"),
         )
 
         self.assertEqual(
-            Contentline('dtstart;value=datetime:20050101T120000').parts(),
-            ('dtstart', Parameters({'VALUE': 'datetime'}), '20050101T120000')
+            Contentline("dtstart;value=datetime:20050101T120000").parts(),
+            ("dtstart", Parameters({"VALUE": "datetime"}), "20050101T120000"),
         )
 
-        c = Contentline('ATTENDEE;CN=Max Rasmussen;ROLE=REQ-PARTICIPANT:'
-                        'MAILTO:maxm@example.com')
+        c = Contentline(
+            "ATTENDEE;CN=Max Rasmussen;ROLE=REQ-PARTICIPANT:MAILTO:maxm@example.com"
+        )
         self.assertEqual(
             c.parts(),
-            ('ATTENDEE',
-             Parameters({'ROLE': 'REQ-PARTICIPANT', 'CN': 'Max Rasmussen'}),
-             'MAILTO:maxm@example.com')
+            (
+                "ATTENDEE",
+                Parameters({"ROLE": "REQ-PARTICIPANT", "CN": "Max Rasmussen"}),
+                "MAILTO:maxm@example.com",
+            ),
         )
         self.assertEqual(
-            c.to_ical().decode('utf-8'),
-            'ATTENDEE;CN=Max Rasmussen;ROLE=REQ-PARTICIPANT:'
-            'MAILTO:maxm@example.com'
+            c.to_ical().decode("utf-8"),
+            "ATTENDEE;CN=Max Rasmussen;ROLE=REQ-PARTICIPANT:MAILTO:maxm@example.com",
         )
 
         # and back again
         # NOTE: we are quoting property values with spaces in it.
-        parts = ('ATTENDEE',
-                 Parameters({'ROLE': 'REQ-PARTICIPANT',
-                             'CN': 'Max Rasmussen'}),
-                 'MAILTO:maxm@example.com')
+        parts = (
+            "ATTENDEE",
+            Parameters({"ROLE": "REQ-PARTICIPANT", "CN": "Max Rasmussen"}),
+            "MAILTO:maxm@example.com",
+        )
         self.assertEqual(
             Contentline.from_parts(*parts),
             'ATTENDEE;CN="Max Rasmussen";ROLE=REQ-PARTICIPANT:'
-            'MAILTO:maxm@example.com'
+            "MAILTO:maxm@example.com",
         )
 
         # and again
-        parts = ('ATTENDEE', Parameters(), 'MAILTO:maxm@example.com')
+        parts = ("ATTENDEE", Parameters(), "MAILTO:maxm@example.com")
         self.assertEqual(
-            Contentline.from_parts(*parts),
-            'ATTENDEE:MAILTO:maxm@example.com'
+            Contentline.from_parts(*parts), "ATTENDEE:MAILTO:maxm@example.com"
         )
 
         # A value can also be any of the types defined in PropertyValues
-        parts = ('ATTENDEE', Parameters(), vText('MAILTO:test@example.com'))
+        parts = ("ATTENDEE", Parameters(), vText("MAILTO:test@example.com"))
         self.assertEqual(
-            Contentline.from_parts(*parts),
-            'ATTENDEE:MAILTO:test@example.com'
+            Contentline.from_parts(*parts), "ATTENDEE:MAILTO:test@example.com"
         )
 
         # A value in UTF-8
-        parts = ('SUMMARY', Parameters(), vText('INternational char æ ø å'))
+        parts = ("SUMMARY", Parameters(), vText("INternational char æ ø å"))
         self.assertEqual(
-            Contentline.from_parts(*parts),
-            'SUMMARY:INternational char æ ø å'
+            Contentline.from_parts(*parts), "SUMMARY:INternational char æ ø å"
         )
 
         # A value can also be unicode
-        parts = ('SUMMARY', Parameters(), vText('INternational char æ ø å'))
+        parts = ("SUMMARY", Parameters(), vText("INternational char æ ø å"))
         self.assertEqual(
-            Contentline.from_parts(*parts),
-            'SUMMARY:INternational char æ ø å'
+            Contentline.from_parts(*parts), "SUMMARY:INternational char æ ø å"
         )
 
         # Traversing could look like this.
         name, params, vals = c.parts()
-        self.assertEqual(name, 'ATTENDEE')
-        self.assertEqual(vals, 'MAILTO:maxm@example.com')
+        self.assertEqual(name, "ATTENDEE")
+        self.assertEqual(vals, "MAILTO:maxm@example.com")
         self.assertEqual(
             sorted(params.items()),
-            sorted([('ROLE', 'REQ-PARTICIPANT'), ('CN', 'Max Rasmussen')])
+            sorted([("ROLE", "REQ-PARTICIPANT"), ("CN", "Max Rasmussen")]),
         )
 
         # And the traditional failure
         with self.assertRaisesRegex(
-            ValueError,
-            'Content line could not be parsed into parts'
+            ValueError, "Content line could not be parsed into parts"
         ):
-            Contentline('ATTENDEE;maxm@example.com').parts()
+            Contentline("ATTENDEE;maxm@example.com").parts()
 
         # Another failure:
         with self.assertRaisesRegex(
-            ValueError,
-            'Content line could not be parsed into parts'
+            ValueError, "Content line could not be parsed into parts"
         ):
-            Contentline(':maxm@example.com').parts()
+            Contentline(":maxm@example.com").parts()
 
         self.assertEqual(
-            Contentline('key;param=:value').parts(),
-            ('key', Parameters({'PARAM': ''}), 'value')
+            Contentline("key;param=:value").parts(),
+            ("key", Parameters({"PARAM": ""}), "value"),
         )
 
         self.assertEqual(
             Contentline('key;param="pvalue":value').parts(),
-            ('key', Parameters({'PARAM': 'pvalue'}), 'value')
+            ("key", Parameters({"PARAM": "pvalue"}), "value"),
         )
 
         # Should bomb on missing param:
         with self.assertRaisesRegex(
-            ValueError,
-            'Content line could not be parsed into parts'
+            ValueError, "Content line could not be parsed into parts"
         ):
             Contentline.from_ical("k;:no param").parts()
 
         self.assertEqual(
-            Contentline('key;param=pvalue:value', strict=False).parts(),
-            ('key', Parameters({'PARAM': 'pvalue'}), 'value')
+            Contentline("key;param=pvalue:value", strict=False).parts(),
+            ("key", Parameters({"PARAM": "pvalue"}), "value"),
         )
 
         # If strict is set to True, uppercase param values that are not
         # double-quoted, this is because the spec says non-quoted params are
         # case-insensitive.
         self.assertEqual(
-            Contentline('key;param=pvalue:value', strict=True).parts(),
-            ('key', Parameters({'PARAM': 'PVALUE'}), 'value')
+            Contentline("key;param=pvalue:value", strict=True).parts(),
+            ("key", Parameters({"PARAM": "PVALUE"}), "value"),
         )
 
         self.assertEqual(
             Contentline('key;param="pValue":value', strict=True).parts(),
-            ('key', Parameters({'PARAM': 'pValue'}), 'value')
+            ("key", Parameters({"PARAM": "pValue"}), "value"),
         )
 
         contains_base64 = (
-            b'X-APPLE-STRUCTURED-LOCATION;'
+            b"X-APPLE-STRUCTURED-LOCATION;"
             b'VALUE=URI;X-ADDRESS="Kaiserliche Hofburg, 1010 Wien";'
-            b'X-APPLE-MAPKIT-HANDLE=CAESxQEZgr3QZXJyZWljaA==;'
-            b'X-APPLE-RADIUS=328.7978217977285;X-APPLE-REFERENCEFRAME=1;'
-            b'X-TITLE=Heldenplatz:geo:48.206686,16.363235'
+            b"X-APPLE-MAPKIT-HANDLE=CAESxQEZgr3QZXJyZWljaA==;"
+            b"X-APPLE-RADIUS=328.7978217977285;X-APPLE-REFERENCEFRAME=1;"
+            b"X-TITLE=Heldenplatz:geo:48.206686,16.363235"
         )
 
         self.assertEqual(
             Contentline(contains_base64, strict=True).parts(),
-            ('X-APPLE-STRUCTURED-LOCATION',
-             Parameters({
-                 'X-APPLE-RADIUS': '328.7978217977285',
-                 'X-ADDRESS': 'Kaiserliche Hofburg, 1010 Wien',
-                 'X-APPLE-REFERENCEFRAME': '1',
-                 'X-TITLE': 'HELDENPLATZ',
-                 'X-APPLE-MAPKIT-HANDLE':
-                 'CAESXQEZGR3QZXJYZWLJAA==',
-                 'VALUE': 'URI',
-             }),
-             'geo:48.206686,16.363235'
-             )
+            (
+                "X-APPLE-STRUCTURED-LOCATION",
+                Parameters(
+                    {
+                        "X-APPLE-RADIUS": "328.7978217977285",
+                        "X-ADDRESS": "Kaiserliche Hofburg, 1010 Wien",
+                        "X-APPLE-REFERENCEFRAME": "1",
+                        "X-TITLE": "HELDENPLATZ",
+                        "X-APPLE-MAPKIT-HANDLE": "CAESXQEZGR3QZXJYZWLJAA==",
+                        "VALUE": "URI",
+                    }
+                ),
+                "geo:48.206686,16.363235",
+            ),
         )
 
     def test_fold_line(self):
-        self.assertEqual(foldline('foo'), 'foo')
+        self.assertEqual(foldline("foo"), "foo")
         self.assertEqual(
-            foldline("Lorem ipsum dolor sit amet, consectetur adipiscing "
-                     "elit. Vestibulum convallis imperdiet dui posuere."),
-            ('Lorem ipsum dolor sit amet, consectetur adipiscing elit. '
-             'Vestibulum conval\r\n lis imperdiet dui posuere.')
+            foldline(
+                "Lorem ipsum dolor sit amet, consectetur adipiscing "
+                "elit. Vestibulum convallis imperdiet dui posuere."
+            ),
+            (
+                "Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
+                "Vestibulum conval\r\n lis imperdiet dui posuere."
+            ),
         )
 
         # I don't really get this test
         # at least just but bytes in there
         # porting it to "run" under python 2 & 3 makes it not much better
         with self.assertRaises(AssertionError):
-            foldline('привет'.encode(), limit=3)
+            foldline("привет".encode(), limit=3)
 
-        self.assertEqual(foldline('foobar', limit=4), 'foo\r\n bar')
+        self.assertEqual(foldline("foobar", limit=4), "foo\r\n bar")
         self.assertEqual(
-            foldline('Lorem ipsum dolor sit amet, consectetur adipiscing elit'
-                     '. Vestibulum convallis imperdiet dui posuere.'),
-            ('Lorem ipsum dolor sit amet, consectetur adipiscing elit.'
-             ' Vestibulum conval\r\n lis imperdiet dui posuere.')
+            foldline(
+                "Lorem ipsum dolor sit amet, consectetur adipiscing elit"
+                ". Vestibulum convallis imperdiet dui posuere."
+            ),
+            (
+                "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
+                " Vestibulum conval\r\n lis imperdiet dui posuere."
+            ),
         )
         self.assertEqual(
-            foldline('DESCRIPTION:АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЬЫЪЭЮЯ'),
-            'DESCRIPTION:АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЬЫЪЭ\r\n ЮЯ'
+            foldline("DESCRIPTION:АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЬЫЪЭЮЯ"),
+            "DESCRIPTION:АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЬЫЪЭ\r\n ЮЯ",
         )
 
     def test_value_double_quoting(self):
-        self.assertEqual(dquote('Max'), 'Max')
-        self.assertEqual(dquote('Rasmussen, Max'), '"Rasmussen, Max"')
-        self.assertEqual(dquote('name:value'), '"name:value"')
+        self.assertEqual(dquote("Max"), "Max")
+        self.assertEqual(dquote("Rasmussen, Max"), '"Rasmussen, Max"')
+        self.assertEqual(dquote("name:value"), '"name:value"')
 
     def test_q_split(self):
-        self.assertEqual(q_split('Max,Moller,"Rasmussen, Max"'),
-                         ['Max', 'Moller', '"Rasmussen, Max"'])
+        self.assertEqual(
+            q_split('Max,Moller,"Rasmussen, Max"'),
+            ["Max", "Moller", '"Rasmussen, Max"'],
+        )
 
     def test_q_split_bin(self):
-        for s in ('X-SOMETHING=ABCDE==', ',,,'):
+        for s in ("X-SOMETHING=ABCDE==", ",,,"):
             for maxsplit in range(-1, 3):
-                self.assertEqual(q_split(s, '=', maxsplit=maxsplit),
-                                 s.split('=', maxsplit))
+                self.assertEqual(
+                    q_split(s, "=", maxsplit=maxsplit), s.split("=", maxsplit)
+                )
 
     def test_q_join(self):
-        self.assertEqual(q_join(['Max', 'Moller', 'Rasmussen, Max']),
-                         'Max,Moller,"Rasmussen, Max"')
+        self.assertEqual(
+            q_join(["Max", "Moller", "Rasmussen, Max"]), 'Max,Moller,"Rasmussen, Max"'
+        )
diff -pruN 6.0.1-3/src/icalendar/tests/test_issue_116.py 6.3.1-1/src/icalendar/tests/test_issue_116.py
--- 6.0.1-3/src/icalendar/tests/test_issue_116.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/test_issue_116.py	2025-05-20 07:31:39.000000000 +0000
@@ -1,4 +1,3 @@
-
 import icalendar
 
 
@@ -15,14 +14,14 @@ def test_issue_116():
             "VALUE": "URI",
             "X-ADDRESS": "367 George Street Sydney CBD NSW 2000",
             "X-APPLE-RADIUS": "72",
-            "X-TITLE": "367 George Street"
-        }
+            "X-TITLE": "367 George Street",
+        },
     )
     assert event.to_ical() == (
-        b'BEGIN:VEVENT\r\nX-APPLE-STRUCTURED-LOCATION;VALUE=URI;'
+        b"BEGIN:VEVENT\r\nX-APPLE-STRUCTURED-LOCATION;VALUE=URI;"
         b'X-ADDRESS="367 George Street Sydney \r\n CBD NSW 2000";'
         b'X-APPLE-RADIUS=72;X-TITLE="367 George Street":'
-        b'geo:-33.868900\r\n \\,151.207000\r\nEND:VEVENT\r\n'
+        b"geo:-33.868900\r\n \\,151.207000\r\nEND:VEVENT\r\n"
     )
 
     # roundtrip
diff -pruN 6.0.1-3/src/icalendar/tests/test_issue_165_missing_event.py 6.3.1-1/src/icalendar/tests/test_issue_165_missing_event.py
--- 6.0.1-3/src/icalendar/tests/test_issue_165_missing_event.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/test_issue_165_missing_event.py	2025-05-20 07:31:39.000000000 +0000
@@ -1,8 +1,9 @@
-'''Issue #165 - Problem parsing a file with event recurring on weekdays
+"""Issue #165 - Problem parsing a file with event recurring on weekdays
+
+https://github.com/collective/icalendar/issues/165
+"""
 
-   https://github.com/collective/icalendar/issues/165
-'''
 
 def test_issue_165_missing_event(calendars):
-    events = list(calendars.issue_165_missing_event.walk('VEVENT'))
+    events = list(calendars.issue_165_missing_event.walk("VEVENT"))
     assert len(events) == 1, "There was an event missing from the parsed events' list."
diff -pruN 6.0.1-3/src/icalendar/tests/test_issue_168_parsing_invalid_calendars_no_warning.py 6.3.1-1/src/icalendar/tests/test_issue_168_parsing_invalid_calendars_no_warning.py
--- 6.0.1-3/src/icalendar/tests/test_issue_168_parsing_invalid_calendars_no_warning.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/test_issue_168_parsing_invalid_calendars_no_warning.py	2025-05-20 07:31:39.000000000 +0000
@@ -1,9 +1,16 @@
-'''Issue #168 - Parsing invalid icalendars fails without any warning
+"""Issue #168 - Parsing invalid icalendars fails without any warning
+
+https://github.com/collective/icalendar/issues/168
+"""
 
-   https://github.com/collective/icalendar/issues/168
-'''
 
 def test_issue_168_parsing_inavlid_calendars_no_warning(calendars):
-    expected_error = (None, "Content line could not be parsed into parts: 'X-APPLE-RADIUS=49.91307046514149': X-APPLE-RADIUS=49.91307046514149")
-    assert expected_error in calendars.issue_168_input.walk('VEVENT')[0].errors
-    assert calendars.issue_168_input.to_ical() == calendars.issue_168_expected_output.raw_ics
+    expected_error = (
+        None,
+        "Content line could not be parsed into parts: 'X-APPLE-RADIUS=49.91307046514149': X-APPLE-RADIUS=49.91307046514149",
+    )
+    assert expected_error in calendars.issue_168_input.walk("VEVENT")[0].errors
+    assert (
+        calendars.issue_168_input.to_ical()
+        == calendars.issue_168_expected_output.raw_ics
+    )
diff -pruN 6.0.1-3/src/icalendar/tests/test_issue_218_parse_calendar.py 6.3.1-1/src/icalendar/tests/test_issue_218_parse_calendar.py
--- 6.0.1-3/src/icalendar/tests/test_issue_218_parse_calendar.py	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/test_issue_218_parse_calendar.py	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,32 @@
+"""Parse the calendar and make sure the timezone is used.
+
+See https://github.com/collective/icalendar/issues/218
+"""
+from __future__ import annotations
+
+from datetime import datetime, timedelta
+from typing import TYPE_CHECKING
+
+import pytest
+
+from icalendar.timezone.tzid import tzid_from_dt
+
+if TYPE_CHECKING:
+    from icalendar import Event
+
+@pytest.fixture()
+def event(calendars) -> Event:
+    """The event to check."""
+    return calendars.issue_218_bad_tzid.events[0]
+
+
+def test_event_has_start_and_end(event : Event):
+    """The calendar should be parsed and the start and end have a timezone."""
+    assert event.start.replace(tzinfo=None) == datetime(2017, 2, 28, 23, 00)
+    assert event.end.replace(tzinfo=None) == datetime(2017, 2, 28, 23, 30)
+
+def test_timezone(event:Event):
+    """The event uses a timezone."""
+    assert event.start.tzinfo == event.end.tzinfo
+    assert tzid_from_dt(event.start) == "UTC+11"
+    assert event.start.utcoffset() == timedelta(hours=11)
diff -pruN 6.0.1-3/src/icalendar/tests/test_issue_27_period.py 6.3.1-1/src/icalendar/tests/test_issue_27_period.py
--- 6.0.1-3/src/icalendar/tests/test_issue_27_period.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/test_issue_27_period.py	2025-05-20 07:31:39.000000000 +0000
@@ -1,13 +1,19 @@
-'''Issue #27 - multiple periods
+"""Issue #27 - multiple periods
+
+https://github.com/collective/icalendar/issues/27
+"""
 
-   https://github.com/collective/icalendar/issues/27
-'''
 
 def test_issue_27_multiple_periods(calendars):
-    free_busy = list(calendars.issue_27_multiple_periods_in_freebusy_multiple_freebusies.walk('VFREEBUSY'))[0]
-    free_busy_period = free_busy['freebusy']
-    print(free_busy['freebusy'])
-    equivalent_way_of_defining_free_busy = list(calendars.issue_27_multiple_periods_in_freebusy_one_freebusy.walk('VFREEBUSY'))[0]
-    free_busy_period_equivalent = equivalent_way_of_defining_free_busy['freebusy']
+    free_busy = list(
+        calendars.issue_27_multiple_periods_in_freebusy_multiple_freebusies.walk(
+            "VFREEBUSY"
+        )
+    )[0]
+    free_busy_period = free_busy["freebusy"]
+    print(free_busy["freebusy"])
+    equivalent_way_of_defining_free_busy = list(
+        calendars.issue_27_multiple_periods_in_freebusy_one_freebusy.walk("VFREEBUSY")
+    )[0]
+    free_busy_period_equivalent = equivalent_way_of_defining_free_busy["freebusy"]
     assert free_busy_period == free_busy_period_equivalent
-
diff -pruN 6.0.1-3/src/icalendar/tests/test_issue_301_add_rrule_as_string.py 6.3.1-1/src/icalendar/tests/test_issue_301_add_rrule_as_string.py
--- 6.0.1-3/src/icalendar/tests/test_issue_301_add_rrule_as_string.py	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/test_issue_301_add_rrule_as_string.py	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,14 @@
+"""We want to add rrule as a string for convenience.
+
+See https://github.com/collective/icalendar/issues/301
+"""
+
+from icalendar.cal import Event
+
+
+def test_rrule_add_example():
+    event = Event()
+    event.add("RRULE", "FREQ=DAILY;INTERVAL=2")
+    assert "FREQ=DAILY;INTERVAL=2" in event.to_ical().decode("utf-8")
+    assert event.rrules[0]["freq"] == ["DAILY"]
+    assert event.rrules[0]["interval"] == [2]
diff -pruN 6.0.1-3/src/icalendar/tests/test_issue_318_skip_default_parameters.py 6.3.1-1/src/icalendar/tests/test_issue_318_skip_default_parameters.py
--- 6.0.1-3/src/icalendar/tests/test_issue_318_skip_default_parameters.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/test_issue_318_skip_default_parameters.py	2025-05-20 07:31:39.000000000 +0000
@@ -8,20 +8,25 @@ Example:
        DTSTART;VALUE=DATE-TIME:20190616T050000Z
 equals DTSTART:20190616T050000Z
 """
+
+from datetime import datetime
+
 import pytest
+
 from icalendar import Event
-from datetime import datetime
 
 
-@pytest.mark.parametrize("attr", [
-    "DTSTART",
-    "DTEND",
-    "DTSTAMP",
-])
+@pytest.mark.parametrize(
+    "attr",
+    [
+        "DTSTART",
+        "DTEND",
+        "DTSTAMP",
+    ],
+)
 def test_datetime_in_event(attr):
     """Check that the "VALUE=DATE-TIME" is absent because not needed."""
     event = Event()
     event.add(attr, datetime(2022, 10, 13, 9, 16, 42))
     ics = event.to_ical()
     assert b"VALUE=DATE-TIME" not in ics
-
diff -pruN 6.0.1-3/src/icalendar/tests/test_issue_322_single_strings_characters_split_into_multiple_categories.py 6.3.1-1/src/icalendar/tests/test_issue_322_single_strings_characters_split_into_multiple_categories.py
--- 6.0.1-3/src/icalendar/tests/test_issue_322_single_strings_characters_split_into_multiple_categories.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/test_issue_322_single_strings_characters_split_into_multiple_categories.py	2025-05-20 07:31:39.000000000 +0000
@@ -4,7 +4,7 @@ from icalendar import Calendar, Event
 def test_issue_322_single_string_split_into_multiple_categories(calendars):
     calendar = Calendar()
     event = Event()
-    event.add('summary', 'Event with bare string as argument for categories')
-    event.add('categories', "Lecture")
+    event.add("summary", "Event with bare string as argument for categories")
+    event.add("categories", "Lecture")
     calendar.add_component(event)
     assert calendar.to_ical() == calendars.issue_322_expected_calendar.raw_ics
diff -pruN 6.0.1-3/src/icalendar/tests/test_issue_336_dateutil_timezone.py 6.3.1-1/src/icalendar/tests/test_issue_336_dateutil_timezone.py
--- 6.0.1-3/src/icalendar/tests/test_issue_336_dateutil_timezone.py	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/test_issue_336_dateutil_timezone.py	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,30 @@
+"""We would like to be able to get the right timezone names.
+
+See https://github.com/collective/icalendar/issues/336
+
+It appears that the timezone Brazil/DeNoronha is actually America/Noronha.
+"""
+
+from datetime import datetime
+
+from dateutil import tz
+
+from icalendar import Event
+from icalendar.timezone import tzid_from_tzinfo
+
+valid_names = ("America/Noronha",  "Brazil/DeNoronha")
+
+
+def test_timezone_name_directly():
+    """Try to get the name directly."""
+    tzinfo = tz.gettz("Brazil/DeNoronha")
+    assert tzid_from_tzinfo(tzinfo) in valid_names
+
+
+def test_in_event():
+    """The example has an event in it and we want to have the id in it."""
+    event = Event()
+    event.start = datetime(2025, 5, 13, 14, 23, tzinfo=tz.gettz("Brazil/DeNoronha"))
+    ics = event.to_ical().decode()
+    print(ics)
+    assert any(name in ics for name in valid_names)
diff -pruN 6.0.1-3/src/icalendar/tests/test_issue_348_exception_parsing_value.py 6.3.1-1/src/icalendar/tests/test_issue_348_exception_parsing_value.py
--- 6.0.1-3/src/icalendar/tests/test_issue_348_exception_parsing_value.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/test_issue_348_exception_parsing_value.py	2025-05-20 07:31:39.000000000 +0000
@@ -7,7 +7,7 @@ see https://github.com/collective/icalen
 def test_calendar_can_be_parsed_correctly(calendars):
     """Exception when there's no ':' when parsing value #348
 
-    see https://github.com/collective/icalendar/issues/348 
+    see https://github.com/collective/icalendar/issues/348
     """
     freebusy = calendars.issue_348_exception_parsing_value.walk("VFREEBUSY")[0]
     assert freebusy["ORGANIZER"].params["CN"] == "Sixt SE"
diff -pruN 6.0.1-3/src/icalendar/tests/test_issue_350.py 6.3.1-1/src/icalendar/tests/test_issue_350.py
--- 6.0.1-3/src/icalendar/tests/test_issue_350.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/test_issue_350.py	2025-05-20 07:31:39.000000000 +0000
@@ -1,8 +1,9 @@
-'''Issue #350 - Ignore X-... properties also at end of file?
+"""Issue #350 - Ignore X-... properties also at end of file?
+
+https://github.com/collective/icalendar/issues/350
+"""
 
-   https://github.com/collective/icalendar/issues/350
-'''
 
 def test_issue_350(calendars):
-    calendar = list(calendars.issue_350.walk('X-COMMENT'))
+    calendar = list(calendars.issue_350.walk("X-COMMENT"))
     assert len(calendar) == 0, "X-COMMENT at the end of the file was parsed"
diff -pruN 6.0.1-3/src/icalendar/tests/test_issue_500_vboolean_for_parameter.py 6.3.1-1/src/icalendar/tests/test_issue_500_vboolean_for_parameter.py
--- 6.0.1-3/src/icalendar/tests/test_issue_500_vboolean_for_parameter.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/test_issue_500_vboolean_for_parameter.py	2025-05-20 07:31:39.000000000 +0000
@@ -1,9 +1,10 @@
 from icalendar import Event, vBoolean, vCalAddress
 
+
 def test_vBoolean_can_be_used_as_parameter_issue_500(events):
-    '''https://github.com/collective/icalendar/issues/500'''
-    attendee = vCalAddress('mailto:someone@example.com')
-    attendee.params['rsvp'] = vBoolean(True)
+    """https://github.com/collective/icalendar/issues/500"""
+    attendee = vCalAddress("mailto:someone@example.com")
+    attendee.params["rsvp"] = vBoolean(True)
     event = Event()
-    event.add('attendee', attendee)
+    event.add("attendee", attendee)
     assert event.to_ical() == events.event_with_rsvp.raw_ics
diff -pruN 6.0.1-3/src/icalendar/tests/test_issue_557_encode_native_parameters.py 6.3.1-1/src/icalendar/tests/test_issue_557_encode_native_parameters.py
--- 6.0.1-3/src/icalendar/tests/test_issue_557_encode_native_parameters.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/test_issue_557_encode_native_parameters.py	2025-05-20 07:31:39.000000000 +0000
@@ -6,7 +6,6 @@ making its behavior unexpected.
 
 see https://github.com/collective/icalendar/issues/557"""
 
-
 import unittest
 
 from icalendar.cal import Component
diff -pruN 6.0.1-3/src/icalendar/tests/test_issue_662_component_properties.py 6.3.1-1/src/icalendar/tests/test_issue_662_component_properties.py
--- 6.0.1-3/src/icalendar/tests/test_issue_662_component_properties.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/test_issue_662_component_properties.py	2025-05-20 07:31:39.000000000 +0000
@@ -1,8 +1,13 @@
 """This tests the properties of components and their types."""
+
+from __future__ import annotations
 from datetime import date, datetime, timedelta
 
 import pytest
 
+from icalendar.error import IncompleteComponent, InvalidCalendar
+from icalendar.cal import Alarm
+
 try:
     from zoneinfo import ZoneInfo
 except ImportError:
@@ -10,66 +15,91 @@ except ImportError:
 
 from icalendar import (
     Event,
-    IncompleteComponent,
-    InvalidCalendar,
     Journal,
+    Todo,
     vDDDTypes,
+    vDatetime,
 )
 from icalendar.prop import vDuration
 
 
-@pytest.fixture()
-def event():
+def prop(component: Event | Todo, prop: str) -> str:
+    """Translate the end property.
+
+    This allows us to run the same tests on Event and Todo.
+    """
+    if isinstance(component, Todo) and prop.upper() == "DTEND":
+        return "DUE"
+    return prop
+
+
+@pytest.fixture(params=[Event, Todo])
+def start_end_component(request):
     """The event to test."""
-    return Event()
+    return request.param()
+
 
-@pytest.fixture(params=[
+@pytest.fixture(
+    params=[
         datetime(2022, 7, 22, 12, 7),
         date(2022, 7, 22),
         datetime(2022, 7, 22, 13, 7, tzinfo=ZoneInfo("Europe/Paris")),
-    ])
-def dtstart(request, set_event_start, event):
+    ]
+)
+def dtstart(request, set_component_start, start_end_component):
     """Start of the event."""
-    set_event_start(event, request.param)
+    set_component_start(start_end_component, request.param)
     return request.param
 
 
-def _set_event_start_init(event, start):
+def _set_component_start_init(component, start):
     """Create the event with the __init__ method."""
-    d = dict(event)
+    d = dict(component)
     d["dtstart"] = vDDDTypes(start)
-    event.clear()
-    event.update(Event(d))
+    component.clear()
+    component.update(type(component)(d))
+
 
-def _set_event_dtstart(event, start):
+def _set_component_dtstart(component, start):
     """Create the event with the dtstart property."""
-    event.DTSTART = start
+    component.DTSTART = start
 
-def _set_event_start_attr(event, start):
+
+def _set_component_start_attr(component, start):
     """Create the event with the dtstart property."""
-    event.start = start
+    component.start = start
+
 
-def _set_event_start_ics(event, start):
+def _set_component_start_ics(component, start):
     """Create the event with the start property."""
-    event.add("dtstart", start)
-    ics = event.to_ical().decode()
+    component.add("dtstart", start)
+    ics = component.to_ical().decode()
     print(ics)
-    event.clear()
-    event.update(Event.from_ical(ics))
+    component.clear()
+    component.update(type(component).from_ical(ics))
+
 
-@pytest.fixture(params=[_set_event_start_init, _set_event_start_ics, _set_event_dtstart, _set_event_start_attr])
-def set_event_start(request):
+@pytest.fixture(
+    params=[
+        _set_component_start_init,
+        _set_component_start_ics,
+        _set_component_dtstart,
+        _set_component_start_attr,
+    ]
+)
+def set_component_start(request):
     """Create a new event."""
     return request.param
 
-def test_event_dtstart(dtstart, event):
+
+def test_component_dtstart(dtstart, start_end_component):
     """Test the start of events."""
-    assert event.DTSTART == dtstart
+    assert start_end_component.DTSTART == dtstart
 
 
-def test_event_start(dtstart, event):
+def test_event_start(dtstart, start_end_component):
     """Test the start of events."""
-    assert event.start == dtstart
+    assert start_end_component.start == dtstart
 
 
 invalid_start_event_1 = Event()
@@ -78,8 +108,22 @@ invalid_start_event_1.add("dtstart", dat
 invalid_start_event_2 = Event.from_ical(invalid_start_event_1.to_ical())
 invalid_start_event_3 = Event()
 invalid_start_event_3.add("DTSTART", (date(2018, 1, 1), date(2018, 2, 1)))
+invalid_start_todo_1 = Todo(invalid_start_event_1)
+invalid_start_todo_2 = Todo(invalid_start_event_2)
+invalid_start_todo_3 = Todo(invalid_start_event_3)
 
-@pytest.mark.parametrize("invalid_event", [invalid_start_event_1, invalid_start_event_2, invalid_start_event_3])
+
+@pytest.mark.parametrize(
+    "invalid_event",
+    [
+        invalid_start_event_1,
+        invalid_start_event_2,
+        invalid_start_event_3,
+        invalid_start_todo_1,
+        invalid_start_todo_2,
+        invalid_start_todo_3,
+    ],
+)
 def test_multiple_dtstart(invalid_event):
     """Check that we get the right error."""
     with pytest.raises(InvalidCalendar):
@@ -87,7 +131,8 @@ def test_multiple_dtstart(invalid_event)
     with pytest.raises(InvalidCalendar):
         invalid_event.DTSTART  # noqa: B018
 
-def test_no_dtstart():
+
+def test_no_dtstart(start_end_component):
     """DTSTART is optional.
 
     The following is REQUIRED if the component
@@ -96,94 +141,119 @@ def test_no_dtstart():
     is OPTIONAL; in any case, it MUST NOT occur
     more than once.
     """
-    assert Event().DTSTART is None
+    assert start_end_component.DTSTART is None
     with pytest.raises(IncompleteComponent):
-        Event().start  # noqa: B018
+        start_end_component.start  # noqa: B018
 
 
-@pytest.fixture(params=[
+@pytest.fixture(
+    params=[
         datetime(2022, 7, 22, 12, 8),
         date(2022, 7, 23),
         datetime(2022, 7, 22, 14, 7, tzinfo=ZoneInfo("Europe/Paris")),
-    ])
-def dtend(request, set_event_end, event):
+    ]
+)
+def dtend(request, set_component_end, start_end_component):
     """end of the event."""
-    set_event_end(event, request.param)
+    set_component_end(start_end_component, request.param)
     return request.param
 
 
-def _set_event_end_init(event, end):
+def _set_component_end_init(component, end):
     """Create the event with the __init__ method."""
-    d = dict(event)
-    d["dtend"] = vDDDTypes(end)
-    event.clear()
-    event.update(Event(d))
+    d = dict(component)
+    d[prop(component, "dtend")] = vDDDTypes(end)
+    component.clear()
+    component.update(type(component)(d))
+
 
-def _set_event_dtend(event, end):
+def _set_component_end_property(component, end):
     """Create the event with the dtend property."""
-    event.DTEND = end
+    setattr(component, prop(component, "DTEND"), end)
+
 
-def _set_event_end_attr(event, end):
+def _set_component_end_attr(component, end):
     """Create the event with the dtend property."""
-    event.end = end
+    component.end = end
 
-def _set_event_end_ics(event, end):
+
+def _set_component_end_ics(component, end):
     """Create the event with the end property."""
-    event.add("dtend", end)
-    ics = event.to_ical().decode()
+    component.add(prop(component, "DTEND"), end)
+    ics = component.to_ical().decode()
     print(ics)
-    event.clear()
-    event.update(Event.from_ical(ics))
+    component.clear()
+    component.update(type(component).from_ical(ics))
+
 
-@pytest.fixture(params=[_set_event_end_init, _set_event_end_ics, _set_event_dtend, _set_event_end_attr])
-def set_event_end(request):
+@pytest.fixture(
+    params=[
+        _set_component_end_init,
+        _set_component_end_ics,
+        _set_component_end_property,
+        _set_component_end_attr,
+    ]
+)
+def set_component_end(request):
     """Create a new event."""
     return request.param
 
-def test_event_dtend(dtend, event):
+
+def test_component_end_property(dtend, start_end_component):
     """Test the end of events."""
-    assert event.DTEND == dtend  # noqa: SIM300
+    attr = prop(start_end_component, "DTEND")
+    assert getattr(start_end_component, attr) == dtend  # noqa: SIM300
 
 
-def test_event_end(dtend, event):
+def test_component_end(dtend, start_end_component):
     """Test the end of events."""
-    assert event.end == dtend
+    assert start_end_component.end == dtend
 
 
 @pytest.mark.parametrize("attr", ["DTSTART", "DTEND"])
-def test_delete_attr(event, dtstart, dtend, attr):
-    delattr(event, attr)
-    assert getattr(event, attr) is None
-    delattr(event, attr)
+def test_delete_attr(start_end_component, dtstart, dtend, attr):
+    attr = prop(start_end_component, attr)
+    delattr(start_end_component, attr)
+    assert getattr(start_end_component, attr) is None
+    delattr(start_end_component, attr)
 
 
-def _set_duration_vdddtypes(event:Event, duration:timedelta):
+def _set_duration_vdddtypes(event: Event, duration: timedelta):
     """Set the vDDDTypes value"""
     event["DURATION"] = vDDDTypes(duration)
 
-def _set_duration_add(event:Event, duration:timedelta):
+
+def _set_duration_add(event: Event, duration: timedelta):
     """Set the vDDDTypes value"""
     event.add("DURATION", duration)
 
-def _set_duration_vduration(event:Event, duration:timedelta):
+
+def _set_duration_vduration(event: Event, duration: timedelta):
     """Set the vDDDTypes value"""
     event["DURATION"] = vDuration(duration)
 
-@pytest.fixture(params=[_set_duration_vdddtypes, _set_duration_add, _set_duration_vduration])
-def duration(event, dtstart, request):
+
+@pytest.fixture(
+    params=[_set_duration_vdddtypes, _set_duration_add, _set_duration_vduration]
+)
+def duration(start_end_component, dtstart, request):
     """... events have a DATE value type for the "DTSTART" property ...
     If such a "VEVENT" has a "DURATION"
     property, it MUST be specified as a "dur-day" or "dur-week" value.
     """
-    duration = timedelta(hours=1) if isinstance(dtstart, datetime) else timedelta(days=2)
-    request.param(event, duration)
+    duration = (
+        timedelta(hours=1) if isinstance(dtstart, datetime) else timedelta(days=2)
+    )
+    request.param(start_end_component, duration)
     return duration
 
-def test_start_and_duration(event, dtstart, duration):
+
+def test_start_and_duration(start_end_component, dtstart, duration):
     """Check calculation of end with duration."""
-    dur = event.end - event.start
+    dur = start_end_component.end - start_end_component.start
     assert dur == duration
-    assert event.duration == duration
+    assert start_end_component.duration == duration
+
 
 # The "VEVENT" is also the calendar component used to specify an
 # anniversary or daily reminder within a calendar.  These events
@@ -203,23 +273,68 @@ invalid_event_end_3.add("DURATION", time
 invalid_event_end_4 = Event()
 invalid_event_end_4.add("DTSTART", date(2024, 1, 1))
 invalid_event_end_4.add("DURATION", timedelta(hours=1))
+
+invalid_todo_end_1 = Todo()
+invalid_todo_end_1.add("DTSTART", datetime(2024, 1, 1, 10, 20))
+invalid_todo_end_1.add("DUE", date(2024, 1, 1))
+invalid_todo_end_2 = Todo()
+invalid_todo_end_2.add("DUE", datetime(2024, 1, 1, 10, 20))
+invalid_todo_end_2.add("DTSTART", date(2024, 1, 1))
+invalid_todo_end_3 = Todo()
+invalid_todo_end_3.add("DUE", datetime(2024, 1, 1, 10, 20))
+invalid_todo_end_3.add("DTSTART", datetime(2024, 1, 1, 10, 20))
+invalid_todo_end_3.add("DURATION", timedelta(days=1))
+invalid_todo_end_4 = Todo()
+invalid_todo_end_4.add("DTSTART", date(2024, 1, 1))
+invalid_todo_end_4.add("DURATION", timedelta(hours=1))
+
+
 @pytest.mark.parametrize(
-    ("invalid_event", "message"),
+    ("invalid_component", "message"),
     [
-        (invalid_event_end_1, "DTSTART and DTEND must be of the same type, either date or datetime."),
-        (invalid_event_end_2, "DTSTART and DTEND must be of the same type, either date or datetime."),
-        (invalid_event_end_3, "Only one of DTEND and DURATION may be in a VEVENT, not both."),
-        (invalid_event_end_4, "When DTSTART is a date, DURATION must be of days or weeks."),
-    ]
+        (
+            invalid_event_end_1,
+            "DTSTART and DTEND must be of the same type, either date or datetime.",
+        ),
+        (
+            invalid_event_end_2,
+            "DTSTART and DTEND must be of the same type, either date or datetime.",
+        ),
+        (
+            invalid_event_end_3,
+            "Only one of DTEND and DURATION may be in a VEVENT, not both.",
+        ),
+        (
+            invalid_event_end_4,
+            "When DTSTART is a date, DURATION must be of days or weeks.",
+        ),
+        (
+            invalid_todo_end_1,
+            "DTSTART and DUE must be of the same type, either date or datetime.",
+        ),
+        (
+            invalid_todo_end_2,
+            "DTSTART and DUE must be of the same type, either date or datetime.",
+        ),
+        (
+            invalid_todo_end_3,
+            "Only one of DUE and DURATION may be in a VTODO, not both.",
+        ),
+        (
+            invalid_todo_end_4,
+            "When DTSTART is a date, DURATION must be of days or weeks.",
+        ),
+    ],
 )
 @pytest.mark.parametrize("attr", ["start", "end"])
-def test_invalid_event(invalid_event, message, attr):
+def test_invalid_event(invalid_component, message, attr):
     """Test that the end and start throuw the right error."""
     with pytest.raises(InvalidCalendar) as e:
-        getattr(invalid_event, attr)
+        getattr(invalid_component, attr)
     assert e.value.args[0] == message
 
-def test_duration_zero():
+
+def test_event_duration_zero():
     """
     For cases where a "VEVENT" calendar component
     specifies a "DTSTART" property with a DATE-TIME value type but no
@@ -231,7 +346,8 @@ def test_duration_zero():
     assert event.end == event.start
     assert event.duration == timedelta(days=0)
 
-def test_duration_one_day():
+
+def test_event_duration_one_day():
     """
     For cases where a "VEVENT" calendar component
     specifies a "DTSTART" property with a DATE value type but no
@@ -244,11 +360,45 @@ def test_duration_one_day():
     assert event.duration == timedelta(days=1)
 
 
+def test_todo_duration_zero():
+    """We do not know about the duration of a todo really."""
+    todo = Todo()
+    todo.start = datetime(2024, 10, 11, 10, 20)
+    assert todo.end == todo.start
+    assert todo.duration == timedelta(days=0)
+
+
+def test_todo_duration_one_day():
+    """The end is at the end of the day, excluding midnight.
+
+    RFC 5545:
+    The following is an example of a "VTODO" calendar
+    component that needs to be completed before May 1st, 2007.  On
+    midnight May 1st, 2007 this to-do would be considered overdue.
+    """
+    event = Event()
+    event.start = date(2024, 10, 11)
+    assert event.end == event.start + timedelta(days=1)
+    assert event.duration == timedelta(days=1)
+
+
 incomplete_event_1 = Event()
 incomplete_event_2 = Event()
 incomplete_event_2.add("DURATION", timedelta(hours=1))
+incomplete_todo_1 = Todo()
+incomplete_todo_2 = Todo()
+incomplete_todo_2.add("DURATION", timedelta(hours=1))
+
 
-@pytest.mark.parametrize("incomplete_event_end", [incomplete_event_1, incomplete_event_2])
+@pytest.mark.parametrize(
+    "incomplete_event_end",
+    [
+        incomplete_event_1,
+        incomplete_event_2,
+        incomplete_todo_1,
+        incomplete_todo_2,
+    ],
+)
 @pytest.mark.parametrize("attr", ["start", "end", "duration"])
 def test_incomplete_event(incomplete_event_end, attr):
     """Test that the end throws the right error."""
@@ -262,19 +412,23 @@ def test_incomplete_event(incomplete_eve
         object(),
         timedelta(days=1),
         (datetime(2024, 10, 11, 10, 20), timedelta(days=1)),
-    ]
+    ],
 )
 @pytest.mark.parametrize(
     ("Component", "attr"),
     [
-        (Event,"start"),
-        (Event,"end"),
-        (Event,"DTSTART"),
-        (Event,"DTEND"),
-        (Journal,"start"),
-        (Journal,"end"),
-        (Journal,"DTSTART"),
-    ]
+        (Event, "start"),
+        (Event, "end"),
+        (Event, "DTSTART"),
+        (Event, "DTEND"),
+        (Journal, "start"),
+        (Journal, "end"),
+        (Journal, "DTSTART"),
+        (Todo, "start"),
+        (Todo, "end"),
+        (Todo, "DTSTART"),
+        (Todo, "DUE"),
+    ],
 )
 def test_set_invalid_start(invalid_value, attr, Component):
     """Check that we get the right error.
@@ -282,15 +436,18 @@ def test_set_invalid_start(invalid_value
     - other types that vDDDTypes accepts
     - object
     """
-    event = Component()
+    component = Component()
     with pytest.raises(TypeError) as e:
-        setattr(event, attr, invalid_value)
-    assert e.value.args[0] == f"Use datetime or date, not {type(invalid_value).__name__}."
+        setattr(component, attr, invalid_value)
+    assert (
+        e.value.args[0] == f"Use datetime or date, not {type(invalid_value).__name__}."
+    )
 
 
-def setitem(d:dict, key, value):
+def setitem(d: dict, key, value):
     d[key] = value
 
+
 @pytest.mark.parametrize(
     "invalid_value",
     [
@@ -299,37 +456,41 @@ def setitem(d:dict, key, value):
         (datetime(2024, 10, 11, 10, 20), timedelta(days=1)),
         date(2012, 2, 2),
         datetime(2022, 2, 2),
-    ]
+    ],
 )
-def test_check_invalid_duration(invalid_value):
+def test_check_invalid_duration(start_end_component, invalid_value):
     """Check that we get the right error."""
-    event = Event()
-    event["DURATION"] = invalid_value
+    start_end_component["DURATION"] = invalid_value
     with pytest.raises(InvalidCalendar) as e:
-        event.DURATION  # noqa: B018
-    assert e.value.args[0] == f"DURATION must be a timedelta, not {type(invalid_value).__name__}."
+        start_end_component.DURATION  # noqa: B018
+    assert (
+        e.value.args[0]
+        == f"DURATION must be a timedelta, not {type(invalid_value).__name__}."
+    )
 
 
-def test_setting_the_end_deletes_the_duration():
+def test_setting_the_end_deletes_the_duration(start_end_component):
     """Setting the end should not break the event."""
-    event = Event()
-    event.DTSTART = datetime(2024, 10, 11, 10, 20)
-    event.DURATION = timedelta(days=1)
-    event.DTEND = datetime(2024, 10, 11, 10, 21)
-    assert "DURATION" not in event
-    assert event.DURATION is None
-    assert event.DTEND == datetime(2024, 10, 11, 10, 21)
+    DTEND = prop(start_end_component, "DTEND")
+    start_end_component.DTSTART = datetime(2024, 10, 11, 10, 20)
+    start_end_component.DURATION = timedelta(days=1)
+    setattr(start_end_component, DTEND, datetime(2024, 10, 11, 10, 21))
+    assert "DURATION" not in start_end_component
+    assert start_end_component.DURATION is None
+    end = getattr(start_end_component, DTEND)
+    assert end == datetime(2024, 10, 11, 10, 21)
 
 
-def test_setting_duration_deletes_the_end():
+def test_setting_duration_deletes_the_end(start_end_component):
     """Setting the duration should not break the event."""
-    event = Event()
-    event.DTSTART = datetime(2024, 10, 11, 10, 20)
-    event.DTEND = datetime(2024, 10, 11, 10, 21)
-    event.DURATION = timedelta(days=1)
-    assert "DTEND" not in event
-    assert event.DTEND is None
-    assert event.DURATION == timedelta(days=1)
+    DTEND = prop(start_end_component, "DTEND")
+    start_end_component.DTSTART = datetime(2024, 10, 11, 10, 20)
+    setattr(start_end_component, DTEND, datetime(2024, 10, 11, 10, 21))
+    start_end_component.DURATION = timedelta(days=1)
+    assert DTEND not in start_end_component
+    assert getattr(start_end_component, DTEND) is None
+    assert start_end_component.DURATION == timedelta(days=1)
+
 
 valid_values = pytest.mark.parametrize(
     ("attr", "value"),
@@ -337,42 +498,55 @@ valid_values = pytest.mark.parametrize(
         ("DTSTART", datetime(2024, 10, 11, 10, 20)),
         ("DTEND", datetime(2024, 10, 11, 10, 20)),
         ("DURATION", timedelta(days=1)),
-    ]
+    ],
 )
+
+
 @valid_values
-def test_setting_to_none_deletes_value(attr, value):
+def test_setting_to_none_deletes_value(start_end_component, attr, value):
     """Setting attributes to None deletes them."""
-    event = Event()
-    setattr(event, attr, value)
-    assert attr in event
-    assert getattr(event, attr) == value
-    setattr(event, attr, None)
-    assert attr not in event
+    attr = prop(start_end_component, attr)
+    setattr(start_end_component, attr, value)
+    assert attr in start_end_component
+    assert getattr(start_end_component, attr) == value
+    setattr(start_end_component, attr, None)
+    assert attr not in start_end_component
 
 
 @valid_values
-def test_setting_a_value_twice(attr, value):
+def test_setting_a_value_twice(start_end_component, attr, value):
     """Setting attributes twice replaces them."""
-    event = Event()
-    setattr(event, attr, value + timedelta(days=1))
-    setattr(event, attr, value)
-    assert getattr(event, attr) == value
+    attr = prop(start_end_component, attr)
+    setattr(start_end_component, attr, value + timedelta(days=1))
+    setattr(start_end_component, attr, value)
+    assert getattr(start_end_component, attr) == value
 
 
 @pytest.mark.parametrize("attr", ["DTSTART", "DTEND", "DURATION"])
-def test_invalid_none(attr):
+def test_invalid_none(start_end_component, attr):
     """Special case for None."""
-    event = Event()
-    event[attr] = None
+    attr = prop(start_end_component, attr)
+    start_end_component[attr] = None
     with pytest.raises(InvalidCalendar):
-        getattr(event, attr)
+        getattr(start_end_component, attr)
+
+
+def test_delete_duration(start_end_component):
+    """Test the del command."""
+    start_end_component.DURATION = timedelta(days=1)
+    del start_end_component.DURATION
+    assert start_end_component.DURATION is None
+
 
 @pytest.mark.parametrize("attr", ["DTSTART", "end", "start"])
-@pytest.mark.parametrize("start", [
-    datetime(2024, 10, 11, 10, 20),
-    date(2024, 10, 11),
-    datetime(2024, 10, 11, 10, 20, tzinfo=ZoneInfo("Europe/Paris")),
-])
+@pytest.mark.parametrize(
+    "start",
+    [
+        datetime(2024, 10, 11, 10, 20),
+        date(2024, 10, 11),
+        datetime(2024, 10, 11, 10, 20, tzinfo=ZoneInfo("Europe/Paris")),
+    ],
+)
 def test_journal_start(start, attr):
     """Test that we can set the start of a journal."""
     j = Journal()
@@ -382,6 +556,7 @@ def test_journal_start(start, attr):
     assert j.end == start
     assert j.duration == timedelta(0)
 
+
 @pytest.mark.parametrize("attr", ["start", "end"])
 def test_delete_journal_start(attr):
     """Delete the start of the journal."""
@@ -393,11 +568,144 @@ def test_delete_journal_start(attr):
     with pytest.raises(IncompleteComponent):
         getattr(j, attr)
 
+
 def setting_twice_does_not_duplicate_the_entry():
     j = Journal()
-    j.DTSTART = date(2024, 1,1 )
+    j.DTSTART = date(2024, 1, 1)
     j.DTSTART = date(2024, 1, 3)
     assert date(2024, 1, 3) == j.DTSTART
     assert j.start == date(2024, 1, 3)
     assert j.end == date(2024, 1, 3)
 
+
+@pytest.mark.parametrize(
+    ("file", "trigger", "related"),
+    [
+        (
+            "rfc_5545_absolute_alarm_example",
+            vDatetime.from_ical("19970317T133000Z"),
+            "START",
+        ),
+        ("rfc_5545_end", timedelta(days=-2), "END"),
+        ("start_date", timedelta(days=-2), "START"),
+    ],
+)
+def test_get_alarm_trigger_property(alarms, file, trigger, related):
+    """Get the trigger property."""
+    alarm = alarms[file]
+    assert alarm.TRIGGER == trigger
+    assert alarm.TRIGGER_RELATED == related
+
+
+def test_set_alarm_trigger():
+    """Set the alarm trigger."""
+    a = Alarm()
+    a.TRIGGER = timedelta(hours=1)
+    assert a.TRIGGER == timedelta(hours=1)
+    assert a.TRIGGER_RELATED == "START"
+
+
+def test_set_alarm_trigger_related():
+    """Set the alarm trigger."""
+    a = Alarm()
+    a.TRIGGER = timedelta(hours=1)
+    a.TRIGGER_RELATED = "END"
+    assert a.TRIGGER == timedelta(hours=1)
+    assert a.TRIGGER_RELATED == "END"
+
+
+def test_get_related_without_trigger():
+    """The default is start"""
+    assert Alarm().TRIGGER_RELATED == "START"
+
+
+def test_cannot_set_related_without_trigger():
+    """TRIGGER must be set to set the parameter."""
+    with pytest.raises(ValueError) as e:
+        a = Alarm()
+        a.TRIGGER_RELATED = "END"
+    assert (
+        e.value.args[0]
+        == "You must set a TRIGGER before setting the RELATED parameter."
+    )
+
+
+@pytest.mark.parametrize(
+    ("file", "triggers"),
+    [
+        (
+            "rfc_5545_absolute_alarm_example",
+            (
+                (),
+                (),
+                (
+                    vDatetime.from_ical("19970317T133000Z"),
+                    vDatetime.from_ical("19970317T134500Z"),
+                    vDatetime.from_ical("19970317T140000Z"),
+                    vDatetime.from_ical("19970317T141500Z"),
+                    vDatetime.from_ical("19970317T143000Z"),
+                ),
+            ),
+        ),
+        ("rfc_5545_end", ((), (timedelta(days=-2),), ())),
+        ("start_date", ((timedelta(days=-2),), (), ())),
+    ],
+)
+def test_get_alarm_triggers(alarms, file, triggers):
+    """Get the trigger property."""
+    alarm = alarms[file]
+    print(tuple(alarm.triggers))
+    print(triggers)
+    assert alarm.triggers == triggers
+
+
+def test_triggers_emtpy_alarm():
+    """An alarm with no trigger has no triggers."""
+    assert Alarm().triggers == ((), (), ())
+
+
+h1 = timedelta(hours=1)
+
+
+def test_triggers_emtpy_with_no_repeat():
+    """Check incomplete values."""
+    a = Alarm()
+    a.TRIGGER = h1
+    a.DURATION = h1
+    assert a.triggers == ((h1,), (), ())
+
+
+def test_triggers_emtpy_with_no_duration():
+    """Check incomplete values."""
+    a = Alarm()
+    a.TRIGGER = h1
+    a.REPEAT = 10
+    assert a.triggers == ((h1,), (), ())
+
+
+@pytest.mark.parametrize(
+    ("file", "triggers"),
+    [
+        (
+            "rfc_5545_absolute_alarm_example",
+            ((), (), (vDatetime.from_ical("19970317T133000Z"),)),
+        ),
+        ("rfc_5545_end", ((), (timedelta(days=-2),), ())),
+        ("start_date", ((timedelta(days=-2),), (), ())),
+    ],
+)
+@pytest.mark.parametrize("duration", [timedelta(days=-1), h1])
+@pytest.mark.parametrize("repeat", [1, 3])
+def test_get_alarm_triggers_repeated(alarms, file, triggers, duration, repeat):
+    """Get the trigger property."""
+    alarm = alarms[file].copy()
+    alarm.REPEAT = repeat
+    alarm.DURATION = duration
+    for expected, triggers in zip(triggers, alarm.triggers):
+        if not expected:
+            assert triggers == ()
+            continue
+        assert len(triggers) == 1 + repeat
+        assert triggers[0] == expected[0]
+        for x, y in zip(triggers[:-1], triggers[1:]):
+            assert y - x == duration
diff -pruN 6.0.1-3/src/icalendar/tests/test_issue_716_alarm_time_computation.py 6.3.1-1/src/icalendar/tests/test_issue_716_alarm_time_computation.py
--- 6.0.1-3/src/icalendar/tests/test_issue_716_alarm_time_computation.py	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/test_issue_716_alarm_time_computation.py	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,438 @@
+"""Test the alarm time computation.
+
+Events can have alarms.
+Alarms can be in this state:
+
+- active - the user wants the alarm to pop up
+- acknowledged - the user no longer wants the alarm
+- snoozed - the user moved that alarm to another time
+
+The alarms can only work on the properties of the event like
+DTSTART, DTEND, and DURATION.
+
+"""
+
+from datetime import date, datetime, timedelta, timezone
+
+import pytest
+
+from icalendar import Event
+from icalendar.alarms import Alarms
+from icalendar.cal import Alarm
+from icalendar.error import IncompleteAlarmInformation
+from icalendar.prop import vDatetime
+from icalendar.tools import normalize_pytz
+
+UTC = timezone.utc
+EXAMPLE_TRIGGER = datetime(1997, 3, 17, 13, 30, tzinfo=UTC)
+
+
+def test_absolute_alarm_time_rfc_example(alarms):
+    """Check that the absolute alarm is recognized.
+
+    The following example is for a "VALARM" calendar component
+    that specifies an audio alarm that will sound at a precise time
+    and repeat 4 more times at 15-minute intervals:
+    """
+    a = Alarms(alarms.rfc_5545_absolute_alarm_example)
+    times = a.times
+    assert len(times) == 5
+    for i, t in enumerate(times):
+        assert t.trigger == EXAMPLE_TRIGGER + timedelta(minutes=15 * i)
+
+
+alarm_1 = Alarm()
+alarm_1.add("TRIGGER", EXAMPLE_TRIGGER)
+alarm_2 = Alarm()
+alarm_2["TRIGGER"] = vDatetime(EXAMPLE_TRIGGER)
+
+
+@pytest.mark.parametrize("alarm", [alarm_1, alarm_2])
+def test_absolute_alarm_time_with_vDatetime(alarm):
+    """Check that the absolute alarm is recognized.
+
+    The following example is for a "VALARM" calendar component
+    that specifies an audio alarm that will sound at a precise time
+    and repeat 4 more times at 15-minute intervals:
+    """
+    a = Alarms(alarm)
+    times = a.times
+    assert len(times) == 1
+    assert times[0].trigger == EXAMPLE_TRIGGER
+
+
+alarm_incomplete_1 = Alarm()
+alarm_incomplete_1.TRIGGER = timedelta(hours=2)
+alarm_incomplete_1.DURATION = timedelta(hours=1)
+alarm_incomplete_2 = Alarm()
+alarm_incomplete_2.TRIGGER = timedelta(hours=2)
+alarm_incomplete_2.REPEAT = 100
+
+
+@pytest.mark.parametrize("alarm", [alarm_incomplete_1, alarm_incomplete_2])
+def test_alarm_has_only_one_of_repeat_or_duration(alarm):
+    """This is an edge case and we should ignore the repetition."""
+    a = Alarms(alarm)
+    a.set_start(datetime(2027, 12, 2))
+    assert len(a.times) == 1
+
+
+@pytest.fixture(params=[(0, timedelta(minutes=-30)), (1, timedelta(minutes=-25))])
+def alarm_before_start(calendars, request):
+    """An example alarm relative to the start of a component."""
+    index, td = request.param
+    alarm = calendars.alarm_etar_future.subcomponents[-1].subcomponents[index]
+    assert isinstance(alarm, Alarm)
+    assert alarm.get("TRIGGER").dt == td
+    alarm.test_td = td
+    return alarm
+
+
+def test_cannot_compute_relative_alarm_without_start(alarm_before_start):
+    """We have an alarm without a start of a component."""
+    with pytest.raises(IncompleteAlarmInformation) as e:
+        Alarms(alarm_before_start).times  # noqa: B018
+    assert (
+        e.value.args[0]
+        == f"Use {Alarms.__name__}.{Alarms.set_start.__name__} because at least one alarm is relative to the start of a component."
+    )
+
+
+@pytest.mark.parametrize(
+    ("dtstart", "timezone", "trigger"),
+    [
+        (
+            datetime(2024, 10, 29, 13, 10),
+            "UTC",
+            datetime(2024, 10, 29, 13, 10, tzinfo=UTC),
+        ),
+        (date(2024, 11, 16), None, datetime(2024, 11, 16, 0, 0)),
+        (
+            datetime(2024, 10, 29, 13, 10),
+            "Asia/Singapore",
+            datetime(2024, 10, 29, 5, 10, tzinfo=UTC),
+        ),
+        (datetime(2024, 10, 29, 13, 20), None, datetime(2024, 10, 29, 13, 20)),
+    ],
+)
+def test_can_complete_relative_calculation_if_a_start_is_given(
+    alarm_before_start, dtstart, timezone, trigger, tzp
+):
+    """The start is given and required."""
+    start = dtstart if timezone is None else tzp.localize(dtstart, timezone)
+    alarms = Alarms(alarm_before_start)
+    alarms.set_start(start)
+    assert len(alarms.times) == 1
+    time = alarms.times[0]
+    expected_trigger = normalize_pytz(trigger + alarm_before_start.test_td)
+    assert time.trigger == expected_trigger
+
+
+@pytest.mark.parametrize("dtstart", [date(1998, 10, 1), date(2023, 12, 31)])
+def test_start_as_date_with_delta_as_date_stays_date(alarms, dtstart):
+    """If we have an alarm with a day delta and the event is a day event, we should stay as a date."""
+    a = Alarms(alarms.start_date)
+    a.set_start(dtstart)
+    assert len(a.times) == 1
+    assert a.times[0].trigger == dtstart - timedelta(days=2)
+
+
+def test_cannot_compute_relative_alarm_without_end(alarms):
+    """We have an alarm without an end of a component."""
+    with pytest.raises(IncompleteAlarmInformation) as e:
+        Alarms(alarms.rfc_5545_end).times  # noqa: B018
+    assert (
+        e.value.args[0]
+        == f"Use {Alarms.__name__}.{Alarms.set_end.__name__} because at least one alarm is relative to the end of a component."
+    )
+
+
+@pytest.mark.parametrize(
+    ("dtend", "timezone", "trigger"),
+    [
+        (
+            datetime(2024, 10, 29, 13, 10),
+            "UTC",
+            datetime(2024, 10, 29, 13, 10, tzinfo=UTC),
+        ),
+        (date(2024, 11, 16), None, date(2024, 11, 16)),
+        (
+            datetime(2024, 10, 29, 13, 10),
+            "Asia/Singapore",
+            datetime(2024, 10, 29, 5, 10, tzinfo=UTC),
+        ),
+        (datetime(2024, 10, 29, 13, 20), None, datetime(2024, 10, 29, 13, 20)),
+    ],
+)
+def test_can_complete_relative_calculation(alarms, dtend, timezone, trigger, tzp):
+    """The start is given and required."""
+    start = dtend if timezone is None else tzp.localize(dtend, timezone)
+    alarms = Alarms(alarms.rfc_5545_end)
+    alarms.set_end(start)
+    assert len(alarms.times) == 1
+    time = alarms.times[0]
+    expected_trigger = normalize_pytz(trigger - timedelta(days=2))
+    assert time.trigger == expected_trigger
+
+
+@pytest.mark.parametrize("dtend", [date(1998, 10, 1), date(2023, 12, 31)])
+def test_end_as_date_with_delta_as_date_stays_date(alarms, dtend):
+    """If we have an alarm with a day delta and the event is a day event, we should stay as a date."""
+    a = Alarms(alarms.rfc_5545_end)
+    a.set_end(dtend)
+    assert len(a.times) == 1
+    assert a.times[0].trigger == dtend - timedelta(days=2)
+
+
+def test_add_multiple_alarms(alarms):
+    """We can add multiple alarms."""
+    a = Alarms()
+    a.add_alarm(alarms.start_date)
+    a.add_alarm(alarms.rfc_5545_end)
+    a.add_alarm(alarms.rfc_5545_absolute_alarm_example)
+    with pytest.raises(IncompleteAlarmInformation):
+        a.times  # noqa: B018
+    a.set_start(datetime(2012, 3, 5))
+    with pytest.raises(IncompleteAlarmInformation):
+        a.times  # noqa: B018
+    a.set_end(datetime(2012, 3, 5))
+    assert len(a.times) == 7
+
+
+def test_alarms_from_event_have_right_times(calendars):
+    """We can collect from an event."""
+    event = calendars.alarm_etar_future.subcomponents[-1]
+    a = Alarms(event)
+    assert len(a.times) == 3
+    assert a.times[0].parent == event
+
+
+def test_cannot_set_the_event_twice(calendars):
+    """We cannot set an event twice. This make the state ambiguous."""
+    event = calendars.alarm_etar_future.subcomponents[-1]
+    a = Alarms()
+    a.add_component(event)
+    a.add_component(event)  # same component is ok
+    with pytest.raises(ValueError):
+        a.add_component(calendars.alarm_google_future.subcomponents[-1])
+
+
+@pytest.mark.parametrize(
+    ("calendar", "index", "count", "message"),
+    [
+        ("alarm_etar_future", -1, 3, "Etar (1): we just created the alarm"),
+        ("alarm_etar_notification", -1, 2, "Etar (2): the notification popped up"),
+        (
+            "alarm_etar_notification_clicked",
+            -1,
+            0,
+            "Etar (3): the notification was dismissed",
+        ),  # TODO: check that that is really true
+        (
+            "alarm_google_future",
+            -1,
+            4,
+            "Google (1): we just created the event with alarms",
+        ),
+        (
+            "alarm_google_acknowledged",
+            -1,
+            2,
+            "Google (2): 2 alarms happened at the same time",
+        ),
+        ("alarm_thunderbird_future", -1, 2, "Thunderbird (1.1): 2 alarms are set"),
+        (
+            "alarm_thunderbird_snoozed_until_1457",
+            -1,
+            2,
+            "Thunderbird (1.2): 2 alarms are snoozed to another time",
+        ),
+        (
+            "alarm_thunderbird_closed",
+            -1,
+            0,
+            "Thunderbird (1.3): all alarms are dismissed (closed)",
+        ),
+        ("alarm_thunderbird_2_future", -1, 2, "Thunderbird (2.1): 2 alarms active"),
+        (
+            "alarm_thunderbird_2_notification_popped_up",
+            -1,
+            2,
+            "Thunderbird (2.2): one alarm popped up as a notification",
+        ),
+        (
+            "alarm_thunderbird_2_notification_5_min_postponed",
+            -1,
+            2,
+            "Thunderbird (2.3): 1 alarm active and one postponed by 5 minutes",
+        ),
+        (
+            "alarm_thunderbird_2_notification_5_min_postponed_and_popped_up",
+            -1,
+            2,
+            "Thunderbird (2.4): 1 alarm active and one postponed by 5 minutes and now popped up",
+        ),
+        (
+            "alarm_thunderbird_2_notification_5_min_postponed_and_closed",
+            -1,
+            1,
+            "Thunderbird (2.5): 1 alarm active and one postponed by 5 minutes and is now acknowledged",
+        ),
+    ],
+)
+def test_number_of_active_alarms_from_calendar_software(
+    calendars, calendar, index, count, message
+):
+    """Check that we extract calculate the correct amount of active alarms."""
+    event = calendars[calendar].subcomponents[index]
+    a = Alarms(event)
+    active_alarms = (
+        a.active
+    )  # We do not need to pass a timezone because the events have a timezone
+    assert (
+        len(active_alarms) == count
+    ), f"{message} - I expect {count} alarms active but got {len(active_alarms)}."
+
+
+three_alarms = Alarm()
+three_alarms.REPEAT = 2
+three_alarms.add("DURATION", timedelta(hours=1))  # 2 hours & 1 hour before
+three_alarms.add("TRIGGER", -timedelta(hours=3))  # 3 hours before
+
+
+@pytest.mark.parametrize(
+    ("start", "acknowledged", "timezone", "count"),
+    [
+        (datetime(2024, 10, 10), datetime(2024, 10, 9), "UTC", 3),
+        (datetime(2024, 10, 10, 12), datetime(2024, 10, 10, 9, 1), "UTC", 2),
+        (datetime(2024, 10, 10, 12), datetime(2024, 10, 10, 10, 1), "UTC", 1),
+        (datetime(2024, 10, 10, 12), datetime(2024, 10, 10, 11, 1), "UTC", 0),
+        (
+            datetime(2024, 10, 10, 12, tzinfo=timezone.utc),
+            datetime(2024, 10, 10, 11, 1),
+            None,
+            0,
+        ),
+    ],
+)
+def test_number_of_active_alarms_with_moving_time(
+    start, acknowledged, count, tzp, timezone
+):
+    """Check how many alarms are active after a time they are acknowledged."""
+    a = Alarms()
+    a.add_alarm(three_alarms)
+    a.set_start(start)
+    a.set_local_timezone(timezone)
+    a.acknowledge_until(tzp.localize_utc(acknowledged))
+    active = a.active
+    assert len(active) == count
+
+
+def test_incomplete_alarm_information_for_active_state(tzp):
+    """Make sure we throw the right error."""
+    a = Alarms()
+    a.add_alarm(three_alarms)
+    a.set_start(date(2017, 12, 1))
+    a.acknowledge_until(tzp.localize_utc(datetime(2012, 10, 10, 12)))
+    with pytest.raises(IncompleteAlarmInformation) as e:
+        a.active  # noqa: B018
+    assert (
+        e.value.args[0]
+        == f"A local timezone is required to check if the alarm is still active. Use Alarms.{Alarms.set_local_timezone.__name__}()."
+    )
+
+
+@pytest.mark.parametrize(
+    "calendar_name",
+    [
+        "alarm_etar_future",
+        "alarm_google_acknowledged",
+        "alarm_thunderbird_closed",
+        "alarm_thunderbird_future",
+        "alarm_thunderbird_snoozed_until_1457",
+    ],
+)
+def test_thunderbird_recognition(calendars, calendar_name):
+    """Check if we correctly discover Thunderbird's alarm algorithm."""
+    calendar = calendars[calendar_name]
+    event = calendar.subcomponents[-1]
+    assert isinstance(event, Event)
+    assert event.is_thunderbird() == ("thunderbird" in calendar_name)
+
+
+@pytest.mark.parametrize(
+    "snooze",
+    [
+        datetime(2012, 10, 10, 11, 1),  # before everything
+        datetime(2017, 12, 1, 10, 1),
+        datetime(2017, 12, 1, 11, 1),
+        datetime(2017, 12, 1, 12, 1),
+        datetime(2017, 12, 1, 13, 1),  # snooze until after the start of the event
+    ],
+)
+def test_snoozed_alarm_has_trigger_at_snooze_time(tzp, snooze):
+    """When an alarm is snoozed, it pops up after the snooze time."""
+    a = Alarms()
+    a.add_alarm(three_alarms)
+    a.set_start(datetime(2017, 12, 1, 13))
+    a.set_local_timezone("UTC")
+    snooze_utc = tzp.localize_utc(snooze)
+    a.snooze_until(snooze_utc)
+    active = a.active
+    assert len(active) == 3
+    for alarm in active:
+        assert alarm.trigger >= snooze_utc
+
+
+@pytest.mark.parametrize(
+    ("event_index", "alarm_times"),
+    [
+        # Assume that we have the following event with an alarm set to trigger 15 minutes before the meeting:
+        (1, ("20210302T101500",)),
+        # When the alarm is triggered, the user decides to "snooze" it for 5 minutes.
+        # The client acknowledges the original alarm and creates a new "snooze"
+        # alarm as a sibling of, and relates it to, the original alarm (note that
+        # both occurrences of "VALARM" reside within the same "parent" VEVENT):
+        (2, ("20210302T102000",)),
+        # When the "snooze" alarm is triggered, the user decides to "snooze" it
+        # again for an additional 5 minutes. The client once again acknowledges
+        # the original alarm, removes the triggered "snooze" alarm, and creates another
+        # new "snooze" alarm as a sibling of, and relates it to, the original alarm
+        # (note the different UID for the new "snooze" alarm):
+        (3, ("20210302T102500",)),
+        # When the second "snooze" alarm is triggered, the user decides to dismiss it.
+        # The client acknowledges both the original alarm and the second "snooze" alarm:
+        (4, ()),
+    ],
+)
+def test_rfc_9074_alarm_times(events, event_index, alarm_times):
+    """Test the examples from the RFC and their timing.
+
+    Add times use America/New_York as timezone.
+    """
+    a = events[f"rfc_9074_example_{event_index}"].alarms
+    assert len(a.active) == len(alarm_times)
+    expected_alarm_times = {
+        vDatetime.from_ical(t, "America/New_York") for t in alarm_times
+    }
+    computed_alarm_times = {alarm.trigger for alarm in a.active}
+    assert expected_alarm_times == computed_alarm_times
+
+
+def test_set_to_None():
+    """acknowledge_until, snooze_until, set_local_timezone."""
+    a = Alarms()
+    a.set_start(None)
+    a.set_end(None)
+    a.set_local_timezone(None)
+    a.acknowledge_until(None)
+    a.snooze_until(None)
+    assert vars(a) == vars(Alarms())
+
+
+def test_delete_TRIGGER():
+    """Delete the TRIGGER property."""
+    a = Alarm()
+    a.TRIGGER = datetime(2017, 12, 1, 10, 1)
+    del a.TRIGGER
+    assert a.TRIGGER is None
diff -pruN 6.0.1-3/src/icalendar/tests/test_issue_720_uid_property.py 6.3.1-1/src/icalendar/tests/test_issue_720_uid_property.py
--- 6.0.1-3/src/icalendar/tests/test_issue_720_uid_property.py	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/test_issue_720_uid_property.py	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,12 @@
+"""This tests the UID property.
+
+See https://github.com/collective/icalendar/issues/740
+"""
+
+from icalendar import Alarm
+
+
+def test_alarm_uses_x_property_too():
+    alarm = Alarm()
+    alarm["X-ALARMUID"] = "1234"
+    assert alarm.uid == "1234"
diff -pruN 6.0.1-3/src/icalendar/tests/test_issue_722_generate_vtimezone.py 6.3.1-1/src/icalendar/tests/test_issue_722_generate_vtimezone.py
--- 6.0.1-3/src/icalendar/tests/test_issue_722_generate_vtimezone.py	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/test_issue_722_generate_vtimezone.py	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,437 @@
+"""Generate VTIMEZONE components from actual timezone information.
+
+When we generate VTIMEZONE from actual tzinfo instances of
+- dateutil
+- zoneinfo
+- pytz
+
+Then, we cannot assume that the future information stays the same but
+we should be able to create tests that work for the past.
+"""
+
+from datetime import date, datetime, timedelta
+from re import findall
+
+import pytest
+from dateutil.tz import gettz
+
+try:
+    from zoneinfo import available_timezones
+except ImportError:
+    from backports.zoneinfo import available_timezones
+
+from icalendar import Calendar, Component, Event, Timezone
+from icalendar.timezone import tzid_from_tzinfo, tzids_from_tzinfo
+
+tzids = pytest.mark.parametrize(
+    "tzid",
+    [
+        "Europe/Berlin",
+        "Asia/Singapore",
+        "America/New_York",
+    ],
+)
+
+
+def assert_components_equal(c1: Component, c2: Component):
+    """Print the diff of two components."""
+    ML = 32
+    ll1 = c1.to_ical().decode().splitlines()
+    ll2 = c2.to_ical().decode().splitlines()
+    pad = max(len(l) for l in ll1 if len(l) <= ML)
+    diff = 0
+    for l1, l2 in zip(ll1, ll2):
+        a = len(l1) > 32 or len(l2) > 32
+        print(
+            a * "  " + l1,
+            " " * (pad - len(l1)),
+            a * "\n->" + l2,
+            " " * (pad - len(l2)),
+            "\tdiff!" if l1 != l2 else "",
+        )
+        diff += l1 != l2
+    assert not diff, f"{diff} lines differ"
+
+
+@tzids
+def test_conversion_converges(tzp, tzid):
+    """tzinfo -> VTIMEZONE -> tzinfo -> VTIMEZONE
+
+    We can assume that both generated VTIMEZONEs are equivalent.
+    """
+    if tzp.uses_pytz():
+        pytest.skip(
+            "pytz will not converge on the first run. This is problematic. PYTZ-TODO"
+        )
+    tzinfo1 = tzp.timezone(tzid)
+    assert tzinfo1 is not None
+    generated1 = Timezone.from_tzinfo(tzinfo1)
+    generated1["TZID"] = (
+        "test-generated"  # change the TZID so we do not use an existing one
+    )
+    tzinfo2 = generated1.to_tz()
+    generated2 = Timezone.from_tzinfo(tzinfo2, "test-generated")
+    tzinfo3 = generated2.to_tz()
+    generated3 = Timezone.from_tzinfo(tzinfo3, "test-generated")
+    # pprint(generated1.get_transitions())
+    # pprint(generated2.get_transitions())
+    assert_components_equal(generated1, generated2)
+    assert_components_equal(generated2, generated3)
+    assert 2 <= len(generated1.standard + generated1.daylight) <= 3
+    assert 2 <= len(generated2.standard + generated2.daylight) <= 3
+    assert dict(generated1) == dict(generated2)
+    assert generated1.to_ical().decode() == generated2.to_ical().decode()
+    assert generated1.daylight == generated2.daylight
+    assert generated1.standard == generated2.standard
+    assert generated1 == generated2
+
+
+@tzids
+def both_tzps_generate_the_same_info(tzid, tzp):
+    """We want to make sure that we get the same info for all timezone implementations.
+
+    We assume that
+    - the timezone implementations have the same info within the days we test
+    - the timezone transitions times do not change because they are before last_date
+    """
+    # default generation
+    tz1 = Timezone.from_tzid(tzid, tzp, last_date=date(2024, 1, 1))
+    tzp.use_zoneinfo()  # we compare to zoneinfo
+    tz2 = Timezone.from_tzid(tzid, tzp, last_date=date(2024, 1, 1))
+    assert_components_equal(tz1, tz2)
+    assert tz1 == tz2
+
+
+@tzids
+def test_tzid_matches(tzid, tzp):
+    """Check the TZID."""
+    tz = Timezone.from_tzinfo(tzp.timezone(tzid))
+    assert tz["TZID"] == tzid
+
+
+def test_do_not_convert_utc(tzp):
+    """We do not need to convert UTC but it should work."""
+    utc = Timezone.from_tzid("UTC")
+    assert utc.daylight == []
+    assert len(utc.standard) == 1
+    standard = utc.standard[0]
+    assert standard["TZOFFSETFROM"].td == timedelta(0)
+    assert standard["TZOFFSETTO"].td == timedelta(0)
+    assert standard["TZNAME"] == "UTC"
+
+
+def test_berlin_time(tzp):
+    """Test the Europe/Berlin timezone conversion."""
+    tz = Timezone.from_tzid("Europe/Berlin")
+    # we should have two timezones in it
+    for x in tz.standard:
+        print(x.name, x["TZNAME"], x["TZOFFSETFROM"].td, x["TZOFFSETTO"].td)
+        print(x.to_ical().decode())
+    assert len(tz.daylight) == 1
+    assert len(tz.standard) in (1, 2), "We start in winter"
+    dst = tz.daylight[-1]
+    sta = tz.standard[-1]
+    assert dst["TZNAME"] == "CEST"  # summer
+    assert sta["TZNAME"] == "CET"
+    assert dst["TZOFFSETFROM"].td == timedelta(hours=1)  # summer
+    assert sta["TZOFFSETFROM"].td == timedelta(hours=2)
+    assert dst["TZOFFSETTO"].td == timedelta(hours=2)  # summer
+    assert sta["TZOFFSETTO"].td == timedelta(hours=1)
+
+
+def test_range_is_not_crossed():
+    first_date = datetime(2023, 1, 1)
+    last_date = datetime(2024, 1, 1)
+
+    def check(dt):
+        assert first_date <= dt <= last_date
+
+    tz = Timezone.from_tzid("Europe/Berlin", last_date=last_date, first_date=first_date)
+    for sub in tz.standard + tz.daylight:
+        check(sub.DTSTART)
+        for rdate in sub.get("RDATE", []):
+            check(rdate)
+
+
+@tzids
+def test_use_the_original_timezone(tzid, tzp):
+    """When we get the timezone again, usually, we should use the
+    one of the library/tzp."""
+    tzinfo1 = tzp.timezone(tzid)
+    assert tzinfo1 is not None
+    generated1 = Timezone.from_tzinfo(tzinfo1)
+    tzinfo2 = generated1.to_tz()
+    assert type(tzinfo1) == type(tzinfo2)
+    assert tzinfo1 == tzinfo2
+
+
+@pytest.mark.parametrize(
+    ("tzid", "dt", "tzname"),
+    [
+        ("Asia/Singapore", datetime(1970, 1, 1), "+0730"),
+        ("Asia/Singapore", datetime(1981, 12, 31), "+0730"),
+        ("Asia/Singapore", datetime(1981, 12, 31, 23, 10), "+0730"),
+        ("Asia/Singapore", datetime(1981, 12, 31, 23, 34), "+0730"),
+        ("Asia/Singapore", datetime(1981, 12, 31, 23, 59, 59), "+0730"),
+        ("Asia/Singapore", datetime(1982, 1, 1), "+08"),
+        ("Asia/Singapore", datetime(1982, 1, 1, 0, 1), "+08"),
+        ("Asia/Singapore", datetime(1982, 1, 1, 0, 34), "+08"),
+        ("Asia/Singapore", datetime(1982, 1, 1, 1, 0), "+08"),
+        ("Asia/Singapore", datetime(1982, 1, 1, 1, 1), "+08"),
+        ("Europe/Berlin", datetime(1970, 1, 1), "CET"),
+        ("Europe/Berlin", datetime(2024, 3, 31, 0, 0), "CET"),
+        ("Europe/Berlin", datetime(2024, 3, 31, 1, 0), "CET"),
+        ("Europe/Berlin", datetime(2024, 3, 31, 2, 0), "CET"),
+        ("Europe/Berlin", datetime(2024, 3, 31, 2, 59, 59), "CET"),
+        ("Europe/Berlin", datetime(2024, 3, 31, 3, 0), "CEST"),
+        ("Europe/Berlin", datetime(2024, 3, 31, 3, 0, 1), "CEST"),
+        ("Europe/Berlin", datetime(2024, 3, 31, 4, 0), "CEST"),
+        ("Europe/Berlin", datetime(2024, 10, 27, 0, 0), "CEST"),
+        ("Europe/Berlin", datetime(2024, 10, 27, 1, 0), "CEST"),
+        ("Europe/Berlin", datetime(2024, 10, 27, 2, 0), "CEST"),
+        ("Europe/Berlin", datetime(2024, 10, 27, 2, 30), "CEST"),
+        ("Europe/Berlin", datetime(2024, 10, 27, 2, 59, 59), "CEST"),
+        ("Europe/Berlin", datetime(2024, 10, 27, 3, 0), "CET"),
+        ("Europe/Berlin", datetime(2024, 10, 27, 3, 0, 1), "CET"),
+        ("Europe/Berlin", datetime(2024, 10, 27, 4, 0), "CET"),
+        # transition times from https://www.zeitverschiebung.net/de/timezone/america--new_york
+        ("America/New_York", datetime(1970, 1, 1), "EST"),
+        # Daylight Saving Time
+        ("America/New_York", datetime(2024, 11, 3, 0, 0), "EDT"),
+        ("America/New_York", datetime(2024, 11, 3, 1, 0), "EDT"),
+        ("America/New_York", datetime(2024, 11, 3, 1, 59, 59), "EDT"),
+        # 03.11.2024 2:00am -> 1:00am Standard
+        # ("America/New_York", datetime(2024, 11, 3, 2, 0), "EDT"),
+        ("America/New_York", datetime(2024, 11, 3, 2, 0, 1), "EST"),
+        ("America/New_York", datetime(2024, 11, 3, 3, 0), "EST"),
+        ("America/New_York", datetime(2025, 3, 9, 1, 0), "EST"),
+        ("America/New_York", datetime(2025, 3, 9, 1, 59, 59), "EST"),
+        ("America/New_York", datetime(2025, 3, 9, 2, 0), "EST"),
+        # 09.03.2025 2:00am -> 3:00am Daylight Saving Time
+        ("America/New_York", datetime(2025, 3, 9, 3, 0), "EDT"),
+        ("America/New_York", datetime(2025, 3, 9, 3, 1, 1), "EDT"),
+        ("America/New_York", datetime(2025, 3, 9, 4, 0), "EDT"),
+    ],
+)
+def test_check_datetimes_around_transition_times(tzp, tzid, dt, tzname):
+    """We should make sure than the datetimes with the generated timezones
+    work as expected: They have the right UTC offset, dst and tzname.
+    """
+    message = f"{tzid}: {dt} (expected in {tzname})"
+    expected_dt = tzp.localize(dt, tzid)
+    component = Timezone.from_tzinfo(tzp.timezone(tzid))
+    generated_tzinfo = component.to_tz(tzp, lookup_tzid=False)
+    generated_dt = dt.replace(tzinfo=generated_tzinfo)
+    print(generated_tzinfo)
+    if tzp.uses_pytz():
+        # generated_dt = generated_tzinfo.localize(dt)
+        generated_dt = generated_tzinfo.normalize(generated_dt)
+        if dt in (
+            datetime(2024, 10, 27, 1, 0),
+            datetime(2024, 11, 3, 1, 59, 59),
+            datetime(2024, 11, 3, 1, 0),
+            datetime(2024, 11, 3, 0, 0),
+            datetime(2024, 10, 27, 2, 59, 59),
+            datetime(2024, 10, 27, 2, 30),
+            datetime(2024, 10, 27, 2, 0),
+            datetime(2024, 10, 27, 1, 0),
+        ):
+            pytest.skip("We do not know how to do this. PYTZ-TODO")
+    assert generated_dt.tzname() == expected_dt.tzname() == tzname, message
+    assert generated_dt.dst() == expected_dt.dst(), message
+    assert generated_dt.utcoffset() == expected_dt.utcoffset(), message
+
+
+@pytest.mark.parametrize("uid", [0, 1, 2, 3])
+def test_dateutil_timezone_when_time_is_going_backwards(calendars, tzp, uid):
+    """When going from Daylight Saving Time to Standard Time, times can be ambiguous.
+    For example, at 3:00 AM, the time falls back to 2:00 AM, repeating a full hour of times from 2:00 AM to 3:00 AM on the same date.
+
+    By the RFC 5545, we cannot accommodate this case. All datetimes should
+    be BEFORE the transition if ambiguous. However, dateutil can
+    create a timezone that allows the event to be after this ambiguous time span, of course.
+
+    Each event has its timezone saved in it.
+    """
+    cal: Calendar = calendars.issue_722_timezone_transition_ambiguity
+    event: Event = cal.events[uid]
+    expected_tzname = str(event["X-TZNAME"])
+    actual_tzname = event.start.tzname()
+    assert actual_tzname == expected_tzname, event["SUMMARY"]
+
+
+def query_tzid(query: str, cal: Calendar) -> str:
+    """The tzid from the query."""
+    try:
+        tzinfo = eval(query, {"cal": cal})  # noqa: S307
+    except Exception as e:
+        raise ValueError(query) from e
+    return tzid_from_tzinfo(tzinfo)
+
+
+# these are queries for all the places that have a TZID
+# according to RFC 5545
+queries = [
+    "cal.events[0].start.tzinfo",  # DTSTART
+    "cal.events[0].end.tzinfo",  # DTEND
+    # EXDATE
+    "cal.todos[0].end.tzinfo",  # DUE
+    "cal.events[0].get('RDATE').dts[0].dt[0].tzinfo",  # RDATE
+    "cal.events[1].get('RECURRENCE-ID').dt.tzinfo",  # RECURRENCE-ID
+    "cal.events[2].get('RDATE')[0].dts[0].dt.tzinfo",  # RDATE multiple
+    "cal.events[2].get('RDATE')[1].dts[0].dt.tzinfo",  # RDATE multiple
+]
+
+
+@pytest.mark.parametrize("query", queries)
+def test_add_missing_timezones_to_example(calendars, query):
+    """Add the missing timezones to the calendar."""
+    cal = calendars.issue_722_missing_timezones
+    tzid = query_tzid(query, cal)
+    tzs = cal.get_missing_tzids()
+    assert tzid in tzs
+
+
+def test_queries_yield_unique_tzids(calendars):
+    """We make sure each query tests a unique place to find for the algorithm."""
+    cal = calendars.issue_722_missing_timezones
+    tzids = set()
+    for query in queries:
+        tzid = query_tzid(query, cal)
+        print(query, "->", tzid)
+        tzids.add(tzid)
+    assert len(tzids) == len(queries)
+
+
+def test_we_do_not_miss_to_add_a_query(calendars):
+    """Make sure all tzids are actually queried."""
+    cal = calendars.issue_722_missing_timezones
+    raw = cal.raw_ics.decode()
+    ids = set(findall("TZID=([a-zA-Z_/+-]+)", raw))
+    assert cal.get_used_tzids() == ids, "We find all tzids and they are unique."
+    assert len(ids) == len(queries), "We query all the tzids."
+
+
+def test_unknown_tzid(calendars):
+    """If we have an unknown tzid with no timezone component."""
+    cal = calendars.issue_722_missing_VTIMEZONE_custom
+    assert "CUSTOM_tzid" in cal.get_used_tzids()
+    assert "CUSTOM_tzid" in cal.get_missing_tzids()
+
+
+def test_custom_timezone_is_found_and_used(calendars):
+    """Check the custom timezone component is not missing."""
+    cal = calendars.america_new_york
+    assert "custom_America/New_York" in cal.get_used_tzids()
+    assert "custom_America/New_York" not in cal.get_missing_tzids()
+
+
+def test_not_missing_anything():
+    """Check that no timezone is missing."""
+    cal = Calendar()
+    assert cal.get_missing_tzids() == set()
+
+
+def test_utc_is_not_missing(calendars):
+    """UTC should not be found missing."""
+    cal = calendars.issue_722_missing_timezones
+    assert "UTC" not in cal.get_missing_tzids()
+    assert "UTC" not in cal.get_used_tzids()
+
+
+def test_dateutil_timezone_is_not_found_with_tzname(calendars, no_pytz):
+    """dateutil is an example of a timezone that has no tzid.
+
+    In this test we make sure that the timezone is said to be missing.
+    """
+    cal: Calendar = calendars.america_new_york
+    cal.subcomponents.remove(cal.timezones[0])
+    assert cal.get_missing_tzids() == {"custom_America/New_York"}
+    assert "dateutil" in repr(cal.events[0].start.tzinfo.__class__)
+
+
+@pytest.mark.parametrize("tzname", ["America/New_York", "Arctic/Longyearbyen"])
+# @pytest.mark.parametrize("component", ["STANDARD", "DAYLIGHT"])
+def test_dateutil_timezone_is_matched_with_tzname(tzname):
+    """dateutil is an example of a timezone that has no tzid.
+
+    In this test we make sure that the timezone is matched by its
+    tzname() in the timezone in the STANDARD and DAYLIGHT components.
+    """
+    cal = Calendar()
+    event = Event()
+    event.start = datetime(2024, 11, 12, tzinfo=gettz(tzname))
+    print(dir(event.start.tzinfo))
+    cal.add_component(event)
+    assert cal.get_missing_tzids() == {tzname}
+    cal.add_missing_timezones()
+    assert cal.get_missing_tzids() == set()
+
+
+def test_dateutil_timezone_is_also_added(calendars):
+    """We find and add a dateutil timezone.
+
+    This is important as we use those in the zoneinfo implementation.
+    """
+
+
+@pytest.mark.parametrize(
+    "calendar",
+    [
+        "example",
+        "america_new_york",  # custom
+        "timezone_same_start",  # known tzid
+        "period_with_timezone",  # known tzid
+    ],
+)
+def test_timezone_is_not_missing(calendars, calendar):
+    """Check that these calendars have no timezone missing."""
+    cal: Calendar = calendars[calendar]
+    timezones = cal.timezones[:]
+    assert set() == cal.get_missing_tzids()
+    cal.add_missing_timezones()
+    assert set() == cal.get_missing_tzids()
+    assert cal.timezones == timezones
+
+
+def test_add_missing_known_timezones(calendars):
+    """Add all timezones specified."""
+    cal: Calendar = calendars.issue_722_missing_timezones
+    assert len(cal.timezones) == 0
+    cal.add_missing_timezones()
+    assert len(cal.timezones) == len(queries), "all timezones are known"
+    assert len(cal.get_missing_tzids()) == 0
+
+
+def test_cannot_add_unknown_timezone(calendars):
+    """I cannot add a timezone that is unknown."""
+    cal: Calendar = calendars.issue_722_missing_VTIMEZONE_custom
+    assert len(cal.timezones) == 0
+    assert cal.get_missing_tzids() == {"CUSTOM_tzid"}
+    cal.add_missing_timezones()
+    assert cal.timezones == [], "we cannot add this timezone"
+    assert cal.get_missing_tzids() == {"CUSTOM_tzid"}
+
+
+def test_cannot_create_a_timezone_from_an_invalid_tzid():
+    with pytest.raises(ValueError):
+        Timezone.from_tzid("invalid/tzid")
+
+
+def test_dates_before_and_after_are_considered():
+    """When we add the timezones, we should check the calendar to see
+    if all dates really occur in the span we use.
+
+    We should also consider a huge default range.
+    """
+    pytest.skip("todo")
+
+
+@pytest.mark.parametrize("tzid", available_timezones() - {"Factory", "localtime"})
+def test_we_can_identify_dateutil_timezones(tzid):
+    """dateutil and others were badly supported.
+
+    But if we know their shortcodes, we should be able to identify them.
+    """
+    tz = gettz(tzid)
+    assert tz is None or tzid in tzids_from_tzinfo(tz)
diff -pruN 6.0.1-3/src/icalendar/tests/test_issue_798_property_parameters.py 6.3.1-1/src/icalendar/tests/test_issue_798_property_parameters.py
--- 6.0.1-3/src/icalendar/tests/test_issue_798_property_parameters.py	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/test_issue_798_property_parameters.py	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,199 @@
+"""Test the property parameters."""
+
+from datetime import datetime
+
+import pytest
+
+from icalendar import (
+    CUTYPE,
+    FBTYPE,
+    PARTSTAT,
+    RANGE,
+    RELTYPE,
+    vCalAddress,
+    vDatetime,
+    vPeriod,
+    vText,
+)
+from icalendar.parser import Parameters
+from icalendar.timezone.tzp import TZP
+
+
+class Prop:
+
+    params: Parameters
+
+    def __init__(self, **parameters):
+        """Create a new property."""
+        self.params = Parameters(parameters)
+
+    def to_ical(self) -> str:
+        """Parameters to bytes to string."""
+        return self.params.to_ical().decode("utf-8")
+
+    from icalendar.param import (
+        ALTREP,
+        CN,
+        CUTYPE,
+        DELEGATED_FROM,
+        DELEGATED_TO,
+        RELTYPE,
+    )
+
+
+@pytest.fixture()
+def p():
+    """Empty test property."""
+    return Prop()
+
+
+def test_set_altrep(p):
+    p.ALTREP = "http://example.com"
+    assert p.params == {"ALTREP": "http://example.com"}
+    assert p.ALTREP == "http://example.com"
+
+def test_altrep_must_be_quoted():
+    """altrepparam = "ALTREP" "=" DQUOTE uri DQUOTE"""
+    assert Prop(ALTREP="1234aA").to_ical() == 'ALTREP="1234aA"'
+
+def test_del_altrep(p):
+    """Del when empty"""
+    del p.ALTREP
+    assert p.params == {}
+    assert p.ALTREP is None
+
+def test_del_altrep_full(p):
+    """Del when empty"""
+    p.ALTREP = "http://example.com"
+    del p.ALTREP
+    assert p.params == {}
+    assert p.ALTREP is None
+
+
+def test_get_cutype(p):
+    """The default is individual."""
+    assert p.CUTYPE == "INDIVIDUAL"
+
+
+def test_set_lowercase():
+    p = Prop(CUTYPE="individual")
+    assert p.CUTYPE == "INDIVIDUAL"
+    p.CUTYPE = "unknown"
+    assert p.CUTYPE == CUTYPE.UNKNOWN
+
+
+def test_set_delegation_to_string(p):
+    p.DELEGATED_FROM = "mailto:foo"
+    assert p.DELEGATED_FROM == ("mailto:foo",)
+
+def test_set_delegation_to_tuple(p):
+    p.DELEGATED_TO = ("mailto:foo","mailto:bar")
+    assert p.DELEGATED_TO == ("mailto:foo","mailto:bar")
+
+def test_delete_delegation_to(p):
+    p.DELEGATED_TO = ("mailto:foo","mailto:bar")
+    del p.DELEGATED_TO
+    assert p.DELEGATED_TO == ()
+
+@pytest.mark.parametrize(
+    ("value", "expected"),
+    [
+        ((), ""),
+        (("mailto:foo",), 'DELEGATED-TO="mailto:foo"'),
+        (("mailto:foo","mailto:bar"), 'DELEGATED-TO="mailto:foo","mailto:bar"'),
+        (('mailto:"asd"',), "DELEGATED-TO=\"mailto:^'asd^'\""),
+    ]
+)
+def test_serialize_delegation_to(p, value, expected):
+    p.DELEGATED_TO = value
+    assert p.to_ical() == expected
+
+
+@pytest.mark.parametrize(
+    ("index", "expected"),
+    [
+        (0, FBTYPE.BUSY_UNAVAILABLE),
+        (1, FBTYPE.BUSY),
+        (2, FBTYPE.FREE),
+    ]
+)
+def test_get_fbtype(calendars, index, expected):
+    fb = calendars.issue_798_freebusy.freebusy[index]
+    p : vPeriod = fb["FREEBUSY"]
+    if isinstance(p, list):
+        p = p[0]
+    assert expected == p.FBTYPE
+
+
+@pytest.fixture()
+def addr():
+    return vCalAddress("mailto:foo")
+
+def test_partstat_get(addr: vCalAddress):
+    """test the default partstat"""
+    assert addr.PARTSTAT == "NEEDS-ACTION"
+
+
+def test_set_the_partstat(addr: vCalAddress):
+    addr.PARTSTAT = PARTSTAT.ACCEPTED
+    assert addr.PARTSTAT == "ACCEPTED"
+
+
+def test_this_and_future():
+    assert vDatetime(datetime(2019, 12, 10)).RANGE is None
+
+def test_this_and_future_set():
+    d = vDatetime(datetime(2019, 12, 10))
+    d.RANGE = RANGE.THISANDFUTURE
+    assert d.params["RANGE"] == "THISANDFUTURE"
+
+
+def test_rsvp_default(addr):
+    assert not addr.RSVP
+
+@pytest.mark.parametrize("rsvp", [True, False])
+def test_set_rsvp(addr: vCalAddress, rsvp):
+    addr.RSVP = rsvp
+    assert addr.RSVP == rsvp
+    assert addr.params["RSVP"] == ("TRUE" if rsvp else "FALSE")
+
+
+def test_sent_by(addr: vCalAddress):
+    assert addr.SENT_BY is None
+
+
+
+def test_set_sent_by(addr: vCalAddress):
+    addr.SENT_BY = "mailto:asd"
+    assert addr.SENT_BY == "mailto:asd"
+    assert addr.params["SENT-BY"] == "mailto:asd"
+    assert addr.params.to_ical() == b'SENT-BY="mailto:asd"'
+
+
+@pytest.mark.parametrize("tzid", [None, "Europe/Berlin"])
+def test_tzid(tzid, tzp:TZP):
+    dt = vDatetime(tzp.localize(datetime(2019, 12, 10), tzid))
+    assert dt.TZID is None
+
+
+@pytest.mark.parametrize(
+    ("index", "reltype"),
+    [
+        (0, RELTYPE.PARENT),
+        (1, RELTYPE.SIBLING),
+    ]
+)
+def test_reltype_example(calendars, index, reltype):
+    """The reltype parameter in the examples."""
+    event = calendars.issue_798_related_to.events[index]
+    print(event.to_ical().decode())
+    r : vText = event["RELATED-TO"]
+    print(r)
+    print(r.params)
+    assert reltype == r.RELTYPE
+
+
+def test_set_reltype(p):
+    p.RELTYPE = RELTYPE.CHILD
+    assert p.RELTYPE == RELTYPE.CHILD
+    assert p.params["RELTYPE"] == "CHILD"
diff -pruN 6.0.1-3/src/icalendar/tests/test_issue_802.py 6.3.1-1/src/icalendar/tests/test_issue_802.py
--- 6.0.1-3/src/icalendar/tests/test_issue_802.py	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/test_issue_802.py	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,54 @@
+"""Test the sequence and other int properies.
+
+https://www.rfc-editor.org/rfc/rfc5545#section-3.8.7.4
+https://github.com/collective/icalendar/issues/802
+
+"""
+
+import pytest
+
+from icalendar import Component, Event, Journal, Todo
+
+
+@pytest.fixture(params=[0, None])
+def default_sequence(request):
+    return request.param
+
+@pytest.fixture(params=[Event, Journal, Todo])
+def component(request, default_sequence) -> Component:
+    """Return a component."""
+    component : Component = request.param()
+    if default_sequence is not None:
+        component["SEQUENCE"] = default_sequence
+    return component
+
+
+def test_sequence_is_0(component: Component):
+    """Check the default value."""
+    assert component.sequence == 0
+
+
+def test_increase_sequence(component: Component):
+    """Check the default value."""
+    component.sequence += 1
+    assert component.sequence == 1
+    assert component["SEQUENCE"] == 1
+
+
+def test_set_sequence(component: Component):
+    """Check the default value."""
+    component.sequence = 400
+    assert component.sequence == 400
+    assert component["SEQUENCE"] == 400
+
+
+def test_delete_sequence_default(component: Component):
+    """Delete the value."""
+    del component.sequence
+    assert component.sequence == 0
+
+def test_delete_sequence_with_value(component: Component):
+    """Delete the value."""
+    component.sequence = 400
+    del component.sequence
+    assert component.sequence == 0
diff -pruN 6.0.1-3/src/icalendar/tests/test_issue_828.py 6.3.1-1/src/icalendar/tests/test_issue_828.py
--- 6.0.1-3/src/icalendar/tests/test_issue_828.py	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/test_issue_828.py	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,162 @@
+"""Events differ although their times are equal."""
+
+import contextlib
+from datetime import date, datetime, timedelta, timezone
+
+import pytest
+
+from icalendar import Event, Journal, vDate, vDatetime, vDDDLists, vDDDTypes
+
+try:
+    from zoneinfo import ZoneInfo
+except ImportError:
+    from backports.zoneinfo import ZoneInfo  # type: ignore PGH003
+
+
+def to_dt(a: date) -> date:
+    return a
+
+
+def to_event(a):
+    e = Event()
+    e.start = a
+    e.end = a + timedelta(days=1)
+    e.add("RECURRENCE-ID", a - timedelta(days=1))
+    return e
+
+
+def to_journal(a):
+    """return a journal for testing"""
+    j = Journal()
+    j.start = a
+    j.end = a + timedelta(days=1)
+    j.add("RECURRENCE-ID", a - timedelta(days=1))
+    return j
+
+
+def to_vDD(a):
+    """Return a value type."""
+    if isinstance(a, datetime):
+        return vDatetime(a)
+    return vDate(a)
+
+
+def to_vDDDTypes(a):
+    return vDDDTypes(a)
+
+
+def to_vDDDLists(a):
+    return vDDDLists([a])
+
+
+equal_dt_pairs = [
+    (date(1998, 10, 1), date(1998, 10, 1)),
+    (datetime(2023, 12, 31), datetime(2023, 12, 31)),
+    (
+        datetime(2023, 12, 31, tzinfo=timezone.utc),
+        datetime(2023, 12, 31, tzinfo=ZoneInfo("UTC")),
+    ),
+    (
+        datetime(2023, 12, 31, tzinfo=ZoneInfo("UTC")),
+        datetime(2023, 12, 31, tzinfo=ZoneInfo("UTC")),
+    ),
+    (
+        datetime(2025, 12, 31, tzinfo=ZoneInfo("UTC")),
+        datetime(2025, 12, 31, tzinfo=ZoneInfo("GMT+0")),
+    ),
+    (
+        datetime(2025, 12, 31, 12, tzinfo=ZoneInfo("Europe/Zurich")),
+        datetime(2025, 12, 31, 11, tzinfo=ZoneInfo("UTC")),
+    ),
+]
+
+
+param_equal_dts = pytest.mark.parametrize(("d1", "d2"), equal_dt_pairs)
+
+param_transform = pytest.mark.parametrize(
+    "transform", [to_dt, to_event, to_journal, to_vDD, to_vDDDTypes, to_vDDDLists]
+)
+
+
+@param_equal_dts
+@param_transform
+def test_equality_of_equal_datetimes(d1, d2, transform):
+    """Check that the values are equal."""
+    a = transform(d1)
+    b = transform(d2)
+    assert_equal(a, b)
+
+
+def assert_equal(a, b):
+    """Check all equality tests."""
+    assert a == b, f"1 equal: {a} == {b}"
+    assert b == a, f"2 equal reversed: {b} == {a}"
+    assert not a != b, f"3 not equal: {a} != {b}"  # noqa: SIM202
+    assert not b != a, f"4 not equal reversed: {b} != {a}"  # noqa: SIM202
+    assert bool(a) == bool(b), f"5 equal bool: {bool(a)} == {bool(b)}"
+    with contextlib.suppress(TypeError):
+        assert hash(a) == hash(b)
+
+
+def assert_not_eq(a, b):
+    """Check all equality tests."""
+    assert a != b, f"1 unequal: {a} == {b}"
+    assert b != a, f"2 unequal reversed: {b} == {a}"
+    assert not a == b, f"3 not unequal: {a} != {b}"  # noqa: SIM201
+    assert not b == a, f"4 not unequal reversed: {b} != {a}"  # noqa: SIM201
+
+
+dts = [to_dt, to_vDD, to_vDDDTypes, to_vDDDLists]
+
+
+@pytest.mark.parametrize("transform1", dts)
+@pytest.mark.parametrize("transform2", dts)
+@param_equal_dts
+def test_property_times_for_date_and_datetime(d1, d2, transform1, transform2):
+    """Check the equality of the date and date implementations."""
+    a = transform1(d1)
+    b = transform2(d2)
+    assert_equal(a, b)
+
+
+def test_datetime_is_in_list_representation():
+    dt = datetime(2023, 12, 31)
+    assert str(dt) in str(vDDDLists([dt]))
+
+
+unequal_pairs = [(a, b) for a, b in equal_dt_pairs if a != b]
+
+
+@pytest.mark.parametrize(("d1", "d2"), unequal_pairs)
+@param_transform
+def test_inequality(d1, d2, transform):
+    """The values are not equal."""
+    a = transform(d1)
+    b = transform(d2)
+    assert_not_eq(a, b)
+
+
+@pytest.mark.parametrize("ddd_type", [to_vDD, to_vDDDTypes])
+@param_equal_dts
+def test_not_equal_if_parameters_differ(d1, d2, ddd_type):
+    """If the items are equal but the parameters differ, they should not be equal."""
+    d1 = ddd_type(d1)
+    d2 = ddd_type(d2)
+    d1.params["foo"] = "bar"
+    assert_not_eq(d1, d2)
+
+
+@pytest.mark.parametrize("ddd_type", [to_vDD, to_vDDDTypes])
+@param_equal_dts
+def test_equal_ignoring_x_params(d1, d2, ddd_type):
+    """RFC 5545: Applications MUST ignore x-param and iana-param values they don't recognize."""
+    d1 = ddd_type(d1)
+    d2 = ddd_type(d2)
+    d1.params["x-foo"] = "bar"
+    assert_equal(d1, d2)
+
+
+def test_list_is_not_hashable():
+    """We cannot hash a list because it changes."""
+    with pytest.raises(TypeError):
+        hash(vDDDLists([datetime(2023, 12, 31)]))
diff -pruN 6.0.1-3/src/icalendar/tests/test_issue_836_do_not_quote_tzid.py 6.3.1-1/src/icalendar/tests/test_issue_836_do_not_quote_tzid.py
--- 6.0.1-3/src/icalendar/tests/test_issue_836_do_not_quote_tzid.py	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/test_issue_836_do_not_quote_tzid.py	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,80 @@
+"""Quoting the TZID parameter creates compatibility problems.
+
+See https://github.com/collective/icalendar/issues/836
+
+:rfc:`5545`:
+
+.. code-block:: text
+
+    param-value   = paramtext / quoted-string
+    paramtext     = *SAFE-CHAR
+    quoted-string = DQUOTE *QSAFE-CHAR DQUOTE
+    SAFE-CHAR     = WSP / %x21 / %x23-2B / %x2D-39 / %x3C-7E
+                   / NON-US-ASCII
+     ; Any character except CONTROL, DQUOTE, ";", ":", ","
+     NON-US-ASCII  = UTF8-2 / UTF8-3 / UTF8-4
+     ; UTF8-2, UTF8-3, and UTF8-4 are defined in [RFC3629]
+
+"""
+from datetime import datetime, time
+from icalendar import Event, Parameters, vDDDTypes, vDatetime, vPeriod, vTime
+import pytest
+
+from icalendar.prop import vDDDLists
+
+# All the controls except HTAB
+CONTROL = {
+    i for i in range(256) if 0x00 <= i <= 0x08 or 0x0A <= i <= 0x1F or i == 0x7F
+}
+
+# Any character except CONTROL, DQUOTE, ";", ":", ","
+SAFE_CHAR = set(range(256)) - CONTROL - set(b'";:,')
+
+param_tzid = pytest.mark.parametrize(
+    "tzid",
+    [
+        "Europe/London",
+        "Eastern Standard Time",
+    ]
+)
+
+@param_tzid
+@pytest.mark.parametrize(
+    "vdt",
+    [
+        vDatetime(datetime(2024, 10, 11, 12, 0)),
+        vTime(time(23, 59, 59)),
+        vDDDTypes(datetime(2024, 10, 11, 12, 0)),
+        vPeriod((datetime(2024, 10, 11, 12, 0), datetime(2024, 10, 11, 13, 0))),
+        vDDDLists([datetime(2024, 10, 11, 12, 0)]),
+    ]
+)
+def test_parameter_is_not_quoted_when_not_needed(tzid, vdt):
+    """Check that serializing the value works without quoting."""
+    e = Event()
+    vdt.params["TZID"] = tzid
+    e["DTSTART"] = vdt
+    ics = e.to_ical().decode()
+    print(ics)
+    assert tzid in ics
+    assert f'"{tzid}' not in ics
+    assert f'{tzid}"' not in ics
+
+
+@pytest.mark.parametrize(
+    "safe_char",
+    list(map(chr, sorted(SAFE_CHAR)))
+)
+def test_safe_char_is_not_escaped(safe_char):
+    """Check that paramerter serialization is without quotes for safe chars."""
+    params = Parameters(tzid=safe_char)
+    result = params.to_ical().decode()
+    assert '"'  not in result
+
+
+def test_get_calendar_and_serialize_it_wihtout_quotes(calendars):
+    """The example calendar should not contain the timezone with quotes."""
+    ics = calendars.issue_836_do_not_quote_tzid.to_ical().decode()
+    assert '"Eastern Standard' not in ics
+    assert 'Standard Time"' not in ics
+    assert "Eastern Standard Time" in ics
diff -pruN 6.0.1-3/src/icalendar/tests/test_multiple.py 6.3.1-1/src/icalendar/tests/test_multiple.py
--- 6.0.1-3/src/icalendar/tests/test_multiple.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/test_multiple.py	2025-05-20 07:31:39.000000000 +0000
@@ -1,7 +1,8 @@
-"""An example with multiple VCALENDAR components"""
-from icalendar.prop import vText
-
+"""Testing multiple VCALENDAR components and multiple VEVENT components"""
 
+from icalendar.prop import vText
+from icalendar.cal import Event
+import pytest
 
 def test_multiple(calendars):
     """Check opening multiple calendars."""
@@ -9,6 +10,24 @@ def test_multiple(calendars):
     cals = calendars.multiple.multiple_calendar_components
 
     assert len(cals) == 2
-    assert [comp.name for comp in cals[0].walk()] == ['VCALENDAR', 'VEVENT']
-    assert [comp.name for comp in cals[1].walk()] == ['VCALENDAR', 'VEVENT', 'VEVENT']
-    assert cals[0]['prodid'] == vText('-//Mozilla.org/NONSGML Mozilla Calendar V1.0//EN')
+    assert [comp.name for comp in cals[0].walk()] == ["VCALENDAR", "VEVENT"]
+    assert [comp.name for comp in cals[1].walk()] == ["VCALENDAR", "VEVENT", "VEVENT"]
+    assert cals[0]["prodid"] == vText(
+        "-//Mozilla.org/NONSGML Mozilla Calendar V1.0//EN"
+    )
+
+def test_multiple_events():
+    """Raises ValueError unless multiple=True"""
+    event_components="""
+BEGIN:VEVENT
+END:VEVENT
+BEGIN:VEVENT
+END:VEVENT
+"""
+    with pytest.raises(ValueError) as exception:
+        Event.from_ical(event_components, multiple=False)
+
+def test_missing_event():
+    """Raises ValueError if no component found"""
+    with pytest.raises(ValueError) as exception:
+        Event.from_ical('')
diff -pruN 6.0.1-3/src/icalendar/tests/test_oss_fuzz_errors.py 6.3.1-1/src/icalendar/tests/test_oss_fuzz_errors.py
--- 6.0.1-3/src/icalendar/tests/test_oss_fuzz_errors.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/test_oss_fuzz_errors.py	2025-05-20 07:31:39.000000000 +0000
@@ -1,10 +1,12 @@
 """This file collects errors that the OSS FUZZ build has found."""
+
 from datetime import time
-from icalendar import Calendar
-from icalendar.prop import vDDDLists
 
 import pytest
 
+from icalendar import Calendar
+from icalendar.prop import vDDDLists
+
 
 def test_stack_is_empty():
     """If we get passed an invalid string, we expect to get a ValueError."""
@@ -15,4 +17,4 @@ def test_stack_is_empty():
 def test_vdd_list_type_mismatch():
     """If we pass in a string type, we expect it to be converted to bytes"""
     vddd_list = vDDDLists([time(hour=6, minute=6, second=6)])
-    assert vddd_list.to_ical() == b'060606'
+    assert vddd_list.to_ical() == b"060606"
diff -pruN 6.0.1-3/src/icalendar/tests/test_parsing.py 6.3.1-1/src/icalendar/tests/test_parsing.py
--- 6.0.1-3/src/icalendar/tests/test_parsing.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/test_parsing.py	2025-05-20 07:31:39.000000000 +0000
@@ -1,194 +1,257 @@
-'''Tests checking that parsing works'''
-import pytest
+"""Tests checking that parsing works"""
+
 import base64
-from icalendar import Calendar, vRecur, vBinary, Event
 from datetime import datetime
+
+import pytest
+
+from icalendar import Calendar, Event, vBinary, vRecur
 from icalendar.parser import Contentline, Parameters, unescape_char
 
-@pytest.mark.parametrize('calendar_name', [
-    # Issue #178 - A component with an unknown/invalid name is represented
-    # as one of the known components, the information about the original
-    # component name is lost.
-    # https://github.com/collective/icalendar/issues/178 https://github.com/collective/icalendar/pull/180
-    # Parsing of a nonstandard component
-    'issue_178_component_with_invalid_name_represented',
-    # Nonstandard component inside other components, also has properties
-    'issue_178_custom_component_inside_other',
-    # Nonstandard component is able to contain other components
-    'issue_178_custom_component_contains_other',
-])
+
+@pytest.mark.parametrize(
+    "calendar_name",
+    [
+        # Issue #178 - A component with an unknown/invalid name is represented
+        # as one of the known components, the information about the original
+        # component name is lost.
+        # https://github.com/collective/icalendar/issues/178 https://github.com/collective/icalendar/pull/180
+        # Parsing of a nonstandard component
+        "issue_178_component_with_invalid_name_represented",
+        # Nonstandard component inside other components, also has properties
+        "issue_178_custom_component_inside_other",
+        # Nonstandard component is able to contain other components
+        "issue_178_custom_component_contains_other",
+    ],
+)
 def test_calendar_to_ical_is_inverse_of_from_ical(calendars, calendar_name):
     calendar = getattr(calendars, calendar_name)
     assert calendar.to_ical().splitlines() == calendar.raw_ics.splitlines()
     assert calendar.to_ical() == calendar.raw_ics
 
-@pytest.mark.parametrize('raw_content_line, expected_output', [
-    # Issue #142 - Multivalued parameters. This is needed for VCard 3.0.
-    # see https://github.com/collective/icalendar/pull/142
-    ('TEL;TYPE=HOME,VOICE:000000000', ('TEL', Parameters({'TYPE': ['HOME', 'VOICE']}), '000000000')),
-    # Issue #143 - Allow dots in property names. Another vCard related issue.
-    # see https://github.com/collective/icalendar/pull/143
-    ('ITEMADRNULLTHISISTHEADRESS08158SOMECITY12345.ADR:;;This is the Adress 08; Some City;;12345;Germany', \
-        ('ITEMADRNULLTHISISTHEADRESS08158SOMECITY12345.ADR', \
-        Parameters(),\
-        ';;This is the Adress 08; Some City;;12345;Germany')),
-    ('ITEMADRNULLTHISISTHEADRESS08158SOMECITY12345.X-ABLABEL:', \
-        ('ITEMADRNULLTHISISTHEADRESS08158SOMECITY12345.X-ABLABEL', \
-        Parameters(), \
-        ''))
-])
+
+@pytest.mark.parametrize(
+    ("raw_content_line", "expected_output"),
+    [
+        # Issue #142 - Multivalued parameters. This is needed for VCard 3.0.
+        # see https://github.com/collective/icalendar/pull/142
+        (
+            "TEL;TYPE=HOME,VOICE:000000000",
+            ("TEL", Parameters({"TYPE": ["HOME", "VOICE"]}), "000000000"),
+        ),
+        # Issue #143 - Allow dots in property names. Another vCard related issue.
+        # see https://github.com/collective/icalendar/pull/143
+        (
+            "ITEMADRNULLTHISISTHEADRESS08158SOMECITY12345.ADR:;;This is the Adress 08; Some City;;12345;Germany",
+            (
+                "ITEMADRNULLTHISISTHEADRESS08158SOMECITY12345.ADR",
+                Parameters(),
+                ";;This is the Adress 08; Some City;;12345;Germany",
+            ),
+        ),
+        (
+            "ITEMADRNULLTHISISTHEADRESS08158SOMECITY12345.X-ABLABEL:",
+            (
+                "ITEMADRNULLTHISISTHEADRESS08158SOMECITY12345.X-ABLABEL",
+                Parameters(),
+                "",
+            ),
+        ),
+    ],
+)
 def test_content_lines_parsed_properly(raw_content_line, expected_output):
     assert Contentline.from_ical(raw_content_line).parts() == expected_output
 
 
-@pytest.mark.parametrize('timezone_info', [
-    # General timezone aware dates in ical string
-    (b'DTSTART;TZID=America/New_York:20130907T120000'),
-    (b'DTEND;TZID=America/New_York:20130907T170000'),
-    # Specific timezone aware exdates in ical string
-    (b'EXDATE;TZID=America/New_York:20131012T120000'),
-    (b'EXDATE;TZID=America/New_York:20131011T120000')
-])
+@pytest.mark.parametrize(
+    "timezone_info",
+    [
+        # General timezone aware dates in ical string
+        (b"DTSTART;TZID=America/New_York:20130907T120000"),
+        (b"DTEND;TZID=America/New_York:20130907T170000"),
+        # Specific timezone aware exdates in ical string
+        (b"EXDATE;TZID=America/New_York:20131012T120000"),
+        (b"EXDATE;TZID=America/New_York:20131011T120000"),
+    ],
+)
 def test_timezone_info_present_in_ical_issue_112(events, timezone_info):
-    '''Issue #112 - No timezone info on EXDATE
+    """Issue #112 - No timezone info on EXDATE
 
     https://github.com/collective/icalendar/issues/112
-    '''
-    timezone_info in events.issue_112_missing_tzinfo_on_exdate.to_ical()
+    """
+    assert timezone_info in events.issue_112_missing_tzinfo_on_exdate.to_ical()
+
 
 def test_timezone_name_parsed_issue_112(events):
-    '''Issue #112 - No timezone info on EXDATE
+    """Issue #112 - No timezone info on EXDATE
 
     https://github.com/collective/icalendar/issues/112
-    '''
-    assert events.issue_112_missing_tzinfo_on_exdate['exdate'][0].dts[0].dt.tzname() == 'EDT'
+    """
+    assert (
+        events.issue_112_missing_tzinfo_on_exdate["exdate"][0].dts[0].dt.tzname()
+        == "EDT"
+    )
+
 
 def test_issue_157_removes_trailing_semicolon(events):
-    '''Issue #157 - Recurring rules and trailing semicolons
+    """Issue #157 - Recurring rules and trailing semicolons
 
     https://github.com/collective/icalendar/pull/157
-    '''
+    """
     recur = events.issue_157_removes_trailing_semicolon.decoded("RRULE")
     assert isinstance(recur, vRecur)
-    assert recur.to_ical() == b'FREQ=YEARLY;BYDAY=1SU;BYMONTH=11'
+    assert recur.to_ical() == b"FREQ=YEARLY;BYDAY=1SU;BYMONTH=11"
 
-@pytest.mark.parametrize('event_name', [
-    # https://github.com/collective/icalendar/pull/100
-    ('issue_100_transformed_doctests_into_unittests'),
-    ('issue_184_broken_representation_of_period'),
-    # PERIOD should be put back into shape
-    'issue_156_RDATE_with_PERIOD',
-    'issue_156_RDATE_with_PERIOD_list',
-    'event_with_unicode_organizer',
-])
+
+@pytest.mark.parametrize(
+    "event_name",
+    [
+        # https://github.com/collective/icalendar/pull/100
+        ("issue_100_transformed_doctests_into_unittests"),
+        ("issue_184_broken_representation_of_period"),
+        # PERIOD should be put back into shape
+        "issue_156_RDATE_with_PERIOD",
+        "issue_156_RDATE_with_PERIOD_list",
+        "event_with_unicode_organizer",
+    ],
+)
 def test_event_to_ical_is_inverse_of_from_ical(events, event_name):
     """Make sure that an event's ICS is equal to the ICS it was made from."""
     event = events[event_name]
     assert event.to_ical().splitlines() == event.raw_ics.splitlines()
     assert event.to_ical() == event.raw_ics
 
+
 def test_decode_rrule_attribute_error_issue_70(events):
     # Issue #70 - e.decode("RRULE") causes Attribute Error
     # see https://github.com/collective/icalendar/issues/70
-    recur = events.issue_70_rrule_causes_attribute_error.decoded('RRULE')
+    recur = events.issue_70_rrule_causes_attribute_error.decoded("RRULE")
     assert isinstance(recur, vRecur)
-    assert recur.to_ical() == b'FREQ=WEEKLY;UNTIL=20070619T225959;INTERVAL=1'
+    assert recur.to_ical() == b"FREQ=WEEKLY;UNTIL=20070619T225959;INTERVAL=1"
+
 
 def test_description_parsed_properly_issue_53(events):
-    '''Issue #53 - Parsing failure on some descriptions?
+    """Issue #53 - Parsing failure on some descriptions?
 
     https://github.com/collective/icalendar/issues/53
-    '''
-    assert b'July 12 at 6:30 PM' in events.issue_53_description_parsed_properly['DESCRIPTION'].to_ical()
+    """
+    assert (
+        b"July 12 at 6:30 PM"
+        in events.issue_53_description_parsed_properly["DESCRIPTION"].to_ical()
+    )
+
 
 def test_raises_value_error_for_properties_without_parent_pull_179():
-        '''Found an issue where from_ical() would raise IndexError for
-        properties without parent components.
+    """Found an issue where from_ical() would raise IndexError for
+    properties without parent components.
+
+    https://github.com/collective/icalendar/pull/179
+    """
+    with pytest.raises(ValueError):
+        Calendar.from_ical("VERSION:2.0")
 
-        https://github.com/collective/icalendar/pull/179
-        '''
-        with pytest.raises(ValueError):
-            Calendar.from_ical('VERSION:2.0')
 
 def test_tzid_parsed_properly_issue_53(timezones):
-    '''Issue #53 - Parsing failure on some descriptions?
+    """Issue #53 - Parsing failure on some descriptions?
 
     https://github.com/collective/icalendar/issues/53
-    '''
-    assert timezones.issue_53_tzid_parsed_properly['tzid'].to_ical() == b'America/New_York'
+    """
+    assert (
+        timezones.issue_53_tzid_parsed_properly["tzid"].to_ical() == b"America/New_York"
+    )
+
 
 def test_timezones_to_ical_is_inverse_of_from_ical(timezones):
-    '''Issue #55 - Parse error on utc-offset with seconds value
-     see https://github.com/collective/icalendar/issues/55'''
-    timezone = timezones['issue_55_parse_error_on_utc_offset_with_seconds']
+    """Issue #55 - Parse error on utc-offset with seconds value
+    see https://github.com/collective/icalendar/issues/55"""
+    timezone = timezones["issue_55_parse_error_on_utc_offset_with_seconds"]
     assert timezone.to_ical() == timezone.raw_ics
 
-@pytest.mark.parametrize('date, expected_output', [
-    (datetime(2012, 7, 16, 0, 0, 0), b'DTSTART:20120716T000000Z'),
-    (datetime(2021, 11, 17, 15, 9, 15), b'DTSTART:20211117T150915Z')
-])
+
+@pytest.mark.parametrize(
+    ("date", "expected_output"),
+    [
+        (datetime(2012, 7, 16, 0, 0, 0), b"DTSTART:20120716T000000Z"),
+        (datetime(2021, 11, 17, 15, 9, 15), b"DTSTART:20211117T150915Z"),
+    ],
+)
 def test_no_tzid_when_utc(utc, date, expected_output):
-    '''Issue #58  - TZID on UTC DATE-TIMEs
+    """Issue #58  - TZID on UTC DATE-TIMEs
        Issue #335 - UTC timezone identification is broken
 
     https://github.com/collective/icalendar/issues/58
     https://github.com/collective/icalendar/issues/335
-    '''
+    """
     # According to RFC 5545: "The TZID property parameter MUST NOT be
     # applied to DATE-TIME or TIME properties whose time values are
     # specified in UTC.
     date = date.replace(tzinfo=utc)
     event = Event()
-    event.add('dtstart', date)
+    event.add("dtstart", date)
     assert expected_output in event.to_ical()
 
+
 def test_vBinary_base64_encoded_issue_82():
-    '''Issue #82 - vBinary __repr__ called rather than to_ical from
+    """Issue #82 - vBinary __repr__ called rather than to_ical from
                    container types
     https://github.com/collective/icalendar/issues/82
-    '''
-    b = vBinary('text')
-    b.params['FMTTYPE'] = 'text/plain'
-    assert b.to_ical() == base64.b64encode(b'text')
+    """
+    b = vBinary("text")
+    b.params["FMTTYPE"] = "text/plain"
+    assert b.to_ical() == base64.b64encode(b"text")
+
 
 def test_creates_event_with_base64_encoded_attachment_issue_82(events):
-    '''Issue #82 - vBinary __repr__ called rather than to_ical from
+    """Issue #82 - vBinary __repr__ called rather than to_ical from
                    container types
     https://github.com/collective/icalendar/issues/82
-    '''
-    b = vBinary('text')
-    b.params['FMTTYPE'] = 'text/plain'
+    """
+    b = vBinary("text")
+    b.params["FMTTYPE"] = "text/plain"
     event = Event()
-    event.add('ATTACH', b)
+    event.add("ATTACH", b)
     assert event.to_ical() == events.issue_82_expected_output.raw_ics
 
-@pytest.mark.parametrize('calendar_name', [
-    # Issue #466 - [BUG] TZID timezone is ignored when forward-slash is used
-    # https://github.com/collective/icalendar/issues/466
-    'issue_466_respect_unique_timezone',
-    'issue_466_convert_tzid_with_slash'
-])
+
+@pytest.mark.parametrize(
+    "calendar_name",
+    [
+        # Issue #466 - [BUG] TZID timezone is ignored when forward-slash is used
+        # https://github.com/collective/icalendar/issues/466
+        "issue_466_respect_unique_timezone",
+        "issue_466_convert_tzid_with_slash",
+    ],
+)
 def test_handles_unique_tzid(calendars, in_timezone, calendar_name):
     calendar = calendars[calendar_name]
-    event = calendar.walk('VEVENT')[0]
+    event = calendar.walk("VEVENT")[0]
     print(vars(event))
-    start_dt = event['dtstart'].dt
-    end_dt = event['dtend'].dt
-    assert start_dt == in_timezone(datetime(2022, 10, 21, 20, 0, 0), 'Europe/Stockholm')
-    assert end_dt == in_timezone(datetime(2022, 10, 21, 21, 0, 0), 'Europe/Stockholm')
-
-@pytest.mark.parametrize('event_name, expected_cn, expected_ics', [
-    ('event_with_escaped_characters', r'that, that; %th%%at%\ that:', 'это, то; that\\ %th%%at%:'),
-    ('event_with_escaped_character1', r'Society, 2014', 'that'),
-    ('event_with_escaped_character2', r'Society\ 2014', 'that'),
-    ('event_with_escaped_character3', r'Society; 2014', 'that'),
-    ('event_with_escaped_character4', r'Society: 2014', 'that'),
-])
+    start_dt = event["dtstart"].dt
+    end_dt = event["dtend"].dt
+    assert start_dt == in_timezone(datetime(2022, 10, 21, 20, 0, 0), "Europe/Stockholm")
+    assert end_dt == in_timezone(datetime(2022, 10, 21, 21, 0, 0), "Europe/Stockholm")
+
+
+@pytest.mark.parametrize(
+    ("event_name", "expected_cn", "expected_ics"),
+    [
+        (
+            "event_with_escaped_characters",
+            r"that, that; %th%%at%\ that:",
+            "это, то; that\\ %th%%at%:",
+        ),
+        ("event_with_escaped_character1", r"Society, 2014", "that"),
+        ("event_with_escaped_character2", r"Society\ 2014", "that"),
+        ("event_with_escaped_character3", r"Society; 2014", "that"),
+        ("event_with_escaped_character4", r"Society: 2014", "that"),
+    ],
+)
 def test_escaped_characters_read(event_name, expected_cn, expected_ics, events):
     event = events[event_name]
-    assert event['ORGANIZER'].params['CN'] == expected_cn
-    assert event['ORGANIZER'].to_ical() == expected_ics.encode('utf-8')
-    
+    assert event["ORGANIZER"].params["CN"] == expected_cn
+    assert event["ORGANIZER"].to_ical() == expected_ics.encode("utf-8")
+
+
 def test_unescape_char():
-    assert unescape_char(b'123') == b'123'
+    assert unescape_char(b"123") == b"123"
     assert unescape_char(b"\\n") == b"\n"
diff -pruN 6.0.1-3/src/icalendar/tests/test_period.py 6.3.1-1/src/icalendar/tests/test_period.py
--- 6.0.1-3/src/icalendar/tests/test_period.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/test_period.py	2025-05-20 07:31:39.000000000 +0000
@@ -4,29 +4,62 @@ See
 - https://github.com/collective/icalendar/issues/156
 - https://github.com/pimutils/khal/issues/152#issuecomment-933635248
 """
-import pytest
-from icalendar.prop import vDDDTypes
+
 import datetime
 
+import pytest
+
+from icalendar.prop import vDDDTypes, vPeriod
 
-@pytest.mark.parametrize("calname,tzname,index,period_string", [
-    ("issue_156_RDATE_with_PERIOD_TZID_khal_2", "Europe/Berlin", 0, "20211101T160000/20211101T163000"),
-    ("issue_156_RDATE_with_PERIOD_TZID_khal_2", "Europe/Berlin", 1, "20211206T160000/20211206T163000"),
-    ("issue_156_RDATE_with_PERIOD_TZID_khal_2", "Europe/Berlin", 2, "20220103T160000/20220103T163000"),
-    ("issue_156_RDATE_with_PERIOD_TZID_khal_2", "Europe/Berlin", 3, "20220207T160000/20220207T163000"),
-] + [
-    ("issue_156_RDATE_with_PERIOD_TZID_khal", "America/Chicago", i, period)
-    for i, period in enumerate(("20180327T080000/20180327T0"
-        "90000,20180403T080000/20180403T090000,20180410T080000/20180410T090000,2018"
-        "0417T080000/20180417T090000,20180424T080000/20180424T090000,20180501T08000"
-        "0/20180501T090000,20180508T080000/20180508T090000,20180515T080000/20180515"
-        "T090000,20180522T080000/20180522T090000,20180529T080000/20180529T090000,20"
-        "180605T080000/20180605T090000,20180612T080000/20180612T090000,20180619T080"
-        "000/20180619T090000,20180626T080000/20180626T090000,20180703T080000/201807"
-        "03T090000,20180710T080000/20180710T090000,20180717T080000/20180717T090000,"
-        "20180724T080000/20180724T090000,20180731T080000/20180731T090000").split(","))
-])
-def test_issue_156_period_list_in_rdate(calendars, calname, tzname, index, period_string):
+
+@pytest.mark.parametrize(
+    ("calname", "tzname", "index", "period_string"),
+    [
+        (
+            "issue_156_RDATE_with_PERIOD_TZID_khal_2",
+            "Europe/Berlin",
+            0,
+            "20211101T160000/20211101T163000",
+        ),
+        (
+            "issue_156_RDATE_with_PERIOD_TZID_khal_2",
+            "Europe/Berlin",
+            1,
+            "20211206T160000/20211206T163000",
+        ),
+        (
+            "issue_156_RDATE_with_PERIOD_TZID_khal_2",
+            "Europe/Berlin",
+            2,
+            "20220103T160000/20220103T163000",
+        ),
+        (
+            "issue_156_RDATE_with_PERIOD_TZID_khal_2",
+            "Europe/Berlin",
+            3,
+            "20220207T160000/20220207T163000",
+        ),
+    ]
+    + [
+        ("issue_156_RDATE_with_PERIOD_TZID_khal", "America/Chicago", i, period)
+        for i, period in enumerate(
+            (
+                "20180327T080000/20180327T0"
+                "90000,20180403T080000/20180403T090000,20180410T080000/20180410T090000,2018"
+                "0417T080000/20180417T090000,20180424T080000/20180424T090000,20180501T08000"
+                "0/20180501T090000,20180508T080000/20180508T090000,20180515T080000/20180515"
+                "T090000,20180522T080000/20180522T090000,20180529T080000/20180529T090000,20"
+                "180605T080000/20180605T090000,20180612T080000/20180612T090000,20180619T080"
+                "000/20180619T090000,20180626T080000/20180626T090000,20180703T080000/201807"
+                "03T090000,20180710T080000/20180710T090000,20180717T080000/20180717T090000,"
+                "20180724T080000/20180724T090000,20180731T080000/20180731T090000"
+            ).split(",")
+        )
+    ],
+)
+def test_issue_156_period_list_in_rdate(
+    calendars, calname, tzname, index, period_string
+):
     """Check items in a list of period values."""
     calendar = calendars[calname]
     rdate = calendar.walk("vevent")[0]["rdate"]
@@ -58,5 +91,22 @@ def test_tzid_is_part_of_the_period_valu
     """The TZID should be set in the datetime."""
     event = list(calendars.period_with_timezone.walk("VEVENT"))[0]
     start, end = event["RDATE"].dts[0].dt
-    assert start == tzp.localize(datetime.datetime(2023, 12, 13, 12), "America/Vancouver")
+    assert start == tzp.localize(
+        datetime.datetime(2023, 12, 13, 12), "America/Vancouver"
+    )
     assert end == tzp.localize(datetime.datetime(2023, 12, 13, 15), "America/Vancouver")
+
+
+def test_period_overlaps():
+    # 30 minute increments
+    datetime_1 = datetime.datetime(2024, 11, 20, 12, 0)  # 12:00
+    datetime_2 = datetime.datetime(2024, 11, 20, 12, 30)  # 12:30
+    datetime_3 = datetime.datetime(2024, 11, 20, 13, 0)  # 13:00
+
+    period_1 = vPeriod((datetime_1, datetime_2))
+    period_2 = vPeriod((datetime_1, datetime_3))
+    period_3 = vPeriod((datetime_2, datetime_3))
+
+    assert period_1.overlaps(period_2)
+    assert period_3.overlaps(period_2)
+    assert not period_1.overlaps(period_3)
diff -pruN 6.0.1-3/src/icalendar/tests/test_property_params.py 6.3.1-1/src/icalendar/tests/test_property_params.py
--- 6.0.1-3/src/icalendar/tests/test_property_params.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/test_property_params.py	2025-05-20 07:31:39.000000000 +0000
@@ -1,94 +1,130 @@
+import re
+
 import pytest
+
 from icalendar import Calendar, Event, Parameters, vCalAddress
 
-import re
 
-@pytest.mark.parametrize('parameter, expected', [
-    # Simple parameter:value pair
-    (Parameters(parameter1='Value1'), b'PARAMETER1=Value1'),
-    # Parameter with list of values must be separated by comma
-    (Parameters({'parameter1': ['Value1', 'Value2']}), b'PARAMETER1=Value1,Value2'),
-    # Multiple parameters must be separated by a semicolon
-    (Parameters({'RSVP': 'TRUE', 'ROLE': 'REQ-PARTICIPANT'}), b'ROLE=REQ-PARTICIPANT;RSVP=TRUE'),
-    # Parameter values containing ',;:' must be double quoted
-    (Parameters({'ALTREP': 'http://www.wiz.org'}), b'ALTREP="http://www.wiz.org"'),
-    # list items must be quoted separately
-    (Parameters({'MEMBER': ['MAILTO:projectA@host.com',
-                                   'MAILTO:projectB@host.com']}),
-     b'MEMBER="MAILTO:projectA@host.com","MAILTO:projectB@host.com"'),
-    (Parameters({'parameter1': 'Value1',
-                        'parameter2': ['Value2', 'Value3'],
-                        'ALTREP': ['http://www.wiz.org', 'value4']}),
-     b'ALTREP="http://www.wiz.org",value4;PARAMETER1=Value1;PARAMETER2=Value2,Value3'),
-    # Including empty strings
-    (Parameters({'PARAM': ''}), b'PARAM='),
-    # We can also parse parameter strings
-    (Parameters({'MEMBER': ['MAILTO:projectA@host.com',
-                                   'MAILTO:projectB@host.com']}),
-     b'MEMBER="MAILTO:projectA@host.com","MAILTO:projectB@host.com"'),
-    # We can also parse parameter strings
-    (Parameters({'PARAMETER1': 'Value1',
-                 'ALTREP': ['http://www.wiz.org', 'value4'],
-                 'PARAMETER2': ['Value2', 'Value3']}),
-     b'ALTREP="http://www.wiz.org",value4;PARAMETER1=Value1;PARAMETER2=Value2,Value3'),
-])
+@pytest.mark.parametrize(
+    ("parameter", "expected"),
+    [
+        # Simple parameter:value pair
+        (Parameters(parameter1="Value1"), b"PARAMETER1=Value1"),
+        # Parameter with list of values must be separated by comma
+        (Parameters({"parameter1": ["Value1", "Value2"]}), b"PARAMETER1=Value1,Value2"),
+        # Multiple parameters must be separated by a semicolon
+        (
+            Parameters({"RSVP": "TRUE", "ROLE": "REQ-PARTICIPANT"}),
+            b"ROLE=REQ-PARTICIPANT;RSVP=TRUE",
+        ),
+        # Parameter values containing ',;:' must be double quoted
+        (Parameters({"ALTREP": "http://www.wiz.org"}), b'ALTREP="http://www.wiz.org"'),
+        # list items must be quoted separately
+        (
+            Parameters(
+                {"MEMBER": ["MAILTO:projectA@host.com", "MAILTO:projectB@host.com"]}
+            ),
+            b'MEMBER="MAILTO:projectA@host.com","MAILTO:projectB@host.com"',
+        ),
+        (
+            Parameters(
+                {
+                    "parameter1": "Value1",
+                    "parameter2": ["Value2", "Value3"],
+                    "ALTREP": ["http://www.wiz.org", "value4"],
+                }
+            ),
+            b'ALTREP="http://www.wiz.org","value4";PARAMETER1=Value1;PARAMETER2=Value2,Value3',
+        ),
+        # Including empty strings
+        (Parameters({"PARAM": ""}), b"PARAM="),
+        # We can also parse parameter strings
+        (
+            Parameters(
+                {"MEMBER": ["MAILTO:projectA@host.com", "MAILTO:projectB@host.com"]}
+            ),
+            b'MEMBER="MAILTO:projectA@host.com","MAILTO:projectB@host.com"',
+        ),
+        # We can also parse parameter strings
+        (
+            Parameters(
+                {
+                    "PARAMETER1": "Value1",
+                    "ALTREP": ["http://www.wiz.org", "value4"],
+                    "PARAMETER2": ["Value2", "Value3"],
+                }
+            ),
+            b'ALTREP="http://www.wiz.org","value4";PARAMETER1=Value1;PARAMETER2=Value2,Value3',
+        ),
+    ],
+)
 def test_parameter_to_ical_is_inverse_of_from_ical(parameter, expected):
     assert parameter.to_ical() == expected
-    assert Parameters.from_ical(expected.decode('utf-8')) == parameter
+    assert Parameters.from_ical(expected.decode("utf-8")) == parameter
 
 
 def test_parse_parameter_string_without_quotes():
-    assert Parameters.from_ical('PARAM1=Value 1;PARA2=Value 2') == Parameters({'PARAM1': 'Value 1', 'PARA2': 'Value 2'})
+    assert Parameters.from_ical("PARAM1=Value 1;PARA2=Value 2") == Parameters(
+        {"PARAM1": "Value 1", "PARA2": "Value 2"}
+    )
 
 
 def test_parametr_is_case_insensitive():
-    parameter = Parameters(parameter1='Value1')
-    assert parameter['parameter1'] == parameter['PARAMETER1'] == parameter['PaRaMeTer1']
+    parameter = Parameters(parameter1="Value1")
+    assert parameter["parameter1"] == parameter["PARAMETER1"] == parameter["PaRaMeTer1"]
 
 
 def test_parameter_keys_are_uppercase():
-    parameter = Parameters(parameter1='Value1')
-    assert list(parameter.keys()) == ['PARAMETER1']
+    parameter = Parameters(parameter1="Value1")
+    assert list(parameter.keys()) == ["PARAMETER1"]
 
 
-@pytest.mark.parametrize('cn_param, cn_quoted', [
-    # not double-quoted
-    ('Aramis', 'Aramis'),
-    # if a space is present - enclose in double quotes
-    ('Aramis Alameda', '"Aramis Alameda"'),
-    # a single quote in parameter value - double quote the value
-    ('Aramis d\'Alameda', '"Aramis d\'Alameda"'),
-    ('Арамис д\'Аламеда', '"Арамис д\'Аламеда"'),
-    # double quote is replaced with single quote
-    ('Aramis d\"Alameda', '"Aramis d\'Alameda"'),
-])
+@pytest.mark.parametrize(
+    ("cn_param", "cn_quoted"),
+    [
+        # not double-quoted
+        ("Aramis", "Aramis"),
+        # if a space is present - enclose in double quotes
+        ("Aramis Alameda", '"Aramis Alameda"'),
+        # a single quote in parameter value - double quote the value
+        ("Aramis d'Alameda", '"Aramis d\'Alameda"'),
+        ("Арамис д'Аламеда", '"Арамис д\'Аламеда"'),
+        # Before, double quote is replaced with single quote
+        # Since RFC 6868, we replace this with ^'
+        ('Aramis d"Alameda', '"Aramis d^\'Alameda"'),
+    ],
+)
 def test_quoting(cn_param, cn_quoted):
     event = Event()
-    attendee = vCalAddress('test@example.com')
-    attendee.params['CN'] = cn_param
-    event.add('ATTENDEE', attendee)
-    assert f'ATTENDEE;CN={cn_quoted}:test@example.com' in event.to_ical().decode('utf-8')
+    attendee = vCalAddress("test@example.com")
+    attendee.params["CN"] = cn_param
+    event.add("ATTENDEE", attendee)
+    assert f"ATTENDEE;CN={cn_quoted}:test@example.com" in event.to_ical().decode(
+        "utf-8"
+    )
 
 
 def test_property_params():
     """Property parameters with values containing a COLON character, a
     SEMICOLON character or a COMMA character MUST be placed in quoted
     text."""
-    cal_address = vCalAddress('mailto:john.doe@example.org')
+    cal_address = vCalAddress("mailto:john.doe@example.org")
     cal_address.params["CN"] = "Doe, John"
     ical = Calendar()
-    ical.add('organizer', cal_address)
+    ical.add("organizer", cal_address)
 
     ical_str = Calendar.to_ical(ical)
-    exp_str = b"""BEGIN:VCALENDAR\r\nORGANIZER;CN="Doe, John":"""\
-              b"""mailto:john.doe@example.org\r\nEND:VCALENDAR\r\n"""
+    exp_str = (
+        b"""BEGIN:VCALENDAR\r\nORGANIZER;CN="Doe, John":"""
+        b"""mailto:john.doe@example.org\r\nEND:VCALENDAR\r\n"""
+    )
 
     assert ical_str == exp_str
 
     # other way around: ensure the property parameters can be restored from
     # an icalendar string.
     ical2 = Calendar.from_ical(ical_str)
-    assert ical2.get('ORGANIZER').params.get('CN') == 'Doe, John'
+    assert ical2.get("ORGANIZER").params.get("CN") == "Doe, John"
 
 
 def test_parse_and_access_property_params(calendars):
@@ -97,13 +133,13 @@ def test_parse_and_access_property_param
 
     """
     event = calendars.property_params.walk("VEVENT")[0]
-    attendee = event['attendee'][0]
-    assert attendee.to_ical() == b'MAILTO:rembrand@xs4all.nl'
-    assert attendee.params.to_ical() == b'CN=RembrandXS;PARTSTAT=NEEDS-ACTION;RSVP=TRUE'
-    assert attendee.params['cn'] == 'RembrandXS'
+    attendee = event["attendee"][0]
+    assert attendee.to_ical() == b"MAILTO:rembrand@xs4all.nl"
+    assert attendee.params.to_ical() == b"CN=RembrandXS;PARTSTAT=NEEDS-ACTION;RSVP=TRUE"
+    assert attendee.params["cn"] == "RembrandXS"
+
 
 def test_repr():
-    """Test correct class representation.
-    """
-    it = Parameters(parameter1='Value1')
+    """Test correct class representation."""
+    it = Parameters(parameter1="Value1")
     assert re.match(r"Parameters\({u?'PARAMETER1': u?'Value1'}\)", str(it))
diff -pruN 6.0.1-3/src/icalendar/tests/test_pytz_zoneinfo_integration.py 6.3.1-1/src/icalendar/tests/test_pytz_zoneinfo_integration.py
--- 6.0.1-3/src/icalendar/tests/test_pytz_zoneinfo_integration.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/test_pytz_zoneinfo_integration.py	2025-05-20 07:31:39.000000000 +0000
@@ -2,19 +2,23 @@
 
 These are mostly located in icalendar.timezone.
 """
+
 try:
     import pytz
+
     from icalendar.timezone.pytz import PYTZ
 except ImportError:
     pytz = None
-from icalendar.timezone.zoneinfo import zoneinfo, ZONEINFO
-from dateutil.tz.tz import _tzicalvtz
-import pytest
 import copy
 import pickle
-from dateutil.rrule import rrule, MONTHLY
 from datetime import datetime
 
+import pytest
+from dateutil.rrule import MONTHLY, rrule
+from dateutil.tz.tz import _tzicalvtz
+
+from icalendar.timezone.zoneinfo import ZONEINFO, zoneinfo
+
 if pytz:
     PYTZ_TIMEZONES = pytz.all_timezones
     TZP_ = [PYTZ(), ZONEINFO()]
@@ -25,17 +29,27 @@ else:
     NEW_TZP_NAME = ["zoneinfo"]
 
 
-@pytest.mark.parametrize("tz_name", PYTZ_TIMEZONES + list(zoneinfo.available_timezones()))
+@pytest.mark.parametrize(
+    "tz_name", PYTZ_TIMEZONES + list(zoneinfo.available_timezones())
+)
 @pytest.mark.parametrize("tzp_", TZP_)
 def test_timezone_names_are_known(tz_name, tzp_):
     """Make sure that all timezones are understood."""
     if tz_name in ("Factory", "localtime"):
         pytest.skip()
-    assert tzp_.knows_timezone_id(tz_name), f"{tzp_.__class__.__name__} should know {tz_name}"
+    assert tzp_.knows_timezone_id(
+        tz_name
+    ), f"{tzp_.__class__.__name__} should know {tz_name}"
 
 
 @pytest.mark.parametrize("func", [pickle.dumps, copy.copy, copy.deepcopy])
-@pytest.mark.parametrize("obj", [_tzicalvtz("id"), rrule(freq=MONTHLY, count=4, dtstart=datetime(2028, 10, 1), cache=True)])
+@pytest.mark.parametrize(
+    "obj",
+    [
+        _tzicalvtz("id"),
+        rrule(freq=MONTHLY, count=4, dtstart=datetime(2028, 10, 1), cache=True),
+    ],
+)
 def test_can_pickle_timezone(func, tzp, obj):
     """Check that we can serialize and copy timezones."""
     func(obj)
@@ -76,3 +90,15 @@ def test_cache_is_emptied_when_tzp_is_sw
     tzp.cache_timezone_component(timezones.pacific_fiji)
     tz2 = tzp.timezone("custom_Pacific/Fiji")
     assert tz1 is not tz2
+
+
+def test_invalid_name(tzp):
+    """Check that the provider name is OK."""
+    provider = "invalid_provider"
+    with pytest.raises(ValueError) as e:
+        tzp.use(provider)
+    # f"Unknown provider {provider}. Use 'pytz' or 'zoneinfo'."
+    message = e.value.args[0]
+    assert f"Unknown provider {provider}." in message
+    assert "zoneinfo" in message
+    assert "pytz" in message
diff -pruN 6.0.1-3/src/icalendar/tests/test_recurrence.py 6.3.1-1/src/icalendar/tests/test_recurrence.py
--- 6.0.1-3/src/icalendar/tests/test_recurrence.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/test_recurrence.py	2025-05-20 07:31:39.000000000 +0000
@@ -1,22 +1,32 @@
-from icalendar import Event
 from datetime import date, datetime
 
 import pytest
 
+from icalendar import Event
+
+
 def test_recurrence_properly_parsed(events):
-    assert events.event_with_recurrence['rrule'] == {'COUNT': [100], 'FREQ': ['DAILY']}
+    assert events.event_with_recurrence["rrule"] == {"COUNT": [100], "FREQ": ["DAILY"]}
+
 
-@pytest.mark.parametrize('i, exception_date', [
-    (0, datetime(1996, 4, 2, 1, 0)),
-    (1, datetime(1996, 4, 3, 1, 0)),
-    (2, datetime(1996, 4, 4, 1, 0))
-])
+@pytest.mark.parametrize(
+    ("i", "exception_date"),
+    [
+        (0, datetime(1996, 4, 2, 1, 0)),
+        (1, datetime(1996, 4, 3, 1, 0)),
+        (2, datetime(1996, 4, 4, 1, 0)),
+    ],
+)
 def test_exdate_properly_parsed(events, i, exception_date, in_timezone):
-    assert events.event_with_recurrence['exdate'].dts[i].dt == in_timezone(exception_date, 'UTC')
+    assert events.event_with_recurrence["exdate"].dts[i].dt == in_timezone(
+        exception_date, "UTC"
+    )
+
 
 def test_exdate_properly_marshalled(events):
-    actual = events.event_with_recurrence['exdate'].to_ical()
-    assert actual == b'19960402T010000Z,19960403T010000Z,19960404T010000Z'
+    actual = events.event_with_recurrence["exdate"].to_ical()
+    assert actual == b"19960402T010000Z,19960403T010000Z,19960404T010000Z"
+
 
 # TODO: DOCUMENT BETTER!
 # In this case we have multiple EXDATE definitions, one per line.
@@ -26,49 +36,95 @@ def test_exdate_properly_marshalled(even
 # code has to handle this as list and not blindly expecting to be able
 # to call event['EXDATE'].to_ical() on it:
 def test_exdate_formed_from_exdates_on_multiple_lines_is_a_list(events):
-    exdate = events.event_with_recurrence_exdates_on_different_lines['exdate']
+    exdate = events.event_with_recurrence_exdates_on_different_lines["exdate"]
     assert isinstance(exdate, list)
 
-@pytest.mark.parametrize('i, exception_date, exception_date_ics', [
-    (0, datetime(2012, 5, 29, 10, 0), b'20120529T100000'),
-    (1, datetime(2012, 4, 3, 10, 0),  b'20120403T100000'),
-    (2, datetime(2012, 4, 10, 10, 0), b'20120410T100000'),
-    (3, datetime(2012, 5, 1, 10, 0),  b'20120501T100000'),
-    (4, datetime(2012, 4, 17, 10, 0), b'20120417T100000')
-])
-def test_list_exdate_to_ical_is_inverse_of_from_ical(events, i, exception_date, exception_date_ics, in_timezone):
-    exdate = events.event_with_recurrence_exdates_on_different_lines['exdate']
-    assert exdate[i].dts[0].dt == in_timezone(exception_date, 'Europe/Vienna')
+
+@pytest.mark.parametrize(
+    ("i", "exception_date", "exception_date_ics"),
+    [
+        (0, datetime(2012, 5, 29, 10, 0), b"20120529T100000"),
+        (1, datetime(2012, 4, 3, 10, 0), b"20120403T100000"),
+        (2, datetime(2012, 4, 10, 10, 0), b"20120410T100000"),
+        (3, datetime(2012, 5, 1, 10, 0), b"20120501T100000"),
+        (4, datetime(2012, 4, 17, 10, 0), b"20120417T100000"),
+    ],
+)
+def test_list_exdate_to_ical_is_inverse_of_from_ical(
+    events, i, exception_date, exception_date_ics, in_timezone
+):
+    exdate = events.event_with_recurrence_exdates_on_different_lines["exdate"]
+    assert exdate[i].dts[0].dt == in_timezone(exception_date, "Europe/Vienna")
     assert exdate[i].to_ical() == exception_date_ics
 
-@pytest.mark.parametrize('freq, byday, dtstart, expected', [
-    # Test some YEARLY BYDAY repeats
-    ('YEARLY', '1SU', date(2016,1,3), # 1st Sunday in year
-        b'BEGIN:VEVENT\r\nSUMMARY:Event YEARLY 1SU\r\nDTSTART;VALUE=DATE:20160103\r\nRRULE:FREQ=YEARLY;BYDAY=1SU\r\nEND:VEVENT\r\n'),
-    ('YEARLY', '53MO', date(1984,12,31), # 53rd Monday in (leap) year
-        b'BEGIN:VEVENT\r\nSUMMARY:Event YEARLY 53MO\r\nDTSTART;VALUE=DATE:19841231\r\nRRULE:FREQ=YEARLY;BYDAY=53MO\r\nEND:VEVENT\r\n'),
-    ('YEARLY', '-1TU', date(1999,12,28), # Last Tuesday in year
-        b'BEGIN:VEVENT\r\nSUMMARY:Event YEARLY -1TU\r\nDTSTART;VALUE=DATE:19991228\r\nRRULE:FREQ=YEARLY;BYDAY=-1TU\r\nEND:VEVENT\r\n'),
-    ('YEARLY', '-17WE', date(2000,9,6), # 17th-to-last Wednesday in year
-        b'BEGIN:VEVENT\r\nSUMMARY:Event YEARLY -17WE\r\nDTSTART;VALUE=DATE:20000906\r\nRRULE:FREQ=YEARLY;BYDAY=-17WE\r\nEND:VEVENT\r\n'),
-    # Test some MONTHLY BYDAY repeats
-    ('MONTHLY', '2TH', date(2003,4,10), # 2nd Thursday in month
-        b'BEGIN:VEVENT\r\nSUMMARY:Event MONTHLY 2TH\r\nDTSTART;VALUE=DATE:20030410\r\nRRULE:FREQ=MONTHLY;BYDAY=2TH\r\nEND:VEVENT\r\n'),
-    ('MONTHLY', '-3FR', date(2017,5,12), # 3rd-to-last Friday in month
-        b'BEGIN:VEVENT\r\nSUMMARY:Event MONTHLY -3FR\r\nDTSTART;VALUE=DATE:20170512\r\nRRULE:FREQ=MONTHLY;BYDAY=-3FR\r\nEND:VEVENT\r\n'),
-    ('MONTHLY', '-5SA', date(2053,11,1), # 5th-to-last Saturday in month
-        b'BEGIN:VEVENT\r\nSUMMARY:Event MONTHLY -5SA\r\nDTSTART;VALUE=DATE:20531101\r\nRRULE:FREQ=MONTHLY;BYDAY=-5SA\r\nEND:VEVENT\r\n'),
-    # Specifically test examples from the report of Issue #518
-    # https://github.com/collective/icalendar/issues/518
-    ('YEARLY', '9MO', date(2023,2,27), # 9th Monday in year
-        b'BEGIN:VEVENT\r\nSUMMARY:Event YEARLY 9MO\r\nDTSTART;VALUE=DATE:20230227\r\nRRULE:FREQ=YEARLY;BYDAY=9MO\r\nEND:VEVENT\r\n'),
-    ('YEARLY', '10MO', date(2023,3,6), # 10th Monday in year
-        b'BEGIN:VEVENT\r\nSUMMARY:Event YEARLY 10MO\r\nDTSTART;VALUE=DATE:20230306\r\nRRULE:FREQ=YEARLY;BYDAY=10MO\r\nEND:VEVENT\r\n'),
-])
+
+@pytest.mark.parametrize(
+    ("freq", "byday", "dtstart", "expected"),
+    [
+        # Test some YEARLY BYDAY repeats
+        (
+            "YEARLY",
+            "1SU",
+            date(2016, 1, 3),  # 1st Sunday in year
+            b"BEGIN:VEVENT\r\nSUMMARY:Event YEARLY 1SU\r\nDTSTART;VALUE=DATE:20160103\r\nRRULE:FREQ=YEARLY;BYDAY=1SU\r\nEND:VEVENT\r\n",
+        ),
+        (
+            "YEARLY",
+            "53MO",
+            date(1984, 12, 31),  # 53rd Monday in (leap) year
+            b"BEGIN:VEVENT\r\nSUMMARY:Event YEARLY 53MO\r\nDTSTART;VALUE=DATE:19841231\r\nRRULE:FREQ=YEARLY;BYDAY=53MO\r\nEND:VEVENT\r\n",
+        ),
+        (
+            "YEARLY",
+            "-1TU",
+            date(1999, 12, 28),  # Last Tuesday in year
+            b"BEGIN:VEVENT\r\nSUMMARY:Event YEARLY -1TU\r\nDTSTART;VALUE=DATE:19991228\r\nRRULE:FREQ=YEARLY;BYDAY=-1TU\r\nEND:VEVENT\r\n",
+        ),
+        (
+            "YEARLY",
+            "-17WE",
+            date(2000, 9, 6),  # 17th-to-last Wednesday in year
+            b"BEGIN:VEVENT\r\nSUMMARY:Event YEARLY -17WE\r\nDTSTART;VALUE=DATE:20000906\r\nRRULE:FREQ=YEARLY;BYDAY=-17WE\r\nEND:VEVENT\r\n",
+        ),
+        # Test some MONTHLY BYDAY repeats
+        (
+            "MONTHLY",
+            "2TH",
+            date(2003, 4, 10),  # 2nd Thursday in month
+            b"BEGIN:VEVENT\r\nSUMMARY:Event MONTHLY 2TH\r\nDTSTART;VALUE=DATE:20030410\r\nRRULE:FREQ=MONTHLY;BYDAY=2TH\r\nEND:VEVENT\r\n",
+        ),
+        (
+            "MONTHLY",
+            "-3FR",
+            date(2017, 5, 12),  # 3rd-to-last Friday in month
+            b"BEGIN:VEVENT\r\nSUMMARY:Event MONTHLY -3FR\r\nDTSTART;VALUE=DATE:20170512\r\nRRULE:FREQ=MONTHLY;BYDAY=-3FR\r\nEND:VEVENT\r\n",
+        ),
+        (
+            "MONTHLY",
+            "-5SA",
+            date(2053, 11, 1),  # 5th-to-last Saturday in month
+            b"BEGIN:VEVENT\r\nSUMMARY:Event MONTHLY -5SA\r\nDTSTART;VALUE=DATE:20531101\r\nRRULE:FREQ=MONTHLY;BYDAY=-5SA\r\nEND:VEVENT\r\n",
+        ),
+        # Specifically test examples from the report of Issue #518
+        # https://github.com/collective/icalendar/issues/518
+        (
+            "YEARLY",
+            "9MO",
+            date(2023, 2, 27),  # 9th Monday in year
+            b"BEGIN:VEVENT\r\nSUMMARY:Event YEARLY 9MO\r\nDTSTART;VALUE=DATE:20230227\r\nRRULE:FREQ=YEARLY;BYDAY=9MO\r\nEND:VEVENT\r\n",
+        ),
+        (
+            "YEARLY",
+            "10MO",
+            date(2023, 3, 6),  # 10th Monday in year
+            b"BEGIN:VEVENT\r\nSUMMARY:Event YEARLY 10MO\r\nDTSTART;VALUE=DATE:20230306\r\nRRULE:FREQ=YEARLY;BYDAY=10MO\r\nEND:VEVENT\r\n",
+        ),
+    ],
+)
 def test_byday_to_ical(freq, byday, dtstart, expected):
-    'Test the BYDAY rule is correctly processed by to_ical().'
+    """Test the BYDAY rule is correctly processed by to_ical()."""
     event = Event()
-    event.add('SUMMARY', ' '.join(['Event', freq, byday]))
-    event.add('DTSTART', dtstart)
-    event.add('RRULE', {'FREQ':[freq], 'BYDAY':byday})
+    event.add("SUMMARY", " ".join(["Event", freq, byday]))
+    event.add("DTSTART", dtstart)
+    event.add("RRULE", {"FREQ": [freq], "BYDAY": byday})
     assert event.to_ical() == expected
diff -pruN 6.0.1-3/src/icalendar/tests/test_rfc_6868.py 6.3.1-1/src/icalendar/tests/test_rfc_6868.py
--- 6.0.1-3/src/icalendar/tests/test_rfc_6868.py	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/test_rfc_6868.py	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,108 @@
+"""This implemensts RFC 6868.
+
+There are only some changes to parameters needed.
+"""
+import os
+from typing import TYPE_CHECKING
+
+import pytest
+
+from icalendar import Calendar
+from icalendar.parser import dquote, rfc_6868_escape, rfc_6868_unescape
+
+if TYPE_CHECKING:
+    from icalendar import vCalAddress, vText
+
+
+param_duplicate = pytest.mark.parametrize(
+    "duplicate",
+    [ lambda x:x, lambda cal: Calendar.from_ical(cal.to_ical()) ]
+)
+
+@param_duplicate
+def test_rfc_6868_example(calendars, duplicate):
+    """Check the example from the RFC."""
+    cal : Calendar = duplicate(calendars.rfc_6868)
+    attendee : vCalAddress = cal.events[0]["attendee"]
+    assert attendee.name == 'George Herman "Babe" Ruth'
+
+
+@param_duplicate
+def test_all_parameters(calendars, duplicate):
+    """Check that all examples get decoded correctly."""
+    cal : Calendar = duplicate(calendars.rfc_6868)
+    param = cal["X-PARAM"].params["ALL"]
+    assert param == '^"\n'
+
+
+@param_duplicate
+def test_unknown_character(calendars, duplicate):
+    """if a ^ (U+005E) character is followed by any character other than
+      the ones above, parsers MUST leave both the ^ and the following
+      character in place"""
+    cal : Calendar = duplicate(calendars.rfc_6868)
+    param = cal["X-PARAM"].params["UNKNOWN"]
+    assert param == "^a^ ^asd"
+
+
+@pytest.mark.parametrize(
+    ("text", "expected"),
+    [
+        ("^a", "^a"),
+        ("^^", "^"),
+        # ("^n", ),  # see other test
+        ("^'", '"'),
+        ("^^a^b", "^a^b")
+    ],
+)
+@pytest.mark.parametrize(
+    "modify", [lambda x: x, lambda x: x*10, lambda x: f"asd{x}aaA^AA"]
+)
+def test_unescape(text, expected, modify):
+    """Check unescaping."""
+    result = rfc_6868_unescape(modify(text))
+    assert result == modify(expected)
+
+
+@pytest.mark.parametrize(
+    "newline", ["\n", "\r\n", "\r", os.linesep])
+def test_unescape_newline(newline, monkeypatch):
+    """Unescape the newline."""
+    monkeypatch.setattr(os, "linesep", newline)
+    assert rfc_6868_unescape("^n") == newline
+
+
+param_values = pytest.mark.parametrize("text, expected", [
+    ("", ""),
+    ("^", "^^"),
+    ("^n", "^^n"),
+    ("This text\n has\r several\r\n lines", "This text^n has^n several^n lines"),
+    ('Call me "Harry".', "Call me ^'Harry^'."),
+]
+)
+
+@param_values
+def test_escape_rfc_6868(text, expected):
+    """Check that we can escape the content with special characters."""
+    escaped = rfc_6868_escape(text)
+    assert escaped == expected, f"{escaped!r} == {expected!r}"
+    assert rfc_6868_escape(rfc_6868_unescape(escaped)) == expected
+
+
+@param_values
+def test_escaping_parameters(text, expected):
+    cal = Calendar()
+    cal.add("X-Param", "asd")
+    param : vText = cal["X-PARAM"]
+    param.params["RFC6868"] = text
+    ical = cal.to_ical().decode()
+    print(ical)
+    assert "X-PARAM;RFC6868=" + dquote(expected) in ical
+
+
+def test_encode_example_again(calendars):
+    """The example file should yield its content again."""
+    cal : Calendar = calendars.rfc_6868
+    again = Calendar.from_ical(cal.to_ical())
+    assert cal == again
+    assert cal.to_ical() == again.to_ical()
diff -pruN 6.0.1-3/src/icalendar/tests/test_rfc_7529.py 6.3.1-1/src/icalendar/tests/test_rfc_7529.py
--- 6.0.1-3/src/icalendar/tests/test_rfc_7529.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/test_rfc_7529.py	2025-05-20 07:31:39.000000000 +0000
@@ -1,21 +1,23 @@
 """This tests the compatibility with RFC 7529.
 
 See
-- https://github.com/collective/icalendar/issues/653
+- https://github.com/collective/icalendar/issues/655
 - https://www.rfc-editor.org/rfc/rfc7529.html
 """
+
 import pytest
-from icalendar.prop import vRecur, vMonth, vSkip
+
+from icalendar.prop import vMonth, vRecur, vSkip
 
 
 @pytest.mark.parametrize(
-    "uid,scale",
+    ("uid", "scale"),
     [
         ("4.3.1", "CHINESE"),
         ("4.3.2", "ETHIOPIC"),
         ("4.3.3", "HEBREW"),
         ("4.3.4", "GREGORIAN"),
-    ]
+    ],
 )
 def test_rscale(calendars, uid, scale):
     """Check that the RSCALE is parsed correctly."""
@@ -27,13 +29,13 @@ def test_rscale(calendars, uid, scale):
 
 
 @pytest.mark.parametrize(
-    "uid,skip",
+    ("uid", "skip"),
     [
         ("4.3.2", None),
         ("4.3.3", ["FORWARD"]),
-    ]
+    ],
 )
-def test_rscale(calendars, uid, skip):
+def test_rscale_with_skip(calendars, uid, skip):
     """Check that the RSCALE is parsed correctly."""
     event = calendars.rfc_7529.walk(select=lambda c: c.get("UID") == uid)[0]
     recur = event["RRULE"]
@@ -48,9 +50,13 @@ def test_leap_month(calendars):
 
 
 @pytest.mark.parametrize(
-    "ty, recur, ics",
+    ("ty", "recur", "ics"),
     [
-        (vRecur, vRecur(rscale="CHINESE", freq="YEARLY"), b"RSCALE=CHINESE;FREQ=YEARLY"),
+        (
+            vRecur,
+            vRecur(rscale="CHINESE", freq="YEARLY"),
+            b"RSCALE=CHINESE;FREQ=YEARLY",
+        ),
         (vRecur, vRecur(bymonth=vMonth(10)), b"BYMONTH=10"),
         (vRecur, vRecur(bymonth=vMonth("5L")), b"BYMONTH=5L"),
         (vMonth, vMonth(10), b"10"),
@@ -61,9 +67,17 @@ def test_leap_month(calendars):
         (vSkip, vSkip("OMIT"), b"OMIT"),
         (vSkip, vSkip("BACKWARD"), b"BACKWARD"),
         (vSkip, vSkip("FORWARD"), b"FORWARD"),
-        (vRecur, vRecur(rscale="GREGORIAN", freq="YEARLY", skip='FORWARD'), b"RSCALE=GREGORIAN;FREQ=YEARLY;SKIP=FORWARD"),
-        (vRecur, vRecur(rscale="GREGORIAN", freq="YEARLY", skip=vSkip.FORWARD), b"RSCALE=GREGORIAN;FREQ=YEARLY;SKIP=FORWARD"),
-    ]
+        (
+            vRecur,
+            vRecur(rscale="GREGORIAN", freq="YEARLY", skip="FORWARD"),
+            b"RSCALE=GREGORIAN;FREQ=YEARLY;SKIP=FORWARD",
+        ),
+        (
+            vRecur,
+            vRecur(rscale="GREGORIAN", freq="YEARLY", skip=vSkip.FORWARD),
+            b"RSCALE=GREGORIAN;FREQ=YEARLY;SKIP=FORWARD",
+        ),
+    ],
 )
 def test_conversion(ty, recur, ics):
     """Test string conversion."""
diff -pruN 6.0.1-3/src/icalendar/tests/test_rfc_7986.py 6.3.1-1/src/icalendar/tests/test_rfc_7986.py
--- 6.0.1-3/src/icalendar/tests/test_rfc_7986.py	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/test_rfc_7986.py	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,191 @@
+"""This tests additional attributes from :rfc:`7986`.
+
+Some attributes are also available as ``X-*`` attributes.
+They are also considered.
+"""
+from __future__ import annotations
+
+from typing import Union
+
+import pytest
+
+from icalendar import Calendar, Event, Journal, Todo
+from icalendar.prop import vText
+
+
+@pytest.fixture()
+def calendar() -> Calendar:
+    """Empty calendar"""
+    return Calendar()
+
+
+param_name = pytest.mark.parametrize("name", ["Company Vacation Days", "Calendar Name"])
+param_prop = pytest.mark.parametrize("prop", ["NAME", "X-WR-CALNAME"])
+
+
+@param_prop
+@param_name
+def test_get_calendar_name(prop, name, calendar):
+    """Get the name of the calendar."""
+    calendar.add(prop, name)
+    assert calendar.calendar_name == name
+
+
+@param_name
+def test_set_calendar_name(name, calendar):
+    """Setting the name overrides the old attributes."""
+    calendar.calendar_name = name
+    assert calendar.calendar_name == name
+    assert calendar["NAME"] == name
+
+
+@param_name
+@param_prop
+def test_replace_name(name, prop, calendar):
+    """Setting the name overrides the old attributes."""
+    calendar[prop] = "Other Name"
+    calendar.calendar_name = name
+    assert calendar.calendar_name == name
+
+
+@param_name
+@param_prop
+def test_del_name(name, calendar, prop):
+    """Delete the name."""
+    calendar.add(prop, name)
+    del calendar.calendar_name
+    assert calendar.calendar_name is None
+
+
+def test_default_name(calendar):
+    """We have no name by default."""
+    assert calendar.calendar_name is None
+
+
+@param_name
+def test_setting_the_name_deletes_the_non_standard_attribute(calendar, name):
+    """The default_attr is deleted when setting the name."""
+    calendar["X-WR-CALNAME"] = name
+    assert "X-WR-CALNAME" in calendar
+    calendar.calendar_name = "other name"
+    assert "X-WR-CALNAME" not in calendar
+
+
+@param_name
+@pytest.mark.parametrize("order", [1, 2])
+def test_multiple_names_use_the_one_without_a_language(calendar, name, order):
+    """Add several names and use the one without a language param."""
+    if order == 1:
+        calendar.add("NAME", name)
+    calendar.add("NAME", vText("Kalendername", params={"LANGUAGE":"de"}))
+    if order == 2:
+        calendar.add("NAME", name)
+    assert calendar.calendar_name == name
+
+
+@param_name
+def test_name_is_preferred(calendar, name):
+    """NAME is more important that X-WR-CALNAME"""
+    calendar.add("NAME", name)
+    calendar.add("X-WR-CALNAME", "asd")
+    assert calendar.calendar_name == name
+
+
+
+# For description, we would use the same tests as name, but we also use the
+# same code, so it is all right.
+
+param_color = pytest.mark.parametrize("desc", ["DESCRIPTION", "X-WR-CALDESC"])
+
+@param_color
+@param_name
+def test_description(calendar, desc, name):
+    """Get the value"""
+    calendar.add(desc, name)
+    assert calendar.description == name
+
+# For color, we would use the same tests as name, but we also use the
+# same code, so it is all right.
+
+param_color = pytest.mark.parametrize("color_param", ["COLOR", "X-APPLE-CALENDAR-COLOR"])
+
+@param_color
+def test_get_calendar_color(calendar, color_param, color):
+    """Get the value"""
+    calendar.add(color_param, color)
+    assert calendar.color == color
+
+@param_color
+def test_delete_calendar_color(calendar, color_param, color):
+    """Delete the value"""
+    calendar.add(color_param, color)
+    del calendar.color
+    assert calendar.color == ""
+    assert color_param not in calendar
+
+@param_color
+def test_set_calendar_color(calendar, color_param, color):
+    """Set the color and it replaces what is there."""
+    calendar.add(color_param, "green")
+    calendar.color = color
+    assert calendar.color == color
+    assert calendar["COLOR"] == color
+
+def test_get_COLOR_first(calendar, color):
+    """We prefer COLOR over X-APPLE-CALENDAR-COLOR"""
+    calendar.add("COLOR", color)
+    calendar.add("X-APPLE-CALENDAR-COLOR", "green")
+    assert calendar.color == color
+
+# The color of the event is a bit different
+# It only appears once and does not have a backup.
+
+@pytest.fixture(params=[Calendar, Event, Todo, Journal])
+def color_component(request) -> Union[Calendar, Event, Todo, Journal]:
+    """An empty component that should have a color attribute."""
+    return request.param()
+
+@pytest.fixture(params=["blue", "#123456"])
+def color(request) -> str:
+    """Return a color."""
+    return request.param
+
+def test_default_color(color_component: Union[Calendar, Event, Todo, Journal]):
+    """There is no color by default."""
+    assert color_component.color == ""
+
+def test_set_the_color(color:str, color_component: Union[Calendar, Event, Todo, Journal]):
+    """We set the value and get it."""
+    color_component.color = color
+    assert color_component.color == color
+    assert color_component["COLOR"] == color
+
+def test_replace_color(color:str, color_component: Union[Calendar, Event, Todo, Journal]):
+    """Replace the color."""
+    color_component.color = "blue"
+    color_component.color = color
+    assert color_component.color == color
+    assert color_component["COLOR"] == color
+
+
+def test_multiple_colors(color_component: Union[Calendar, Event, Todo, Journal]):
+    """Add several colors and use the first one."""
+    color_component.add("COLOR", "blue")
+    color_component.add("COLOR", "green")
+    assert color_component.color == "blue"
+
+
+def test_delete_the_color(color_component: Union[Calendar, Event, Todo, Journal]):
+    """Delete the color."""
+    color_component.color = "blue"
+    del color_component.color
+    assert "COLOR" not in color_component
+    assert color_component.color == ""
+
+
+def test_set_if_multiple_colors(color: str, color_component: Union[Calendar, Event, Todo, Journal]):
+    """Add several colors and use the first one."""
+    color_component.add("COLOR", "blue")
+    color_component.add("COLOR", "green")
+    color_component.color = color
+    assert color_component.color == color
diff -pruN 6.0.1-3/src/icalendar/tests/test_rfc_7986_categories.py 6.3.1-1/src/icalendar/tests/test_rfc_7986_categories.py
--- 6.0.1-3/src/icalendar/tests/test_rfc_7986_categories.py	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/test_rfc_7986_categories.py	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,71 @@
+"""This tests the compatibility with RFC 7529.
+
+CATEGORIES property
+
+See
+- https://github.com/collective/icalendar/issues/655
+- https://www.rfc-editor.org/rfc/rfc7529.html
+"""
+
+from typing import Union
+
+import pytest
+
+from icalendar import Calendar, Event, Journal, Todo
+
+CTJE = Union[Calendar, Event, Journal, Todo]
+
+@pytest.fixture(params=[Event, Calendar, Todo, Journal])
+def component(request):
+    """An empty component with possible categories."""
+    return request.param()
+
+
+def test_no_categories_at_creation(component: CTJE):
+    """An empty component has no categories."""
+    assert "CATEGORIES" not in component
+    assert component.categories == []
+
+
+def test_add_one_category(component: CTJE):
+    """Add one category."""
+    component.add("categories", "Lecture")
+    assert component.categories == ["Lecture"]
+
+def test_add_multiple_categories(component: CTJE):
+    """Add categories."""
+    component.add("categories", ["Lecture", "Workshop"])
+    assert component.categories == ["Lecture", "Workshop"]
+
+def test_set_categories(component: CTJE):
+    """Set categories."""
+    component.categories = ["Lecture", "Workshop"]
+    assert component.categories == ["Lecture", "Workshop"]
+
+
+def test_modify_list(component: CTJE):
+    """Modify the list and it still works."""
+    component.categories = categories = ["cat1"]
+    categories.append("cat2")
+    assert component.categories == ["cat1", "cat2"]
+
+
+def test_delete_categories(component: CTJE):
+    """Delete categories."""
+    component.categories = ["Lecture", "Workshop"]
+    del component.categories
+    assert "CATEGORIES" not in component
+    assert component.categories == []
+
+
+def test_manage_add_append_remove_categories(component: CTJE):
+    """Manage multiple categories by merging them, then append
+    and remove a category from the resulting set."""
+    component.add("categories", ["c1", "c2"])
+    component.add("categories", ["c3", "c4"])
+    assert component.categories == ["c1", "c2", "c3", "c4"]
+    component.categories.append("c5")
+    assert component.categories == ["c1", "c2", "c3", "c4", "c5"]
+    component.categories.remove("c2")
+    assert component.categories == ["c1", "c3", "c4", "c5"]
+    assert "c1,c3,c4,c5" in component.to_ical().decode()
diff -pruN 6.0.1-3/src/icalendar/tests/test_rfc_9074.py 6.3.1-1/src/icalendar/tests/test_rfc_9074.py
--- 6.0.1-3/src/icalendar/tests/test_rfc_9074.py	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/test_rfc_9074.py	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,44 @@
+"""Test the VALARM compatibility of RFC 9074.
+
+See https://www.rfc-editor.org/rfc/rfc9074.html
+and also https://github.com/collective/icalendar/issues/657
+"""
+
+import pytest
+
+from icalendar.prop import vDDDTypes, vText
+
+
+@pytest.mark.parametrize(
+    ("prop", "cls", "file", "alarm_index"),
+    [
+        ("UID", vText, "rfc_9074_example_1", 0),
+        ("RELATED-TO", vText, "rfc_9074_example_2", 1),
+        ("ACKNOWLEDGED", vDDDTypes, "rfc_9074_example_3", 0),
+        ("PROXIMITY", vText, "rfc_9074_example_proximity", 0),
+    ],
+)
+def test_calendar_types(events, prop, cls, file, alarm_index):
+    """Check the types of the properties."""
+    event = events[file]
+    alarm = event.subcomponents[alarm_index]
+    value = alarm[prop]
+    assert isinstance(value, cls)
+
+
+def test_snooze(events):
+    """Check values of the alarms."""
+    alarm_1 = events.rfc_9074_example_3.subcomponents[0]
+    assert alarm_1["ACKNOWLEDGED"].dt == vDDDTypes.from_ical("20210302T152024Z")
+    alarm_2 = events.rfc_9074_example_3.subcomponents[1]
+    assert alarm_2["RELATED-TO"] == "8297C37D-BA2D-4476-91AE-C1EAA364F8E1"
+    assert alarm_2["RELATED-TO"].params["RELTYPE"] == "SNOOZE"
+
+
+def test_proximity(events):
+    """Check the proximity values."""
+    alarm = events.rfc_9074_example_proximity.subcomponents[0]
+    assert alarm["PROXIMITY"] == "DEPART"
+    assert len(alarm.subcomponents) == 1
+    location = alarm.subcomponents[0]
+    assert location["UID"] == "123456-abcdef-98765432"
diff -pruN 6.0.1-3/src/icalendar/tests/test_time.py 6.3.1-1/src/icalendar/tests/test_time.py
--- 6.0.1-3/src/icalendar/tests/test_time.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/test_time.py	2025-05-20 07:31:39.000000000 +0000
@@ -1,28 +1,30 @@
 import datetime
-import icalendar
 import os
 
+import icalendar
+
+
 def test_value_type_is_not_mapped():
     """Usually, the value should be absent."""
-    assert 'X-SOMETIME' not in icalendar.cal.types_factory.types_map
+    assert "X-SOMETIME" not in icalendar.cal.types_factory.types_map
 
 
 def test_value_type_is_mapped(x_sometime):
     """The value is mapped for the test."""
-    assert 'X-SOMETIME' in icalendar.cal.types_factory.types_map
+    assert "X-SOMETIME" in icalendar.cal.types_factory.types_map
 
 
 def test_create_from_ical(x_sometime):
     directory = os.path.dirname(__file__)
-    ics = open(os.path.join(directory, 'calendars', 'time.ics'), 'rb')
+    ics = open(os.path.join(directory, "calendars", "time.ics"), "rb")
     cal = icalendar.Calendar.from_ical(ics.read())
     ics.close()
 
-    assert cal['X-SOMETIME'].dt == datetime.time(17, 20, 10)
-    assert cal['X-SOMETIME'].to_ical() == '172010'
+    assert cal["X-SOMETIME"].dt == datetime.time(17, 20, 10)
+    assert cal["X-SOMETIME"].to_ical() == "172010"
 
 
 def test_create_to_ical(x_sometime):
     cal = icalendar.Calendar()
-    cal.add('X-SOMETIME', datetime.time(17, 20, 10))
-    assert b'X-SOMETIME;VALUE=TIME:172010' in cal.to_ical().splitlines()
+    cal.add("X-SOMETIME", datetime.time(17, 20, 10))
+    assert b"X-SOMETIME;VALUE=TIME:172010" in cal.to_ical().splitlines()
diff -pruN 6.0.1-3/src/icalendar/tests/test_timezone_identification.py 6.3.1-1/src/icalendar/tests/test_timezone_identification.py
--- 6.0.1-3/src/icalendar/tests/test_timezone_identification.py	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/test_timezone_identification.py	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,32 @@
+"""Test that we can identify all timezones.
+
+Timezones can be removed from ./timezone_ids.py if they make the tests fail:
+Timezone information changes over time and can be dependent on the operating system's
+timezone database (zoneinfo, dateutil) or the package (pytz).
+We want to make sure we can roughly identify most of them.
+"""
+
+from icalendar.timezone import tzid_from_tzinfo, tzids_from_tzinfo
+from icalendar.timezone.tzp import TZP
+
+
+def test_can_identify_zoneinfo(tzid, zoneinfo_only, tzp:TZP):
+    """Check that all those zoneinfo timezones can be identified."""
+    assert tzid in tzids_from_tzinfo(tzp.timezone(tzid))
+
+
+def test_can_identify_pytz(tzid, pytz_only, tzp:TZP):
+    """Check that all those pytz timezones can be identified."""
+    assert tzid in tzids_from_tzinfo(tzp.timezone(tzid))
+
+
+def test_can_identify_dateutil(tzid):
+    """Check that all those dateutil timezones can be identified."""
+    from dateutil.tz import gettz
+    assert tzid in tzids_from_tzinfo(gettz(tzid))
+
+
+def test_utc_is_identified(utc):
+    """Test UTC because it is handled in a special way."""
+    assert "UTC" in tzids_from_tzinfo(utc)
+    assert tzid_from_tzinfo(utc) == "UTC"
diff -pruN 6.0.1-3/src/icalendar/tests/test_timezoned.py 6.3.1-1/src/icalendar/tests/test_timezoned.py
--- 6.0.1-3/src/icalendar/tests/test_timezoned.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/test_timezoned.py	2025-05-20 07:31:39.000000000 +0000
@@ -1,6 +1,7 @@
-
 import datetime
+
 import dateutil.parser
+
 import icalendar
 from icalendar.prop import tzid_from_dt
 
@@ -9,49 +10,53 @@ def test_create_from_ical(calendars, oth
     """Create a calendar from a .ics file."""
     cal = calendars.timezoned
 
-    assert cal['prodid'].to_ical() == b"-//Plone.org//NONSGML plone.app.event//EN"
+    assert cal["prodid"].to_ical() == b"-//Plone.org//NONSGML plone.app.event//EN"
 
-    timezones = cal.walk('VTIMEZONE')
+    timezones = cal.walk("VTIMEZONE")
     assert len(timezones) == 1
 
     tz = timezones[0]
-    assert tz['tzid'].to_ical() == b"Europe/Vienna"
+    assert tz["tzid"].to_ical() == b"Europe/Vienna"
 
-    std = tz.walk('STANDARD')[0]
-    assert std.decoded('TZOFFSETFROM') == datetime.timedelta(0, 7200)
+    std = tz.walk("STANDARD")[0]
+    assert std.decoded("TZOFFSETFROM") == datetime.timedelta(0, 7200)
 
-    ev1 = cal.walk('VEVENT')[0]
-    assert ev1.decoded('DTSTART') == other_tzp.localize(datetime.datetime(2012, 2, 13, 10, 0, 0), 'Europe/Vienna')
-    assert ev1.decoded('DTSTAMP') == other_tzp.localize(datetime.datetime(2010, 10, 10, 9, 10, 10), 'UTC')
+    ev1 = cal.walk("VEVENT")[0]
+    assert ev1.decoded("DTSTART") == other_tzp.localize(
+        datetime.datetime(2012, 2, 13, 10, 0, 0), "Europe/Vienna"
+    )
+    assert ev1.decoded("DTSTAMP") == other_tzp.localize(
+        datetime.datetime(2010, 10, 10, 9, 10, 10), "UTC"
+    )
 
 
 def test_create_to_ical(tzp):
     cal = icalendar.Calendar()
 
-    cal.add('prodid', "-//Plone.org//NONSGML plone.app.event//EN")
-    cal.add('version', "2.0")
-    cal.add('x-wr-calname', "test create calendar")
-    cal.add('x-wr-caldesc', "icalendar tests")
-    cal.add('x-wr-relcalid', "12345")
-    cal.add('x-wr-timezone', "Europe/Vienna")
+    cal.add("prodid", "-//Plone.org//NONSGML plone.app.event//EN")
+    cal.add("version", "2.0")
+    cal.add("x-wr-calname", "test create calendar")
+    cal.add("x-wr-caldesc", "icalendar tests")
+    cal.add("x-wr-relcalid", "12345")
+    cal.add("x-wr-timezone", "Europe/Vienna")
 
     tzc = icalendar.Timezone()
-    tzc.add('tzid', 'Europe/Vienna')
-    tzc.add('x-lic-location', 'Europe/Vienna')
+    tzc.add("tzid", "Europe/Vienna")
+    tzc.add("x-lic-location", "Europe/Vienna")
 
     tzs = icalendar.TimezoneStandard()
-    tzs.add('tzname', 'CET')
-    tzs.add('dtstart', datetime.datetime(1970, 10, 25, 3, 0, 0))
-    tzs.add('rrule', {'freq': 'yearly', 'bymonth': 10, 'byday': '-1su'})
-    tzs.add('TZOFFSETFROM', datetime.timedelta(hours=2))
-    tzs.add('TZOFFSETTO', datetime.timedelta(hours=1))
+    tzs.add("tzname", "CET")
+    tzs.add("dtstart", datetime.datetime(1970, 10, 25, 3, 0, 0))
+    tzs.add("rrule", {"freq": "yearly", "bymonth": 10, "byday": "-1su"})
+    tzs.add("TZOFFSETFROM", datetime.timedelta(hours=2))
+    tzs.add("TZOFFSETTO", datetime.timedelta(hours=1))
 
     tzd = icalendar.TimezoneDaylight()
-    tzd.add('tzname', 'CEST')
-    tzd.add('dtstart', datetime.datetime(1970, 3, 29, 2, 0, 0))
-    tzs.add('rrule', {'freq': 'yearly', 'bymonth': 3, 'byday': '-1su'})
-    tzd.add('TZOFFSETFROM', datetime.timedelta(hours=1))
-    tzd.add('TZOFFSETTO', datetime.timedelta(hours=2))
+    tzd.add("tzname", "CEST")
+    tzd.add("dtstart", datetime.datetime(1970, 3, 29, 2, 0, 0))
+    tzs.add("rrule", {"freq": "yearly", "bymonth": 3, "byday": "-1su"})
+    tzd.add("TZOFFSETFROM", datetime.timedelta(hours=1))
+    tzd.add("TZOFFSETTO", datetime.timedelta(hours=2))
 
     tzc.add_component(tzs)
     tzc.add_component(tzd)
@@ -59,36 +64,41 @@ def test_create_to_ical(tzp):
 
     event = icalendar.Event()
     event.add(
-        'dtstart',
-        tzp.localize(datetime.datetime(2012, 2, 13, 10, 00, 00), "Europe/Vienna"))
+        "dtstart",
+        tzp.localize(datetime.datetime(2012, 2, 13, 10, 00, 00), "Europe/Vienna"),
+    )
     event.add(
-        'dtend',
-        tzp.localize(datetime.datetime(2012, 2, 17, 18, 00, 00), "Europe/Vienna"))
+        "dtend",
+        tzp.localize(datetime.datetime(2012, 2, 17, 18, 00, 00), "Europe/Vienna"),
+    )
     event.add(
-        'dtstamp',
-        tzp.localize(datetime.datetime(2010, 10, 10, 10, 10, 10), "Europe/Vienna"))
+        "dtstamp",
+        tzp.localize(datetime.datetime(2010, 10, 10, 10, 10, 10), "Europe/Vienna"),
+    )
     event.add(
-        'created',
-        tzp.localize(datetime.datetime(2010, 10, 10, 10, 10, 10), "Europe/Vienna"))
-    event.add('uid', '123456')
+        "created",
+        tzp.localize(datetime.datetime(2010, 10, 10, 10, 10, 10), "Europe/Vienna"),
+    )
+    event.add("uid", "123456")
     event.add(
-        'last-modified',
-        tzp.localize(datetime.datetime(2010, 10, 10, 10, 10, 10), "Europe/Vienna"))
-    event.add('summary', 'artsprint 2012')
+        "last-modified",
+        tzp.localize(datetime.datetime(2010, 10, 10, 10, 10, 10), "Europe/Vienna"),
+    )
+    event.add("summary", "artsprint 2012")
     # event.add('rrule', 'FREQ=YEARLY;INTERVAL=1;COUNT=10')
-    event.add('description', 'sprinting at the artsprint')
-    event.add('location', 'aka bild, wien')
-    event.add('categories', 'first subject')
-    event.add('categories', 'second subject')
-    event.add('attendee', 'häns')
-    event.add('attendee', 'franz')
-    event.add('attendee', 'sepp')
-    event.add('contact', 'Max Mustermann, 1010 Wien')
-    event.add('url', 'https://plone.org')
+    event.add("description", "sprinting at the artsprint")
+    event.add("location", "aka bild, wien")
+    event.add("categories", "first subject")
+    event.add("categories", "second subject")
+    event.add("attendee", "häns")
+    event.add("attendee", "franz")
+    event.add("attendee", "sepp")
+    event.add("contact", "Max Mustermann, 1010 Wien")
+    event.add("url", "https://plone.org")
     cal.add_component(event)
 
-    test_out = b'|'.join(cal.to_ical().splitlines())
-    test_out = test_out.decode('utf-8')
+    test_out = b"|".join(cal.to_ical().splitlines())
+    test_out = test_out.decode("utf-8")
 
     vtimezone_lines = "BEGIN:VTIMEZONE|TZID:Europe/Vienna|X-LIC-LOCATION:"
     "Europe/Vienna|BEGIN:STANDARD|DTSTART:19701025T03"
@@ -100,61 +110,72 @@ def test_create_to_ical(tzp):
     assert vtimezone_lines in test_out
 
     test_str = "DTSTART;TZID=Europe/Vienna:20120213T100000"
-    assert (test_str in test_out)
-    assert ("ATTENDEE:sepp" in test_out)
+    assert test_str in test_out
+    assert "ATTENDEE:sepp" in test_out
 
     # ical standard expects DTSTAMP and CREATED in UTC
-    assert ("DTSTAMP:20101010T081010Z" in test_out)
-    assert ("CREATED:20101010T081010Z" in test_out)
+    assert "DTSTAMP:20101010T081010Z" in test_out
+    assert "CREATED:20101010T081010Z" in test_out
 
 
 def test_tzinfo_dateutil():
     """Test for issues #77, #63
     references: #73,7430b66862346fe3a6a100ab25e35a8711446717
     """
-    date = dateutil.parser.parse('2012-08-30T22:41:00Z')
-    date2 = dateutil.parser.parse('2012-08-30T22:41:00 +02:00')
-    assert (date.tzinfo.__module__.startswith('dateutil.tz'))
-    assert (date2.tzinfo.__module__.startswith('dateutil.tz'))
+    date = dateutil.parser.parse("2012-08-30T22:41:00Z")
+    date2 = dateutil.parser.parse("2012-08-30T22:41:00 +02:00")
+    assert date.tzinfo.__module__.startswith("dateutil.tz")
+    assert date2.tzinfo.__module__.startswith("dateutil.tz")
 
     # make sure, it's parsed properly and doesn't throw an error
-    assert (icalendar.vDDDTypes(date).to_ical()
-                    == b'20120830T224100Z')
-    assert (icalendar.vDDDTypes(date2).to_ical()
-                    == b'20120830T224100')
+    assert icalendar.vDDDTypes(date).to_ical() == b"20120830T224100Z"
+    assert icalendar.vDDDTypes(date2).to_ical() == b"20120830T224100"
 
 
 def test_create_america_new_york(calendars, tzp):
     """testing America/New_York, the most complex example from the RFC"""
     cal = calendars.america_new_york
-    dt = cal.walk('VEVENT')[0]['DTSTART'][0].dt
-    assert tzid_from_dt(dt) in ('custom_America/New_York', "EDT")
+    dt = cal.events[0].start
+    assert tzid_from_dt(dt) in ("custom_America/New_York", "EDT")
 
+def test_create_america_new_york_forward_reference(calendars, tzp):
+    """testing America/New_York variant with VTIMEZONE as a forward reference"""
+    cal = calendars.america_new_york_forward_reference
+    dt = cal.walk('VEVENT')[0]['DTSTART'][0].dt
+    assert tzid_from_dt(dt) in ('custom_America/New_York_Forward_reference', "EDT")
 
 def test_america_new_york_with_pytz(calendars, tzp, pytz_only):
     """Create a custom timezone with pytz and test the transition times."""
     print(tzp)
     cal = calendars.america_new_york
-    dt = cal.walk('VEVENT')[0]['DTSTART'][0].dt
+    dt = cal.events[0].start
     tz = dt.tzinfo
-    tz_new_york = tzp.timezone('America/New_York')
+    tz_new_york = tzp.timezone("America/New_York")
     # for reasons (tm) the locally installed version of the timezone
     # database isn't always complete, therefore we only compare some
     # transition times
     ny_transition_times = []
     ny_transition_info = []
     for num, date in enumerate(tz_new_york._utc_transition_times):
-        if datetime.datetime(1967, 4, 30, 7, 0)\
-                <= date <= datetime.datetime(2037, 11, 1, 6, 0):
+        if (
+            datetime.datetime(1967, 4, 30, 7, 0)
+            <= date
+            <= datetime.datetime(2037, 11, 1, 6, 0)
+        ):
             ny_transition_times.append(date)
             ny_transition_info.append(tz_new_york._transition_info[num])
     assert tz._utc_transition_times[:142] == ny_transition_times
     assert tz._transition_info[0:142] == ny_transition_info
     assert (
-            datetime.timedelta(-1, 72000),
-            datetime.timedelta(0, 3600), 'EDT'
-        ) in tz._tzinfos.keys()
-    assert (datetime.timedelta(-1, 68400), datetime.timedelta(0), 'EST') in tz._tzinfos.keys()
+        datetime.timedelta(-1, 72000),
+        datetime.timedelta(0, 3600),
+        "EDT",
+    ) in tz._tzinfos.keys()
+    assert (
+        datetime.timedelta(-1, 68400),
+        datetime.timedelta(0),
+        "EST",
+    ) in tz._tzinfos.keys()
 
 
 fiji_transition_times = [
@@ -221,68 +242,85 @@ fiji_transition_times = [
     datetime.datetime(2037, 1, 17, 13, 0),
     datetime.datetime(2037, 10, 24, 14, 0),
     datetime.datetime(2038, 1, 23, 13, 0),
-    datetime.datetime(2038, 10, 23, 14, 0)
+    datetime.datetime(2038, 10, 23, 14, 0),
 ]
 
 fiji_transition_info = (
-    [(
-        datetime.timedelta(0, 43200),
-        datetime.timedelta(0),
-        'custom_Pacific/Fiji_19151026T000000_+115544_+1200'
-    )] +
-    3 * [(
-        datetime.timedelta(0, 46800),
-        datetime.timedelta(0, 3600),
-        'custom_Pacific/Fiji_19981101T020000_+1200_+1300'
-    ), (
-        datetime.timedelta(0, 43200),
-        datetime.timedelta(0),
-        'custom_Pacific/Fiji_19990228T030000_+1300_+1200')
-    ] +
-    3 * [(
-        datetime.timedelta(0, 46800),
-        datetime.timedelta(0, 3600),
-        'custom_Pacific/Fiji_20101024T020000_+1200_+1300'
-    ), (
-        datetime.timedelta(0, 43200),
-        datetime.timedelta(0),
-        'custom_Pacific/Fiji_19990228T030000_+1300_+1200'
-    )] +
-    25 * [(
-        datetime.timedelta(0, 46800),
-        datetime.timedelta(0, 3600),
-        'custom_Pacific/Fiji_20101024T020000_+1200_+1300'
-    ), (
-        datetime.timedelta(0, 43200),
-        datetime.timedelta(0),
-        'custom_Pacific/Fiji_20140119T020000_+1300_+1200'
-    )] +
-    [(
-        datetime.timedelta(0, 46800),
-        datetime.timedelta(0, 3600),
-        'custom_Pacific/Fiji_20101024T020000_+1200_+1300'
-    )]
+    [
+        (
+            datetime.timedelta(0, 43200),
+            datetime.timedelta(0),
+            "custom_Pacific/Fiji_19151026T000000_+115544_+1200",
+        )
+    ]
+    + 3
+    * [
+        (
+            datetime.timedelta(0, 46800),
+            datetime.timedelta(0, 3600),
+            "custom_Pacific/Fiji_19981101T020000_+1200_+1300",
+        ),
+        (
+            datetime.timedelta(0, 43200),
+            datetime.timedelta(0),
+            "custom_Pacific/Fiji_19990228T030000_+1300_+1200",
+        ),
+    ]
+    + 3
+    * [
+        (
+            datetime.timedelta(0, 46800),
+            datetime.timedelta(0, 3600),
+            "custom_Pacific/Fiji_20101024T020000_+1200_+1300",
+        ),
+        (
+            datetime.timedelta(0, 43200),
+            datetime.timedelta(0),
+            "custom_Pacific/Fiji_19990228T030000_+1300_+1200",
+        ),
+    ]
+    + 25
+    * [
+        (
+            datetime.timedelta(0, 46800),
+            datetime.timedelta(0, 3600),
+            "custom_Pacific/Fiji_20101024T020000_+1200_+1300",
+        ),
+        (
+            datetime.timedelta(0, 43200),
+            datetime.timedelta(0),
+            "custom_Pacific/Fiji_20140119T020000_+1300_+1200",
+        ),
+    ]
+    + [
+        (
+            datetime.timedelta(0, 46800),
+            datetime.timedelta(0, 3600),
+            "custom_Pacific/Fiji_20101024T020000_+1200_+1300",
+        )
+    ]
 )
 
+
 def test_create_pacific_fiji(calendars, pytz_only):
     """testing Pacific/Fiji, another pretty complex example with more than
     one RDATE property per subcomponent"""
     cal = calendars.pacific_fiji
 
-    tz = cal.walk('VEVENT')[0]['DTSTART'][0].dt.tzinfo
-    assert str(tz) == 'custom_Pacific/Fiji'
+    tz = cal.walk("VEVENT")[0]["DTSTART"][0].dt.tzinfo
+    assert str(tz) == "custom_Pacific/Fiji"
     assert tz._utc_transition_times == fiji_transition_times
     assert tz._transition_info == fiji_transition_info
     assert (
-            datetime.timedelta(0, 46800),
-            datetime.timedelta(0, 3600),
-            'custom_Pacific/Fiji_19981101T020000_+1200_+1300'
-        ) in  tz._tzinfos.keys()
+        datetime.timedelta(0, 46800),
+        datetime.timedelta(0, 3600),
+        "custom_Pacific/Fiji_19981101T020000_+1200_+1300",
+    ) in tz._tzinfos.keys()
     assert (
-            datetime.timedelta(0, 43200),
-            datetime.timedelta(0),
-            'custom_Pacific/Fiji_19990228T030000_+1300_+1200'
-        ) in tz._tzinfos.keys()
+        datetime.timedelta(0, 43200),
+        datetime.timedelta(0),
+        "custom_Pacific/Fiji_19990228T030000_+1300_+1200",
+    ) in tz._tzinfos.keys()
 
 
 # these are the expected offsets before and after the fiji_transition_times
@@ -356,8 +394,8 @@ fiji_expected_offsets = [
 
 def test_transition_times_fiji(tzp, timezones):
     """The transition times are computed."""
-    tz = timezones.pacific_fiji.to_tz(tzp)
-    offsets = [] # [(before, after), ...]
+    tz = timezones.pacific_fiji.to_tz(tzp, lookup_tzid=False)
+    offsets = []  # [(before, after), ...]
     for i, transition_time in enumerate(fiji_transition_times):
         before_after_offset = []
         for offset in (datetime.timedelta(hours=-1), datetime.timedelta(hours=+1)):
@@ -372,42 +410,43 @@ def test_same_start_date(calendars):
     """testing if we can handle VTIMEZONEs whose different components
     have the same start DTIMEs."""
     cal = calendars.timezone_same_start
-    d = cal.subcomponents[1]['DTSTART'].dt
-    assert d.strftime('%c') == 'Fri Feb 24 12:00:00 2017'
+    d = cal.subcomponents[1]["DTSTART"].dt
+    assert d.strftime("%c") == "Fri Feb 24 12:00:00 2017"
+
 
 def test_same_start_date_and_offset(calendars):
     """testing if we can handle VTIMEZONEs whose different components
     have the same DTSTARTs, TZOFFSETFROM, and TZOFFSETTO."""
     cal = calendars.timezone_same_start_and_offset
-    d = cal.subcomponents[1]['DTSTART'].dt
-    assert d.strftime('%c') == 'Fri Feb 24 12:00:00 2017'
+    d = cal.subcomponents[1]["DTSTART"].dt
+    assert d.strftime("%c") == "Fri Feb 24 12:00:00 2017"
+
 
 def test_rdate(calendars):
-    """testing if we can handle VTIMEZONEs who only have an RDATE, not RRULE
-    """
+    """testing if we can handle VTIMEZONEs who only have an RDATE, not RRULE"""
     cal = calendars.timezone_rdate
-    vevent = cal.walk('VEVENT')[0]
-    assert tzid_from_dt(vevent['DTSTART'].dt) in ('posix/Europe/Vaduz', "CET")
+    vevent = cal.walk("VEVENT")[0]
+    assert tzid_from_dt(vevent["DTSTART"].dt) in ("posix/Europe/Vaduz", "CET")
+
 
 def test_rdate_pytz(calendars, pytz_only):
-    """testing if we can handle VTIMEZONEs who only have an RDATE, not RRULE
-    """
+    """testing if we can handle VTIMEZONEs who only have an RDATE, not RRULE"""
     cal = calendars.timezone_rdate
-    vevent = cal.walk('VEVENT')[0]
-    tz = vevent['DTSTART'].dt.tzinfo
+    vevent = cal.walk("VEVENT")[0]
+    tz = vevent["DTSTART"].dt.tzinfo
     assert tz._utc_transition_times[:6] == [
-            datetime.datetime(1901, 12, 13, 20, 45, 38),
-            datetime.datetime(1941, 5, 5, 0, 0, 0),
-            datetime.datetime(1941, 10, 6, 0, 0, 0),
-            datetime.datetime(1942, 5, 4, 0, 0, 0),
-            datetime.datetime(1942, 10, 5, 0, 0, 0),
-            datetime.datetime(1981, 3, 29, 1, 0),
-        ]
+        datetime.datetime(1901, 12, 13, 20, 45, 38),
+        datetime.datetime(1941, 5, 5, 0, 0, 0),
+        datetime.datetime(1941, 10, 6, 0, 0, 0),
+        datetime.datetime(1942, 5, 4, 0, 0, 0),
+        datetime.datetime(1942, 10, 5, 0, 0, 0),
+        datetime.datetime(1981, 3, 29, 1, 0),
+    ]
     assert tz._transition_info[:6] == [
-            (datetime.timedelta(0, 3600), datetime.timedelta(0), 'CET'),
-            (datetime.timedelta(0, 7200), datetime.timedelta(0, 3600), 'CEST'),
-            (datetime.timedelta(0, 3600), datetime.timedelta(0), 'CET'),
-            (datetime.timedelta(0, 7200), datetime.timedelta(0, 3600), 'CEST'),
-            (datetime.timedelta(0, 3600), datetime.timedelta(0), 'CET'),
-            (datetime.timedelta(0, 7200), datetime.timedelta(0, 3600), 'CEST'),
-        ]
+        (datetime.timedelta(0, 3600), datetime.timedelta(0), "CET"),
+        (datetime.timedelta(0, 7200), datetime.timedelta(0, 3600), "CEST"),
+        (datetime.timedelta(0, 3600), datetime.timedelta(0), "CET"),
+        (datetime.timedelta(0, 7200), datetime.timedelta(0, 3600), "CEST"),
+        (datetime.timedelta(0, 3600), datetime.timedelta(0), "CET"),
+        (datetime.timedelta(0, 7200), datetime.timedelta(0, 3600), "CEST"),
+    ]
diff -pruN 6.0.1-3/src/icalendar/tests/test_unit_cal.py 6.3.1-1/src/icalendar/tests/test_unit_cal.py
--- 6.0.1-3/src/icalendar/tests/test_unit_cal.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/test_unit_cal.py	2025-05-20 07:31:39.000000000 +0000
@@ -1,13 +1,12 @@
 import itertools
-from datetime import datetime
-from datetime import timedelta
+import re
+from datetime import datetime, timedelta
 
 import pytest
 
 import icalendar
-import re
-from icalendar.cal import Component, Calendar, Event
 from icalendar import prop
+from icalendar.cal import Calendar, Component, Event
 from icalendar.prop import tzid_from_dt
 
 
@@ -21,15 +20,15 @@ def test_nonempty_calendar_component(cal
     """Every key defines a property.A property can consist of either a
     single item. This can be set with a single value...
     """
-    calendar_component['prodid'] = '-//max m//icalendar.mxm.dk/'
+    calendar_component["prodid"] = "-//max m//icalendar.mxm.dk/"
     assert not calendar_component.is_empty()
-    assert calendar_component == Calendar({'PRODID': '-//max m//icalendar.mxm.dk/'})
+    assert calendar_component == Calendar({"PRODID": "-//max m//icalendar.mxm.dk/"})
 
     # or with a list
-    calendar_component['ATTENDEE'] = ['Max M', 'Rasmussen']
+    calendar_component["ATTENDEE"] = ["Max M", "Rasmussen"]
     assert calendar_component == Calendar(
-        {'ATTENDEE': ['Max M', 'Rasmussen'],
-         'PRODID': '-//max m//icalendar.mxm.dk/'})
+        {"ATTENDEE": ["Max M", "Rasmussen"], "PRODID": "-//max m//icalendar.mxm.dk/"}
+    )
 
 
 def test_add_multiple_values(event_component):
@@ -39,57 +38,62 @@ def test_add_multiple_values(event_compo
     a list or not.
     """
     # add multiple values at once
-    event_component.add('attendee',
-          ['test@test.com', 'test2@test.com'])
+    event_component.add("attendee", ["test@test.com", "test2@test.com"])
 
     # or add one per line
-    event_component.add('attendee', 'maxm@mxm.dk')
-    event_component.add('attendee', 'test@example.dk')
+    event_component.add("attendee", "maxm@mxm.dk")
+    event_component.add("attendee", "test@example.dk")
 
     # add again multiple values at once to very concatenaton of lists
-    event_component.add('attendee',
-          ['test3@test.com', 'test4@test.com'])
+    event_component.add("attendee", ["test3@test.com", "test4@test.com"])
 
-    assert event_component == Event({'ATTENDEE': [
-            prop.vCalAddress('test@test.com'),
-            prop.vCalAddress('test2@test.com'),
-            prop.vCalAddress('maxm@mxm.dk'),
-            prop.vCalAddress('test@example.dk'),
-            prop.vCalAddress('test3@test.com'),
-            prop.vCalAddress('test4@test.com')
-        ]})
+    assert event_component == Event(
+        {
+            "ATTENDEE": [
+                prop.vCalAddress("test@test.com"),
+                prop.vCalAddress("test2@test.com"),
+                prop.vCalAddress("maxm@mxm.dk"),
+                prop.vCalAddress("test@example.dk"),
+                prop.vCalAddress("test3@test.com"),
+                prop.vCalAddress("test4@test.com"),
+            ]
+        }
+    )
 
 
 def test_get_content_directly(c):
     """You can get the values back directly ..."""
-    c.add('prodid', '-//my product//')
-    assert c['prodid'] == prop.vText('-//my product//')
+    c.add("prodid", "-//my product//")
+    assert c["prodid"] == prop.vText("-//my product//")
     # ... or decoded to a python type
-    assert c.decoded('prodid') == b'-//my product//'
+    assert c.decoded("prodid") == b"-//my product//"
 
 
 def test_get_default_value(c):
     """With default values for non existing properties"""
-    assert c.decoded('version', 'No Version') == 'No Version'
+    assert c.decoded("version", "No Version") == "No Version"
 
 
 def test_default_list_example(c):
-    c.add('rdate', [datetime(2013, 3, 28), datetime(2013, 3, 27)])
-    assert isinstance(c.decoded('rdate'), prop.vDDDLists)
+    c.add("rdate", [datetime(2013, 3, 28), datetime(2013, 3, 27)])
+    assert isinstance(c.decoded("rdate"), prop.vDDDLists)
 
 
 def test_render_component(calendar_component):
     """The component can render itself in the RFC 5545 format."""
-    calendar_component.add('attendee', 'Max M')
-    assert calendar_component.to_ical() == b'BEGIN:VCALENDAR\r\nATTENDEE:Max M\r\nEND:VCALENDAR\r\n'
+    calendar_component.add("attendee", "Max M")
+    assert (
+        calendar_component.to_ical()
+        == b"BEGIN:VCALENDAR\r\nATTENDEE:Max M\r\nEND:VCALENDAR\r\n"
+    )
 
 
 def test_nested_component_event_ics(filled_event_component):
     """Check the ical string of the event component."""
     assert filled_event_component.to_ical() == (
-        b'BEGIN:VEVENT\r\nDTEND:20000102T000000\r\n'
-        + b'DTSTART:20000101T000000\r\nSUMMARY:A brief history of time\r'
-        + b'\nEND:VEVENT\r\n'
+        b"BEGIN:VEVENT\r\nDTEND:20000102T000000\r\n"
+        + b"DTSTART:20000101T000000\r\nSUMMARY:A brief history of time\r"
+        + b"\nEND:VEVENT\r\n"
     )
 
 
@@ -98,58 +102,75 @@ def test_nested_components(calendar_comp
     holds events."""
     self.assertEqual(
         calendar_component.subcomponents,
-        [Event({'DTEND': '20000102T000000', 'DTSTART': '20000101T000000',
-                'SUMMARY': 'A brief history of time'})]
+        [
+            Event(
+                {
+                    "DTEND": "20000102T000000",
+                    "DTSTART": "20000101T000000",
+                    "SUMMARY": "A brief history of time",
+                }
+            )
+        ],
     )
 
 
 def test_walk_filled_calendar_component(calendar_component, filled_event_component):
     """We can walk over nested componentes with the walk method."""
-    assert [i.name for i in calendar_component.walk()] == ['VCALENDAR', 'VEVENT']
+    assert [i.name for i in calendar_component.walk()] == ["VCALENDAR", "VEVENT"]
 
 
 def test_filter_walk(calendar_component, filled_event_component):
     """We can also just walk over specific component types, by filtering
     them on their name."""
-    assert [i.name for i in calendar_component.walk('VEVENT')] == ['VEVENT']
-    assert [i['dtstart'] for i in calendar_component.walk('VEVENT')] == ['20000101T000000']
+    assert [i.name for i in calendar_component.walk("VEVENT")] == ["VEVENT"]
+    assert [i["dtstart"] for i in calendar_component.walk("VEVENT")] == [
+        "20000101T000000"
+    ]
 
 
 def test_recursive_property_items(calendar_component, filled_event_component):
     """We can enumerate property items recursively with the property_items
     method."""
-    calendar_component.add('attendee', 'Max M')
+    calendar_component.add("attendee", "Max M")
     assert calendar_component.property_items() == [
-         ('BEGIN', b'VCALENDAR'), ('ATTENDEE', prop.vCalAddress('Max M')),
-         ('BEGIN', b'VEVENT'), ('DTEND', '20000102T000000'),
-         ('DTSTART', '20000101T000000'),
-         ('SUMMARY', 'A brief history of time'), ('END', b'VEVENT'),
-         ('END', b'VCALENDAR')]
+        ("BEGIN", b"VCALENDAR"),
+        ("ATTENDEE", prop.vCalAddress("Max M")),
+        ("BEGIN", b"VEVENT"),
+        ("DTEND", "20000102T000000"),
+        ("DTSTART", "20000101T000000"),
+        ("SUMMARY", "A brief history of time"),
+        ("END", b"VEVENT"),
+        ("END", b"VCALENDAR"),
+    ]
 
 
 def test_flat_property_items(calendar_component, filled_event_component):
     """We can also enumerate property items just under the component."""
     assert calendar_component.property_items(recursive=False) == [
-         ('BEGIN', b'VCALENDAR'),
-         ('ATTENDEE', prop.vCalAddress('Max M')),
-         ('END', b'VCALENDAR')]
+        ("BEGIN", b"VCALENDAR"),
+        ("ATTENDEE", prop.vCalAddress("Max M")),
+        ("END", b"VCALENDAR"),
+    ]
 
 
 def test_flat_property_items(filled_event_component):
     """Flat enumeration on the event."""
     assert filled_event_component.property_items(recursive=False) == [
-         ('BEGIN', b'VEVENT'), ('DTEND', '20000102T000000'),
-         ('DTSTART', '20000101T000000'),
-         ('SUMMARY', 'A brief history of time'), ('END', b'VEVENT')]
+        ("BEGIN", b"VEVENT"),
+        ("DTEND", "20000102T000000"),
+        ("DTSTART", "20000101T000000"),
+        ("SUMMARY", "A brief history of time"),
+        ("END", b"VEVENT"),
+    ]
 
 
 def test_indent():
     """Text fields which span multiple mulitple lines require proper indenting"""
     c = Calendar()
-    c['description'] = 'Paragraph one\n\nParagraph two'
+    c["description"] = "Paragraph one\n\nParagraph two"
     assert c.to_ical() == (
-        b'BEGIN:VCALENDAR\r\nDESCRIPTION:Paragraph one\\n\\nParagraph two'
-        + b'\r\nEND:VCALENDAR\r\n'
+        b"BEGIN:VCALENDAR\r\nDESCRIPTION:Paragraph one\\n\\nParagraph two"
+        + b"\r\nEND:VCALENDAR\r\n"
     )
 
 
@@ -157,10 +178,12 @@ def test_INLINE_properties(calendar_with
     """INLINE properties have their values on one property line. Note the
     double quoting of the value with a colon in it.
     """
-    assert calendar_with_resources == Calendar({'RESOURCES': 'Chair, Table, "Room: 42"'})
+    assert calendar_with_resources == Calendar(
+        {"RESOURCES": 'Chair, Table, "Room: 42"'}
+    )
     assert calendar_with_resources.to_ical() == (
         b'BEGIN:VCALENDAR\r\nRESOURCES:Chair\\, Table\\, "Room: 42"\r\n'
-        + b'END:VCALENDAR\r\n'
+        + b"END:VCALENDAR\r\n"
     )
 
 
@@ -168,32 +191,48 @@ def test_get_inline(calendar_with_resour
     """The inline values must be handled by the get_inline() and
     set_inline() methods.
     """
-    assert calendar_with_resources.get_inline('resources', decode=0) == \
-        ['Chair', 'Table', 'Room: 42']
+    assert calendar_with_resources.get_inline("resources", decode=0) == [
+        "Chair",
+        "Table",
+        "Room: 42",
+    ]
 
 
 def test_get_inline_decoded(calendar_with_resources):
     """These can also be decoded"""
-    assert calendar_with_resources.get_inline('resources', decode=1) == \
-        [b'Chair', b'Table', b'Room: 42']
+    assert calendar_with_resources.get_inline("resources", decode=1) == [
+        b"Chair",
+        b"Table",
+        b"Room: 42",
+    ]
 
 
 def test_set_inline(calendar_with_resources):
     """You can set them directly ..."""
-    calendar_with_resources.set_inline('resources', ['A', 'List', 'of', 'some, recources'],
-                 encode=1)
-    assert calendar_with_resources['resources'] == 'A,List,of,"some, recources"'
-    assert calendar_with_resources.get_inline('resources', decode=0) == ['A', 'List', 'of', 'some, recources']
+    calendar_with_resources.set_inline(
+        "resources", ["A", "List", "of", "some, recources"], encode=1
+    )
+    assert calendar_with_resources["resources"] == 'A,List,of,"some, recources"'
+    assert calendar_with_resources.get_inline("resources", decode=0) == [
+        "A",
+        "List",
+        "of",
+        "some, recources",
+    ]
 
 
 def test_inline_free_busy_inline(c):
-    c['freebusy'] = '19970308T160000Z/PT3H,19970308T200000Z/PT1H,'\
-                    + '19970308T230000Z/19970309T000000Z'
-    assert c.get_inline('freebusy', decode=0) == \
-        ['19970308T160000Z/PT3H', '19970308T200000Z/PT1H',
-         '19970308T230000Z/19970309T000000Z']
+    c["freebusy"] = (
+        "19970308T160000Z/PT3H,19970308T200000Z/PT1H,"
+        + "19970308T230000Z/19970309T000000Z"
+    )
+    assert c.get_inline("freebusy", decode=0) == [
+        "19970308T160000Z/PT3H",
+        "19970308T200000Z/PT1H",
+        "19970308T230000Z/19970309T000000Z",
+    ]
 
-    freebusy = c.get_inline('freebusy', decode=1)
+    freebusy = c.get_inline("freebusy", decode=1)
     assert isinstance(freebusy[0][0], datetime)
     assert isinstance(freebusy[0][1], timedelta)
 
@@ -202,11 +241,10 @@ def test_cal_Component_add(comp, tzp):
     """Test the for timezone correctness: dtstart should preserve it's
     timezone, created, dtstamp and last-modified must be in UTC.
     """
-    comp.add('dtstart', tzp.localize(datetime(2010, 10, 10, 10, 0, 0), "Europe/Vienna"))
-    comp.add('created', datetime(2010, 10, 10, 12, 0, 0))
-    comp.add('dtstamp', tzp.localize(datetime(2010, 10, 10, 14, 0, 0), "Europe/Vienna"))
-    comp.add('last-modified', tzp.localize_utc(
-        datetime(2010, 10, 10, 16, 0, 0)))
+    comp.add("dtstart", tzp.localize(datetime(2010, 10, 10, 10, 0, 0), "Europe/Vienna"))
+    comp.add("created", datetime(2010, 10, 10, 12, 0, 0))
+    comp.add("dtstamp", tzp.localize(datetime(2010, 10, 10, 14, 0, 0), "Europe/Vienna"))
+    comp.add("last-modified", tzp.localize_utc(datetime(2010, 10, 10, 16, 0, 0)))
 
     lines = comp.to_ical().splitlines()
     assert b"DTSTART;TZID=Europe/Vienna:20101010T100000" in lines
@@ -216,22 +254,20 @@ def test_cal_Component_add(comp, tzp):
 
 
 def test_cal_Component_add_no_reencode(comp):
-    """Already encoded values should not be re-encoded.
-    """
-    comp.add('ATTACH', 'me')
-    comp.add('ATTACH', 'you', encode=False)
-    binary = prop.vBinary('us')
-    comp.add('ATTACH', binary)
+    """Already encoded values should not be re-encoded."""
+    comp.add("ATTACH", "me")
+    comp.add("ATTACH", "you", encode=False)
+    binary = prop.vBinary("us")
+    comp.add("ATTACH", binary)
 
-    assert comp['ATTACH'] == ['me', 'you', binary]
+    assert comp["ATTACH"] == ["me", "you", binary]
 
 
 def test_cal_Component_add_property_parameter(comp):
     """Test the for timezone correctness: dtstart should preserve it's
     timezone, crated, dtstamp and last-modified must be in UTC.
     """
-    comp.add('X-TEST-PROP', 'tryout.',
-             parameters={'prop1': 'val1', 'prop2': 'val2'})
+    comp.add("X-TEST-PROP", "tryout.", parameters={"prop1": "val1", "prop2": "val2"})
     lines = comp.to_ical().splitlines()
     assert b"X-TEST-PROP;PROP1=val1;PROP2=val2:tryout." in lines
 
@@ -239,20 +275,20 @@ def test_cal_Component_add_property_para
 comp_prop = pytest.mark.parametrize(
     "component_name, property_name",
     [
-        ('VEVENT', 'DTSTART'),
-        ('VEVENT', 'DTEND'),
-        ('VEVENT', 'RECURRENCE-ID'),
-        ('VTODO', 'DUE')
-    ]
+        ("VEVENT", "DTSTART"),
+        ("VEVENT", "DTEND"),
+        ("VEVENT", "RECURRENCE-ID"),
+        ("VTODO", "DUE"),
+    ],
 )
 
 
 @comp_prop
 def test_cal_Component_from_ical(component_name, property_name, tzp):
     """Check for proper handling of TZID parameter of datetime properties"""
-    component_str = 'BEGIN:' + component_name + '\n'
-    component_str += property_name + ';TZID=America/Denver:'
-    component_str += '20120404T073000\nEND:' + component_name
+    component_str = "BEGIN:" + component_name + "\n"
+    component_str += property_name + ";TZID=America/Denver:"
+    component_str += "20120404T073000\nEND:" + component_name
     component = Component.from_ical(component_str)
     assert tzid_from_dt(component[property_name].dt) == "America/Denver"
 
@@ -260,20 +296,22 @@ def test_cal_Component_from_ical(compone
 @comp_prop
 def test_cal_Component_from_ical_2(component_name, property_name, tzp):
     """Check for proper handling of TZID parameter of datetime properties"""
-    component_str = 'BEGIN:' + component_name + '\n'
-    component_str += property_name + ':'
-    component_str += '20120404T073000\nEND:' + component_name
+    component_str = "BEGIN:" + component_name + "\n"
+    component_str += property_name + ":"
+    component_str += "20120404T073000\nEND:" + component_name
     component = Component.from_ical(component_str)
     assert component[property_name].dt.tzinfo == None
 
 
 def test_cal_Component_to_ical_property_order():
-    component_str = [b'BEGIN:VEVENT',
-                     b'DTSTART:19970714T170000Z',
-                     b'DTEND:19970715T035959Z',
-                     b'SUMMARY:Bastille Day Party',
-                     b'END:VEVENT']
-    component = Component.from_ical(b'\r\n'.join(component_str))
+    component_str = [
+        b"BEGIN:VEVENT",
+        b"DTSTART:19970714T170000Z",
+        b"DTEND:19970715T035959Z",
+        b"SUMMARY:Bastille Day Party",
+        b"END:VEVENT",
+    ]
+    component = Component.from_ical(b"\r\n".join(component_str))
 
     sorted_str = component.to_ical().splitlines()
     assert sorted_str != component_str
@@ -284,39 +322,43 @@ def test_cal_Component_to_ical_property_
 
 
 def test_cal_Component_to_ical_parameter_order():
-    component_str = [b'BEGIN:VEVENT',
-                     b'X-FOOBAR;C=one;A=two;B=three:helloworld.',
-                     b'END:VEVENT']
-    component = Component.from_ical(b'\r\n'.join(component_str))
+    component_str = [
+        b"BEGIN:VEVENT",
+        b"X-FOOBAR;C=one;A=two;B=three:helloworld.",
+        b"END:VEVENT",
+    ]
+    component = Component.from_ical(b"\r\n".join(component_str))
 
     sorted_str = component.to_ical().splitlines()
     assert sorted_str[0] == component_str[0]
-    assert sorted_str[1] == b'X-FOOBAR;A=two;B=three;C=one:helloworld.'
+    assert sorted_str[1] == b"X-FOOBAR;A=two;B=three;C=one:helloworld."
     assert sorted_str[2] == component_str[2]
 
     preserved_str = component.to_ical(sorted=False).splitlines()
     assert preserved_str == component_str
 
 
-@pytest.fixture()
+@pytest.fixture
 def repr_example(c):
     class ReprExample:
         component = c
-        component['key1'] = 'value1'
+        component["key1"] = "value1"
         calendar = Calendar()
-        calendar['key1'] = 'value1'
+        calendar["key1"] = "value1"
         event = Event()
-        event['key1'] = 'value1'
-        nested = Component(key1='VALUE1')
+        event["key1"] = "value1"
+        nested = Component(key1="VALUE1")
         nested.add_component(component)
         nested.add_component(calendar)
+
     return ReprExample
 
+
 def test_repr_component(repr_example):
-    """Test correct class representation.
-    """
+    """Test correct class representation."""
     assert re.match(r"Component\({u?'KEY1': u?'value1'}\)", str(repr_example.component))
 
+
 def test_repr_calendar(repr_example):
     assert re.match(r"VCALENDAR\({u?'KEY1': u?'value1'}\)", str(repr_example.calendar))
 
@@ -330,24 +372,24 @@ def test_nested_components(repr_example)
     repr_example.calendar.add_component(repr_example.event)
     print(repr_example.nested)
     assert re.match(
-            r"Component\({u?'KEY1': u?'VALUE1'}, "
-            r"Component\({u?'KEY1': u?'value1'}\), "
-            r"VCALENDAR\({u?'KEY1': u?'value1'}, "
-            r"VEVENT\({u?'KEY1': u?'value1'}\)\)\)",
-            str(repr_example.nested)
-        )
+        r"Component\({u?'KEY1': u?'VALUE1'}, "
+        r"Component\({u?'KEY1': u?'value1'}\), "
+        r"VCALENDAR\({u?'KEY1': u?'value1'}, "
+        r"VEVENT\({u?'KEY1': u?'value1'}\)\)\)",
+        str(repr_example.nested),
+    )
 
 
 def test_component_factory_VEVENT(factory):
     """Check the events in the component factory"""
-    component = factory['VEVENT']
-    event = component(dtstart='19700101')
-    assert event.to_ical() == b'BEGIN:VEVENT\r\nDTSTART:19700101\r\nEND:VEVENT\r\n'
+    component = factory["VEVENT"]
+    event = component(dtstart="19700101")
+    assert event.to_ical() == b"BEGIN:VEVENT\r\nDTSTART:19700101\r\nEND:VEVENT\r\n"
 
 
 def test_component_factory_VCALENDAR(factory):
     """Check the VCALENDAR in the factory."""
-    assert factory.get('VCALENDAR') == icalendar.cal.Calendar
+    assert factory.get("VCALENDAR") == icalendar.cal.Calendar
 
 
 def test_minimal_calendar_component_with_one_event():
@@ -355,19 +397,21 @@ def test_minimal_calendar_component_with
     cal = Calendar()
 
     # Some properties are required to be compliant
-    cal['prodid'] = '-//My calendar product//mxm.dk//'
-    cal['version'] = '2.0'
+    cal["prodid"] = "-//My calendar product//mxm.dk//"
+    cal["version"] = "2.0"
 
     # We also need at least one subcomponent for a calendar to be compliant
     event = Event()
-    event['summary'] = 'Python meeting about calendaring'
-    event['uid'] = '42'
-    event.add('dtstart', datetime(2005, 4, 4, 8, 0, 0))
+    event["summary"] = "Python meeting about calendaring"
+    event["uid"] = "42"
+    event.add("dtstart", datetime(2005, 4, 4, 8, 0, 0))
     cal.add_component(event)
-    assert cal.subcomponents[0].to_ical() == \
-        b'BEGIN:VEVENT\r\nSUMMARY:Python meeting about calendaring\r\n' \
-        + b'DTSTART:20050404T080000\r\nUID:42\r\n' \
-        + b'END:VEVENT\r\n'
+    assert (
+        cal.subcomponents[0].to_ical()
+        == b"BEGIN:VEVENT\r\nSUMMARY:Python meeting about calendaring\r\n"
+        + b"DTSTART:20050404T080000\r\nUID:42\r\n"
+        + b"END:VEVENT\r\n"
+    )
 
 
 def test_calendar_with_parsing_errors_includes_all_events(calendars):
@@ -376,8 +420,10 @@ def test_calendar_with_parsing_errors_in
     attribute. The error in the following is the third EXDATE: it has an
     empty DATE.
     """
-    event_descriptions = [e['DESCRIPTION'].to_ical() for e in calendars.parsing_error.walk('VEVENT')]
-    assert event_descriptions == [b'Perfectly OK event', b'Wrong event']
+    event_descriptions = [
+        e["DESCRIPTION"].to_ical() for e in calendars.parsing_error.walk("VEVENT")
+    ]
+    assert event_descriptions == [b"Perfectly OK event", b"Wrong event"]
 
 
 def test_calendar_with_parsing_errors_has_an_error_in_one_event(calendars):
@@ -386,8 +432,8 @@ def test_calendar_with_parsing_errors_ha
     attribute. The error in the following is the third EXDATE: it has an
     empty DATE.
     """
-    errors = [e.errors for e in calendars.parsing_error.walk('VEVENT')]
-    assert errors == [[], [('EXDATE', "Expected datetime, date, or time, got: ''")]]
+    errors = [e.errors for e in calendars.parsing_error.walk("VEVENT")]
+    assert errors == [[], [("EXDATE", "Expected datetime, date, or time, got: ''")]]
 
 
 def test_cal_strict_parsing(calendars):
@@ -398,21 +444,26 @@ def test_cal_strict_parsing(calendars):
 
 def test_cal_ignore_errors_parsing(calendars, vUTCOffset_ignore_exceptions):
     """If we diable the errors, we should be able to put the calendar back together."""
-    assert calendars.parsing_error_in_UTC_offset.to_ical() == calendars.parsing_error_in_UTC_offset.raw_ics
-
+    assert (
+        calendars.parsing_error_in_UTC_offset.to_ical()
+        == calendars.parsing_error_in_UTC_offset.raw_ics
+    )
 
 
 @pytest.mark.parametrize(
-    'calendar, other_calendar',
-    itertools.product([
-        'issue_156_RDATE_with_PERIOD_TZID_khal',
-        'issue_156_RDATE_with_PERIOD_TZID_khal_2',
-        'issue_178_custom_component_contains_other',
-        'issue_178_custom_component_inside_other',
-        'issue_526_calendar_with_events',
-        'issue_526_calendar_with_different_events',
-        'issue_526_calendar_with_event_subset',
-    ], repeat=2)
+    ("calendar", "other_calendar"),
+    itertools.product(
+        [
+            "issue_156_RDATE_with_PERIOD_TZID_khal",
+            "issue_156_RDATE_with_PERIOD_TZID_khal_2",
+            "issue_178_custom_component_contains_other",
+            "issue_178_custom_component_inside_other",
+            "issue_526_calendar_with_events",
+            "issue_526_calendar_with_different_events",
+            "issue_526_calendar_with_event_subset",
+        ],
+        repeat=2,
+    ),
 )
 def test_comparing_calendars(calendars, calendar, other_calendar, tzp):
     are_calendars_equal = calendars[calendar] == calendars[other_calendar]
@@ -420,12 +471,19 @@ def test_comparing_calendars(calendars,
     assert are_calendars_equal == are_calendars_actually_equal
 
 
-@pytest.mark.parametrize('calendar, shuffeled_calendar', [
-    (
-        'issue_526_calendar_with_events',
-        'issue_526_calendar_with_shuffeled_events',
-    ),
-])
-def test_calendars_with_same_subcomponents_in_different_order_are_equal(calendars, calendar, shuffeled_calendar):
-    assert not calendars[calendar].subcomponents == calendars[shuffeled_calendar].subcomponents
+@pytest.mark.parametrize(
+    ("calendar", "shuffeled_calendar"),
+    [
+        (
+            "issue_526_calendar_with_events",
+            "issue_526_calendar_with_shuffeled_events",
+        ),
+    ],
+)
+def test_calendars_with_same_subcomponents_in_different_order_are_equal(
+    calendars, calendar, shuffeled_calendar
+):
+    assert (
+        calendars[calendar].subcomponents != calendars[shuffeled_calendar].subcomponents
+    )
     assert calendars[calendar] == calendars[shuffeled_calendar]
diff -pruN 6.0.1-3/src/icalendar/tests/test_unit_caselessdict.py 6.3.1-1/src/icalendar/tests/test_unit_caselessdict.py
--- 6.0.1-3/src/icalendar/tests/test_unit_caselessdict.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/test_unit_caselessdict.py	2025-05-20 07:31:39.000000000 +0000
@@ -4,64 +4,93 @@ import icalendar
 
 
 class TestCaselessdict(unittest.TestCase):
-
     def test_caselessdict_canonsort_keys(self):
         canonsort_keys = icalendar.caselessdict.canonsort_keys
 
-        keys = ['DTEND', 'DTSTAMP', 'DTSTART', 'UID', 'SUMMARY', 'LOCATION']
+        keys = ["DTEND", "DTSTAMP", "DTSTART", "UID", "SUMMARY", "LOCATION"]
 
         out = canonsort_keys(keys)
         self.assertEqual(
-            out,
-            ['DTEND', 'DTSTAMP', 'DTSTART', 'LOCATION', 'SUMMARY', 'UID']
+            out, ["DTEND", "DTSTAMP", "DTSTART", "LOCATION", "SUMMARY", "UID"]
         )
 
-        out = canonsort_keys(keys, ('SUMMARY', 'DTSTART', 'DTEND', ))
-        self.assertEqual(
-            out,
-            ['SUMMARY', 'DTSTART', 'DTEND', 'DTSTAMP', 'LOCATION', 'UID']
+        out = canonsort_keys(
+            keys,
+            (
+                "SUMMARY",
+                "DTSTART",
+                "DTEND",
+            ),
         )
-
-        out = canonsort_keys(keys, ('UID', 'DTSTART', 'DTEND', ))
         self.assertEqual(
-            out,
-            ['UID', 'DTSTART', 'DTEND', 'DTSTAMP', 'LOCATION', 'SUMMARY']
+            out, ["SUMMARY", "DTSTART", "DTEND", "DTSTAMP", "LOCATION", "UID"]
         )
 
         out = canonsort_keys(
             keys,
-            ('UID', 'DTSTART', 'DTEND', 'RRULE', 'EXDATE')
+            (
+                "UID",
+                "DTSTART",
+                "DTEND",
+            ),
         )
         self.assertEqual(
-            out,
-            ['UID', 'DTSTART', 'DTEND', 'DTSTAMP', 'LOCATION', 'SUMMARY']
+            out, ["UID", "DTSTART", "DTEND", "DTSTAMP", "LOCATION", "SUMMARY"]
+        )
+
+        out = canonsort_keys(keys, ("UID", "DTSTART", "DTEND", "RRULE", "EXDATE"))
+        self.assertEqual(
+            out, ["UID", "DTSTART", "DTEND", "DTSTAMP", "LOCATION", "SUMMARY"]
         )
 
     def test_caselessdict_canonsort_items(self):
         canonsort_items = icalendar.caselessdict.canonsort_items
 
         d = {
-            'i': 7, 'c': 'at', 'a': 3.5, 'l': (2, 3), 'e': [4, 5], 'n': 13, 'd': {'x': 'y'}, 'r': 1.0,
+            "i": 7,
+            "c": "at",
+            "a": 3.5,
+            "l": (2, 3),
+            "e": [4, 5],
+            "n": 13,
+            "d": {"x": "y"},
+            "r": 1.0,
         }
 
         out = canonsort_items(d)
         self.assertEqual(
             out,
-            [('a', 3.5), ('c', 'at'), ('d', {'x': 'y'}), ('e', [4, 5]),
-             ('i', 7), ('l', (2, 3)), ('n', 13), ('r', 1.0)]
+            [
+                ("a", 3.5),
+                ("c", "at"),
+                ("d", {"x": "y"}),
+                ("e", [4, 5]),
+                ("i", 7),
+                ("l", (2, 3)),
+                ("n", 13),
+                ("r", 1.0),
+            ],
         )
 
-        out = canonsort_items(d, ('i', 'c', 'a'))
+        out = canonsort_items(d, ("i", "c", "a"))
         self.assertTrue(
             out,
-            [('i', 7), ('c', 'at'), ('a', 3.5), ('d', {'x': 'y'}),
-             ('e', [4, 5]), ('l', (2, 3)), ('n', 13), ('r', 1.0)]
+            [
+                ("i", 7),
+                ("c", "at"),
+                ("a", 3.5),
+                ("d", {"x": "y"}),
+                ("e", [4, 5]),
+                ("l", (2, 3)),
+                ("n", 13),
+                ("r", 1.0),
+            ],
         )
 
     def test_caselessdict_copy(self):
         CaselessDict = icalendar.caselessdict.CaselessDict
 
-        original_dict = CaselessDict(key1='val1', key2='val2')
+        original_dict = CaselessDict(key1="val1", key2="val2")
         copied_dict = original_dict.copy()
 
         self.assertEqual(original_dict, copied_dict)
@@ -69,31 +98,30 @@ class TestCaselessdict(unittest.TestCase
     def test_CaselessDict(self):
         CaselessDict = icalendar.caselessdict.CaselessDict
 
-        ncd = CaselessDict(key1='val1', key2='val2')
-        self.assertEqual(
-            ncd,
-            CaselessDict({'KEY2': 'val2', 'KEY1': 'val1'})
-        )
+        ncd = CaselessDict(key1="val1", key2="val2")
+        self.assertEqual(ncd, CaselessDict({"KEY2": "val2", "KEY1": "val1"}))
 
-        self.assertEqual(ncd['key1'], 'val1')
-        self.assertEqual(ncd['KEY1'], 'val1')
+        self.assertEqual(ncd["key1"], "val1")
+        self.assertEqual(ncd["KEY1"], "val1")
 
-        ncd['KEY3'] = 'val3'
-        self.assertEqual(ncd['key3'], 'val3')
+        assert ncd.has_key("key1")
 
-        self.assertEqual(ncd.setdefault('key3', 'FOUND'), 'val3')
-        self.assertEqual(ncd.setdefault('key4', 'NOT FOUND'), 'NOT FOUND')
-        self.assertEqual(ncd['key4'], 'NOT FOUND')
-        self.assertEqual(ncd.get('key1'), 'val1')
-        self.assertEqual(ncd.get('key3', 'NOT FOUND'), 'val3')
-        self.assertEqual(ncd.get('key4', 'NOT FOUND'), 'NOT FOUND')
-        self.assertTrue('key4' in ncd)
+        ncd["KEY3"] = "val3"
+        self.assertEqual(ncd["key3"], "val3")
+
+        self.assertEqual(ncd.setdefault("key3", "FOUND"), "val3")
+        self.assertEqual(ncd.setdefault("key4", "NOT FOUND"), "NOT FOUND")
+        self.assertEqual(ncd["key4"], "NOT FOUND")
+        self.assertEqual(ncd.get("key1"), "val1")
+        self.assertEqual(ncd.get("key3", "NOT FOUND"), "val3")
+        self.assertEqual(ncd.get("key4", "NOT FOUND"), "NOT FOUND")
+        self.assertIn("key4", ncd)
 
-        del ncd['key4']
-        self.assertFalse('key4' in ncd)
+        del ncd["key4"]
+        self.assertNotIn("key4", ncd)
 
-        ncd.update({'key5': 'val5', 'KEY6': 'val6', 'KEY5': 'val7'})
-        self.assertEqual(ncd['key6'], 'val6')
+        ncd.update({"key5": "val5", "KEY6": "val6", "KEY5": "val7"})
+        self.assertEqual(ncd["key6"], "val6")
 
         keys = sorted(ncd.keys())
-        self.assertEqual(keys, ['KEY1', 'KEY2', 'KEY3', 'KEY5', 'KEY6'])
+        self.assertEqual(keys, ["KEY1", "KEY2", "KEY3", "KEY5", "KEY6"])
diff -pruN 6.0.1-3/src/icalendar/tests/test_unit_parser_tools.py 6.3.1-1/src/icalendar/tests/test_unit_parser_tools.py
--- 6.0.1-3/src/icalendar/tests/test_unit_parser_tools.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/test_unit_parser_tools.py	2025-05-20 07:31:39.000000000 +0000
@@ -1,28 +1,33 @@
-from icalendar.parser_tools import data_encode
-from icalendar.parser_tools import to_unicode
 import unittest
 
+from icalendar.parser_tools import data_encode, to_unicode, from_unicode
 
-class TestParserTools(unittest.TestCase):
 
+class TestParserTools(unittest.TestCase):
     def test_parser_tools_to_unicode(self):
-
-        self.assertEqual(to_unicode(b'spam'), 'spam')
-        self.assertEqual(to_unicode('spam'), 'spam')
-        self.assertEqual(to_unicode(b'spam'), 'spam')
-        self.assertEqual(to_unicode(b'\xc6\xb5'), '\u01b5')
-        self.assertEqual(to_unicode(b'\xc6\xb5'),
-                         '\u01b5')
-        self.assertEqual(to_unicode(b'\xc6\xb5', encoding='ascii'), '\u01b5')
+        self.assertEqual(to_unicode(b"spam"), "spam")
+        self.assertEqual(to_unicode("spam"), "spam")
+        self.assertEqual(to_unicode(b"spam"), "spam")
+        self.assertEqual(to_unicode(b"\xc6\xb5"), "\u01b5")
+        self.assertEqual(to_unicode(b"\xc6\xb5"), "\u01b5")
+        self.assertEqual(to_unicode(b"\xc6\xb5", encoding="ascii"), "\u01b5")
         self.assertEqual(to_unicode(1), 1)
-        self.assertEqual(to_unicode(None), None)
+        self.assertIsNone(to_unicode(None))
 
-    def test_parser_tools_data_encode(self):
+    def test_parser_tools_from_unicode(self):
+        self.assertEqual(from_unicode("\u01b5", encoding="ascii"), b"\xc6\xb5")
 
+    def test_parser_tools_data_encode(self):
         data1 = {
-            'k1': 'v1', 'k2': 'v2', 'k3': 'v3',
-            'li1': ['it1', 'it2', {'k4': 'v4', 'k5': 'v5'}, 123]
+            "k1": "v1",
+            "k2": "v2",
+            "k3": "v3",
+            "li1": ["it1", "it2", {"k4": "v4", "k5": "v5"}, 123],
+        }
+        res = {
+            b"k3": b"v3",
+            b"k2": b"v2",
+            b"k1": b"v1",
+            b"li1": [b"it1", b"it2", {b"k5": b"v5", b"k4": b"v4"}, 123],
         }
-        res = {b'k3': b'v3', b'k2': b'v2', b'k1': b'v1',
-               b'li1': [b'it1', b'it2', {b'k5': b'v5', b'k4': b'v4'}, 123]}
         self.assertEqual(data_encode(data1), res)
diff -pruN 6.0.1-3/src/icalendar/tests/test_unit_tools.py 6.3.1-1/src/icalendar/tests/test_unit_tools.py
--- 6.0.1-3/src/icalendar/tests/test_unit_tools.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/test_unit_tools.py	2025-05-20 07:31:39.000000000 +0000
@@ -1,54 +1,88 @@
-import pytest
 import unittest
 
+import pytest
+
 from icalendar.tools import UIDGenerator
 
-class TestTools(unittest.TestCase):
 
+class TestTools(unittest.TestCase):
     def test_tools_UIDGenerator(self):
-
         # Automatic semi-random uid
         g = UIDGenerator()
         uid = g.uid()
 
         txt = uid.to_ical()
         length = 15 + 1 + 16 + 1 + 11
-        self.assertTrue(len(txt) == length)
-        self.assertTrue(b'@example.com' in txt)
+        self.assertEqual(len(txt), length)
+        self.assertIn(b"@example.com", txt)
 
         # You should at least insert your own hostname to be more compliant
-        uid = g.uid('Example.ORG')
+        uid = g.uid("Example.ORG")
         txt = uid.to_ical()
-        self.assertTrue(len(txt) == length)
-        self.assertTrue(b'@Example.ORG' in txt)
+        self.assertEqual(len(txt), length)
+        self.assertIn(b"@Example.ORG", txt)
 
         # You can also insert a path or similar
-        uid = g.uid('Example.ORG', '/path/to/content')
+        uid = g.uid("Example.ORG", "/path/to/content")
         txt = uid.to_ical()
-        self.assertTrue(len(txt) == length)
-        self.assertTrue(b'-/path/to/content@Example.ORG' in txt)
-
+        self.assertEqual(len(txt), length)
+        self.assertIn(b"-/path/to/content@Example.ORG", txt)
 
-@pytest.mark.parametrize('split,expected,args,kw', [
-    # default argument host_name
-    ("@", "example.com", (), {},),
-    ("@", "example.com", ("example.com",), {}),
-    ("@", "example.com", (), {"host_name":"example.com"}),
-    # replaced host_name
-    ("@", "test.test", ("test.test",), {}),
-    ("@", "test.test", (), {"host_name":"test.test"}),
-    # replace unique
-    ("-", "123@example.com", (), {"unique": "123"},),
-    ("-", "abc@example.com", (), {"unique": "abc"},),
-    # replace host_name and unique
-    ("-", "1234@test.icalendar", (), {"unique": "1234", "host_name":"test.icalendar"},),
-    ("-", "abc@test.example.com", ("test.example.com", "abc"), {},),
 
-])
+@pytest.mark.parametrize(
+    ("split", "expected", "args", "kw"),
+    [
+        # default argument host_name
+        (
+            "@",
+            "example.com",
+            (),
+            {},
+        ),
+        ("@", "example.com", ("example.com",), {}),
+        ("@", "example.com", (), {"host_name": "example.com"}),
+        # replaced host_name
+        ("@", "test.test", ("test.test",), {}),
+        ("@", "test.test", (), {"host_name": "test.test"}),
+        # replace unique
+        (
+            "-",
+            "123@example.com",
+            (),
+            {"unique": "123"},
+        ),
+        (
+            "-",
+            "abc@example.com",
+            (),
+            {"unique": "abc"},
+        ),
+        # replace host_name and unique
+        (
+            "-",
+            "1234@test.icalendar",
+            (),
+            {"unique": "1234", "host_name": "test.icalendar"},
+        ),
+        (
+            "-",
+            "abc@test.example.com",
+            ("test.example.com", "abc"),
+            {},
+        ),
+    ],
+)
 def test_uid_generator_issue_345(args, kw, split, expected):
-    '''Issue #345 - Why is tools.UIDGenerator a class (that must be instantiated) instead of a module?
+    """Issue #345 - Why is tools.UIDGenerator a class (that must be instantiated) instead of a module?
 
     see https://github.com/collective/icalendar/issues/345
-    '''
+    """
     uid = UIDGenerator.uid(*args, **kw)
     assert uid.split(split)[1] == expected
+
+
+def test_warning():
+    with pytest.warns(DeprecationWarning):
+        UIDGenerator.uid()
+    with pytest.warns(DeprecationWarning):
+        UIDGenerator.rnd_string()
diff -pruN 6.0.1-3/src/icalendar/tests/test_with_doctest.py 6.3.1-1/src/icalendar/tests/test_with_doctest.py
--- 6.0.1-3/src/icalendar/tests/test_with_doctest.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/test_with_doctest.py	2025-05-20 07:31:39.000000000 +0000
@@ -10,12 +10,13 @@ This file should be tests, too:
     Hello World!
 
 """
+
 import doctest
-import os
-import pytest
 import importlib
+import os
 import sys
-import re
+
+import pytest
 
 HERE = os.path.dirname(__file__) or "."
 ICALENDAR_PATH = os.path.dirname(HERE)
@@ -23,17 +24,21 @@ ICALENDAR_PATH = os.path.dirname(HERE)
 PYTHON_FILES = [
     "/".join((dirpath, filename))
     for dirpath, dirnames, filenames in os.walk(ICALENDAR_PATH)
-    for filename in filenames if filename.lower().endswith(".py") and 'fuzzing' not in dirpath
+    for filename in filenames
+    if filename.lower().endswith(".py") and "fuzzing" not in dirpath
 ]
 
 MODULE_NAMES = [
-    "icalendar" + python_file[len(ICALENDAR_PATH):-3].replace("\\", "/").replace("/", ".")
+    "icalendar"
+    + python_file[len(ICALENDAR_PATH) : -3].replace("\\", "/").replace("/", ".")
     for python_file in PYTHON_FILES
 ]
 
+
 def test_this_module_is_among_them():
     assert __name__ in MODULE_NAMES
 
+
 @pytest.mark.parametrize("module_name", MODULE_NAMES)
 def test_docstring_of_python_file(module_name, env_for_doctest):
     """This test runs doctest on the Python module."""
@@ -58,12 +63,18 @@ try:
         if filename.lower().endswith(".rst")
     ]
 except FileNotFoundError:
-    raise OSError("Could not find the documentation - remove the build folder and try again.")
+    raise OSError(
+        "Could not find the documentation - remove the build folder and try again."
+    )
 
-@pytest.mark.parametrize("filename", [
-    "README.rst",
-    "index.rst",
-])
+
+@pytest.mark.parametrize(
+    "filename",
+    [
+        "README.rst",
+        "index.rst",
+    ],
+)
 def test_files_is_included(filename):
     assert any(path.endswith(filename) for path in DOCUMENT_PATHS)
 
@@ -75,15 +86,19 @@ def test_documentation_file(document, zo
     functions are also replaced to work.
     """
     try:
+        import pytz
+    except ImportError:
+        pytest.skip("pytz not installed, skipping this file.")
+    try:
         # set raise_on_error to False if you wand to see the error for debug
-        test_result = doctest.testfile(document, module_relative=False, globs=env_for_doctest, raise_on_error=True)
-    except doctest.UnexpectedException as e:
-        ty, err, tb = e.exc_info
-        if issubclass(ty, ModuleNotFoundError) and err.name == "pytz":
-            pytest.skip("pytz not installed, skipping this file.")
+        test_result = doctest.testfile(
+            document, module_relative=False, globs=env_for_doctest, raise_on_error=False
+        )
     finally:
         tzp.use_zoneinfo()
-    assert test_result.failed == 0, f"{test_result.failed} errors in {os.path.basename(document)}"
+    assert (
+        test_result.failed == 0
+    ), f"{test_result.failed} errors in {os.path.basename(document)}"
 
 
 def test_can_import_zoneinfo(env_for_doctest):
diff -pruN 6.0.1-3/src/icalendar/tests/timezone_ids.py 6.3.1-1/src/icalendar/tests/timezone_ids.py
--- 6.0.1-3/src/icalendar/tests/timezone_ids.py	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/tests/timezone_ids.py	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,599 @@
+"""This file contains all the timezone ids that should be tested."""
+
+TZIDS = [
+    "Africa/Abidjan",
+    "Africa/Accra",
+    "Africa/Addis_Ababa",
+    "Africa/Algiers",
+    "Africa/Asmara",
+    "Africa/Asmera",
+    "Africa/Bamako",
+    "Africa/Bangui",
+    "Africa/Banjul",
+    "Africa/Bissau",
+    "Africa/Blantyre",
+    "Africa/Brazzaville",
+    "Africa/Bujumbura",
+    "Africa/Cairo",
+    "Africa/Casablanca",
+    "Africa/Ceuta",
+    "Africa/Conakry",
+    "Africa/Dakar",
+    "Africa/Dar_es_Salaam",
+    "Africa/Djibouti",
+    "Africa/Douala",
+    "Africa/El_Aaiun",
+    "Africa/Freetown",
+    "Africa/Gaborone",
+    "Africa/Harare",
+    "Africa/Johannesburg",
+    "Africa/Juba",
+    "Africa/Kampala",
+    "Africa/Khartoum",
+    "Africa/Kigali",
+    "Africa/Kinshasa",
+    "Africa/Lagos",
+    "Africa/Libreville",
+    "Africa/Lome",
+    "Africa/Luanda",
+    "Africa/Lubumbashi",
+    "Africa/Lusaka",
+    "Africa/Malabo",
+    "Africa/Maputo",
+    "Africa/Maseru",
+    "Africa/Mbabane",
+    "Africa/Mogadishu",
+    "Africa/Monrovia",
+    "Africa/Nairobi",
+    "Africa/Ndjamena",
+    "Africa/Niamey",
+    "Africa/Nouakchott",
+    "Africa/Ouagadougou",
+    "Africa/Porto-Novo",
+    "Africa/Sao_Tome",
+    "Africa/Timbuktu",
+    "Africa/Tripoli",
+    "Africa/Tunis",
+    "Africa/Windhoek",
+    "America/Adak",
+    "America/Anchorage",
+    "America/Anguilla",
+    "America/Antigua",
+    "America/Araguaina",
+    "America/Argentina/Buenos_Aires",
+    "America/Argentina/Catamarca",
+    "America/Argentina/ComodRivadavia",
+    "America/Argentina/Cordoba",
+    "America/Argentina/Jujuy",
+    "America/Argentina/La_Rioja",
+    "America/Argentina/Mendoza",
+    "America/Argentina/Rio_Gallegos",
+    "America/Argentina/Salta",
+    "America/Argentina/San_Juan",
+    "America/Argentina/San_Luis",
+    "America/Argentina/Tucuman",
+    "America/Argentina/Ushuaia",
+    "America/Aruba",
+    "America/Asuncion",
+    "America/Atikokan",
+    "America/Atka",
+    "America/Bahia",
+    "America/Bahia_Banderas",
+    "America/Barbados",
+    "America/Belem",
+    "America/Belize",
+    "America/Blanc-Sablon",
+    "America/Boa_Vista",
+    "America/Bogota",
+    "America/Boise",
+    "America/Buenos_Aires",
+    "America/Cambridge_Bay",
+    "America/Campo_Grande",
+    "America/Cancun",
+    "America/Caracas",
+    "America/Catamarca",
+    "America/Cayenne",
+    "America/Cayman",
+    "America/Chicago",
+    "America/Chihuahua",
+    "America/Ciudad_Juarez",
+    "America/Coral_Harbour",
+    "America/Cordoba",
+    "America/Costa_Rica",
+    "America/Creston",
+    "America/Cuiaba",
+    "America/Curacao",
+    "America/Danmarkshavn",
+    "America/Dawson",
+    "America/Dawson_Creek",
+    "America/Denver",
+    "America/Detroit",
+    "America/Dominica",
+    "America/Edmonton",
+    "America/Eirunepe",
+    "America/El_Salvador",
+    "America/Ensenada",
+    "America/Fortaleza",
+    "America/Fort_Nelson",
+    "America/Fort_Wayne",
+    "America/Glace_Bay",
+    "America/Godthab",
+    "America/Goose_Bay",
+    "America/Grand_Turk",
+    "America/Grenada",
+    "America/Guadeloupe",
+    "America/Guatemala",
+    "America/Guayaquil",
+    "America/Guyana",
+    "America/Halifax",
+    "America/Havana",
+    "America/Hermosillo",
+    "America/Indiana/Indianapolis",
+    "America/Indiana/Knox",
+    "America/Indiana/Marengo",
+    "America/Indiana/Petersburg",
+    "America/Indianapolis",
+    "America/Indiana/Tell_City",
+    "America/Indiana/Vevay",
+    "America/Indiana/Vincennes",
+    "America/Indiana/Winamac",
+    "America/Inuvik",
+    "America/Iqaluit",
+    "America/Jamaica",
+    "America/Jujuy",
+    "America/Juneau",
+    "America/Kentucky/Louisville",
+    "America/Kentucky/Monticello",
+    "America/Knox_IN",
+    "America/Kralendijk",
+    "America/La_Paz",
+    "America/Lima",
+    "America/Los_Angeles",
+    "America/Louisville",
+    "America/Lower_Princes",
+    "America/Maceio",
+    "America/Managua",
+    "America/Manaus",
+    "America/Marigot",
+    "America/Martinique",
+    "America/Matamoros",
+    "America/Mazatlan",
+    "America/Mendoza",
+    "America/Menominee",
+    "America/Metlakatla",
+    "America/Mexico_City",
+    "America/Miquelon",
+    "America/Moncton",
+    "America/Monterrey",
+    "America/Montevideo",
+    "America/Montreal",
+    "America/Montserrat",
+    "America/Nassau",
+    "America/New_York",
+    "America/Nipigon",
+    "America/Nome",
+    "America/Noronha",
+    "America/North_Dakota/Beulah",
+    "America/North_Dakota/Center",
+    "America/North_Dakota/New_Salem",
+    "America/Nuuk",
+    "America/Ojinaga",
+    "America/Panama",
+    "America/Pangnirtung",
+    "America/Paramaribo",
+    "America/Phoenix",
+    "America/Port-au-Prince",
+    "America/Porto_Acre",
+    "America/Port_of_Spain",
+    "America/Porto_Velho",
+    "America/Puerto_Rico",
+    "America/Punta_Arenas",
+    "America/Rainy_River",
+    "America/Rankin_Inlet",
+    "America/Recife",
+    "America/Regina",
+    "America/Resolute",
+    "America/Rio_Branco",
+    "America/Rosario",
+    "America/Santa_Isabel",
+    "America/Santarem",
+    "America/Santiago",
+    "America/Santo_Domingo",
+    "America/Sao_Paulo",
+    "America/Scoresbysund",
+    "America/Shiprock",
+    "America/Sitka",
+    "America/St_Barthelemy",
+    "America/St_Johns",
+    "America/St_Kitts",
+    "America/St_Lucia",
+    "America/St_Thomas",
+    "America/St_Vincent",
+    "America/Swift_Current",
+    "America/Tegucigalpa",
+    "America/Thule",
+    "America/Thunder_Bay",
+    "America/Tijuana",
+    "America/Toronto",
+    "America/Tortola",
+    "America/Vancouver",
+    "America/Virgin",
+    "America/Whitehorse",
+    "America/Winnipeg",
+    "America/Yakutat",
+    "America/Yellowknife",
+    "Antarctica/Casey",
+    "Antarctica/Davis",
+    "Antarctica/DumontDUrville",
+    "Antarctica/Macquarie",
+    "Antarctica/Mawson",
+    "Antarctica/McMurdo",
+    "Antarctica/Palmer",
+    "Antarctica/Rothera",
+    "Antarctica/South_Pole",
+    "Antarctica/Syowa",
+    "Antarctica/Troll",
+    "Antarctica/Vostok",
+    "Arctic/Longyearbyen",
+    "Asia/Aden",
+    "Asia/Almaty",
+    "Asia/Amman",
+    "Asia/Anadyr",
+    "Asia/Aqtau",
+    "Asia/Aqtobe",
+    "Asia/Ashgabat",
+    "Asia/Ashkhabad",
+    "Asia/Atyrau",
+    "Asia/Baghdad",
+    "Asia/Bahrain",
+    "Asia/Baku",
+    "Asia/Bangkok",
+    "Asia/Barnaul",
+    "Asia/Beirut",
+    "Asia/Bishkek",
+    "Asia/Brunei",
+    "Asia/Calcutta",
+    "Asia/Chita",
+    "Asia/Choibalsan",
+    "Asia/Chongqing",
+    "Asia/Chungking",
+    "Asia/Colombo",
+    "Asia/Dacca",
+    "Asia/Damascus",
+    "Asia/Dhaka",
+    "Asia/Dili",
+    "Asia/Dubai",
+    "Asia/Dushanbe",
+    "Asia/Famagusta",
+    "Asia/Gaza",
+    "Asia/Harbin",
+    "Asia/Hebron",
+    "Asia/Ho_Chi_Minh",
+    "Asia/Hong_Kong",
+    "Asia/Hovd",
+    "Asia/Irkutsk",
+    "Asia/Istanbul",
+    "Asia/Jakarta",
+    "Asia/Jayapura",
+    "Asia/Jerusalem",
+    "Asia/Kabul",
+    "Asia/Kamchatka",
+    "Asia/Karachi",
+    "Asia/Kashgar",
+    "Asia/Kathmandu",
+    "Asia/Katmandu",
+    "Asia/Khandyga",
+    "Asia/Kolkata",
+    "Asia/Krasnoyarsk",
+    "Asia/Kuala_Lumpur",
+    "Asia/Kuching",
+    "Asia/Kuwait",
+    "Asia/Macao",
+    "Asia/Macau",
+    "Asia/Magadan",
+    "Asia/Makassar",
+    "Asia/Manila",
+    "Asia/Muscat",
+    "Asia/Nicosia",
+    "Asia/Novokuznetsk",
+    "Asia/Novosibirsk",
+    "Asia/Omsk",
+    "Asia/Oral",
+    "Asia/Phnom_Penh",
+    "Asia/Pontianak",
+    "Asia/Pyongyang",
+    "Asia/Qatar",
+    "Asia/Qostanay",
+    "Asia/Qyzylorda",
+    "Asia/Rangoon",
+    "Asia/Riyadh",
+    "Asia/Saigon",
+    "Asia/Sakhalin",
+    "Asia/Samarkand",
+    "Asia/Seoul",
+    "Asia/Shanghai",
+    "Asia/Singapore",
+    "Asia/Srednekolymsk",
+    "Asia/Taipei",
+    "Asia/Tashkent",
+    "Asia/Tbilisi",
+    "Asia/Tel_Aviv",
+    "Asia/Thimbu",
+    "Asia/Thimphu",
+    "Asia/Tokyo",
+    "Asia/Tomsk",
+    "Asia/Ujung_Pandang",
+    "Asia/Ulaanbaatar",
+    "Asia/Ulan_Bator",
+    "Asia/Urumqi",
+    "Asia/Ust-Nera",
+    "Asia/Vientiane",
+    "Asia/Vladivostok",
+    "Asia/Yakutsk",
+    "Asia/Yangon",
+    "Asia/Yekaterinburg",
+    "Asia/Yerevan",
+    "Atlantic/Azores",
+    "Atlantic/Bermuda",
+    "Atlantic/Canary",
+    "Atlantic/Cape_Verde",
+    "Atlantic/Faeroe",
+    "Atlantic/Faroe",
+    "Atlantic/Jan_Mayen",
+    "Atlantic/Madeira",
+    "Atlantic/Reykjavik",
+    "Atlantic/South_Georgia",
+    "Atlantic/Stanley",
+    "Atlantic/St_Helena",
+    "Australia/ACT",
+    "Australia/Adelaide",
+    "Australia/Brisbane",
+    "Australia/Broken_Hill",
+    "Australia/Canberra",
+    "Australia/Currie",
+    "Australia/Darwin",
+    "Australia/Eucla",
+    "Australia/Hobart",
+    "Australia/LHI",
+    "Australia/Lindeman",
+    "Australia/Lord_Howe",
+    "Australia/Melbourne",
+    "Australia/North",
+    "Australia/NSW",
+    "Australia/Perth",
+    "Australia/Queensland",
+    "Australia/South",
+    "Australia/Sydney",
+    "Australia/Tasmania",
+    "Australia/Victoria",
+    "Australia/West",
+    "Australia/Yancowinna",
+    "Brazil/Acre",
+    "Brazil/DeNoronha",
+    "Brazil/East",
+    "Brazil/West",
+    "Canada/Atlantic",
+    "Canada/Central",
+    "Canada/Eastern",
+    "Canada/Mountain",
+    "Canada/Newfoundland",
+    "Canada/Pacific",
+    "Canada/Saskatchewan",
+    "Canada/Yukon",
+    "CET",
+    "Chile/Continental",
+    "Chile/EasterIsland",
+    "CST6CDT",
+    "Cuba",
+    "EET",
+    "Egypt",
+    "Eire",
+    "EST",
+    "EST5EDT",
+    "Etc/GMT",
+    "Etc/GMT+0",
+    "Etc/GMT-0",
+    "Etc/GMT0",
+    "Etc/GMT+1",
+    "Etc/GMT-1",
+    "Etc/GMT+10",
+    "Etc/GMT-10",
+    "Etc/GMT+11",
+    "Etc/GMT-11",
+    "Etc/GMT+12",
+    "Etc/GMT-12",
+    "Etc/GMT-13",
+    "Etc/GMT-14",
+    "Etc/GMT+2",
+    "Etc/GMT-2",
+    "Etc/GMT+3",
+    "Etc/GMT-3",
+    "Etc/GMT+4",
+    "Etc/GMT-4",
+    "Etc/GMT+5",
+    "Etc/GMT-5",
+    "Etc/GMT+6",
+    "Etc/GMT-6",
+    "Etc/GMT+7",
+    "Etc/GMT-7",
+    "Etc/GMT+8",
+    "Etc/GMT-8",
+    "Etc/GMT+9",
+    "Etc/GMT-9",
+    "Etc/Greenwich",
+    "Etc/UCT",
+    "Etc/Universal",
+    "Etc/UTC",
+    "Etc/Zulu",
+    "Europe/Amsterdam",
+    "Europe/Andorra",
+    "Europe/Astrakhan",
+    "Europe/Athens",
+    "Europe/Belfast",
+    "Europe/Belgrade",
+    "Europe/Berlin",
+    "Europe/Bratislava",
+    "Europe/Brussels",
+    "Europe/Bucharest",
+    "Europe/Budapest",
+    "Europe/Busingen",
+    "Europe/Chisinau",
+    "Europe/Copenhagen",
+    "Europe/Dublin",
+    "Europe/Gibraltar",
+    "Europe/Guernsey",
+    "Europe/Helsinki",
+    "Europe/Isle_of_Man",
+    "Europe/Istanbul",
+    "Europe/Jersey",
+    "Europe/Kaliningrad",
+    "Europe/Kiev",
+    "Europe/Kirov",
+    "Europe/Kyiv",
+    "Europe/Lisbon",
+    "Europe/Ljubljana",
+    "Europe/London",
+    "Europe/Luxembourg",
+    "Europe/Madrid",
+    "Europe/Malta",
+    "Europe/Mariehamn",
+    "Europe/Minsk",
+    "Europe/Monaco",
+    "Europe/Moscow",
+    "Europe/Nicosia",
+    "Europe/Oslo",
+    "Europe/Paris",
+    "Europe/Podgorica",
+    "Europe/Prague",
+    "Europe/Riga",
+    "Europe/Rome",
+    "Europe/Samara",
+    "Europe/San_Marino",
+    "Europe/Sarajevo",
+    "Europe/Saratov",
+    "Europe/Simferopol",
+    "Europe/Skopje",
+    "Europe/Sofia",
+    "Europe/Stockholm",
+    "Europe/Tallinn",
+    "Europe/Tirane",
+    "Europe/Tiraspol",
+    "Europe/Ulyanovsk",
+    "Europe/Uzhgorod",
+    "Europe/Vaduz",
+    "Europe/Vatican",
+    "Europe/Vienna",
+    "Europe/Vilnius",
+    "Europe/Volgograd",
+    "Europe/Warsaw",
+    "Europe/Zagreb",
+    "Europe/Zaporozhye",
+    "Europe/Zurich",
+    "GB",
+    "GB-Eire",
+    "GMT",
+    "GMT+0",
+    "GMT-0",
+    "GMT0",
+    "Greenwich",
+    "Hongkong",
+    "HST",
+    "Iceland",
+    "Indian/Antananarivo",
+    "Indian/Chagos",
+    "Indian/Christmas",
+    "Indian/Cocos",
+    "Indian/Comoro",
+    "Indian/Kerguelen",
+    "Indian/Mahe",
+    "Indian/Maldives",
+    "Indian/Mauritius",
+    "Indian/Mayotte",
+    "Indian/Reunion",
+    "Iran",
+    "Asia/Tehran",
+    "Israel",
+    "Jamaica",
+    "Japan",
+    "Kwajalein",
+    "Libya",
+    "MET",
+    "Mexico/BajaNorte",
+    "Mexico/BajaSur",
+    "Mexico/General",
+    "MST",
+    "MST7MDT",
+    "Navajo",
+    "NZ",
+    "NZ-CHAT",
+    "Pacific/Chatham",
+    "Pacific/Apia",
+    "Pacific/Auckland",
+    "Pacific/Bougainville",
+    "Pacific/Chuuk",
+    "Pacific/Easter",
+    "Pacific/Efate",
+    "Pacific/Enderbury",
+    "Pacific/Fakaofo",
+    "Pacific/Fiji",
+    "Pacific/Funafuti",
+    "Pacific/Galapagos",
+    "Pacific/Gambier",
+    "Pacific/Guadalcanal",
+    "Pacific/Guam",
+    "Pacific/Honolulu",
+    "Pacific/Johnston",
+    "Pacific/Kanton",
+    "Pacific/Kiritimati",
+    "Pacific/Kosrae",
+    "Pacific/Kwajalein",
+    "Pacific/Majuro",
+    "Pacific/Marquesas",
+    "Pacific/Midway",
+    "Pacific/Nauru",
+    "Pacific/Niue",
+    "Pacific/Norfolk",
+    "Pacific/Noumea",
+    "Pacific/Pago_Pago",
+    "Pacific/Palau",
+    "Pacific/Pitcairn",
+    "Pacific/Pohnpei",
+    "Pacific/Ponape",
+    "Pacific/Port_Moresby",
+    "Pacific/Rarotonga",
+    "Pacific/Saipan",
+    "Pacific/Samoa",
+    "Pacific/Tahiti",
+    "Pacific/Tarawa",
+    "Pacific/Tongatapu",
+    "Pacific/Truk",
+    "Pacific/Wake",
+    "Pacific/Wallis",
+    "Pacific/Yap",
+    "Poland",
+    "Portugal",
+    "PRC",
+    "PST8PDT",
+    "ROC",
+    "ROK",
+    "Singapore",
+    "Turkey",
+    "UCT",
+    "Universal",
+    "US/Alaska",
+    "US/Aleutian",
+    "US/Arizona",
+    "US/Central",
+    "US/Eastern",
+    "US/East-Indiana",
+    "US/Hawaii",
+    "US/Indiana-Starke",
+    "US/Michigan",
+    "US/Mountain",
+    "US/Pacific",
+    "US/Samoa",
+    "UTC",
+    "WET",
+    "W-SU",
+    "Zulu",
+]
diff -pruN 6.0.1-3/src/icalendar/timezone/__init__.py 6.3.1-1/src/icalendar/timezone/__init__.py
--- 6.0.1-3/src/icalendar/timezone/__init__.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/timezone/__init__.py	2025-05-20 07:31:39.000000000 +0000
@@ -1,14 +1,27 @@
 """This package contains all functionality for timezones."""
+
+from .tzid import tzid_from_dt, tzid_from_tzinfo, tzids_from_tzinfo
 from .tzp import TZP
 
 tzp = TZP()
 
+
 def use_pytz():
     """Use pytz as the implementation that looks up and creates timezones."""
     tzp.use_pytz()
 
+
 def use_zoneinfo():
     """Use zoneinfo as the implementation that looks up and creates timezones."""
     tzp.use_zoneinfo()
 
-__all__ = ["tzp", "use_pytz", "use_zoneinfo"]
+
+__all__ = [
+    "TZP",
+    "tzp",
+    "use_pytz",
+    "use_zoneinfo",
+    "tzid_from_tzinfo",
+    "tzid_from_dt",
+    "tzids_from_tzinfo",
+]
diff -pruN 6.0.1-3/src/icalendar/timezone/equivalent_timezone_ids.py 6.3.1-1/src/icalendar/timezone/equivalent_timezone_ids.py
--- 6.0.1-3/src/icalendar/timezone/equivalent_timezone_ids.py	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/timezone/equivalent_timezone_ids.py	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,148 @@
+"""This module helps identifying the timezone ids and where they differ.
+
+The algorithm: We use the tzname and the utcoffset for each hour from
+1970 - 2030.
+We make a big map.
+If they are equivalent, they are equivalent within the time that is mostly used.
+
+You can regenerate the information from this module.
+
+See also:
+- https://stackoverflow.com/questions/79185519/which-timezones-are-equivalent
+
+Run this module:
+
+    python -m icalendar.timezone.equivalent_timezone_ids
+
+"""
+
+from __future__ import annotations
+
+from collections import defaultdict
+from datetime import datetime, timedelta, tzinfo
+from pathlib import Path
+from pprint import pprint
+from typing import Callable, NamedTuple, Optional
+
+from pytz import AmbiguousTimeError, NonExistentTimeError
+from zoneinfo import ZoneInfo, available_timezones
+
+START = datetime(1970, 1, 1)  # noqa: DTZ001
+END = datetime(2020, 1, 1)  # noqa: DTZ001
+DISTANCE_FROM_TIMEZONE_CHANGE = timedelta(hours=12)
+
+DTS = []
+dt = START
+while dt <= END:
+    DTS.append(dt)
+    dt += timedelta(
+        hours=25
+    )  # This must be big enough to be fast and small enough to identify the timeszones before it is the present year
+del dt
+
+
+def main(
+    create_timezones: list[Callable[[str], tzinfo]],
+    name: str,
+):
+    """Generate a lookup table for timezone information if unknown timezones.
+
+    We cannot create one lookup for all because they seem to be all equivalent
+    if we mix timezone implementations.
+    """
+    print(create_timezones, name)
+    unsorted_tzids = available_timezones()
+    unsorted_tzids.remove("localtime")
+    unsorted_tzids.remove("Factory")
+
+    class TZ(NamedTuple):
+        tz: tzinfo
+        id: str
+
+    tzs = [
+        TZ(create_timezone(tzid), tzid)
+        for create_timezone in create_timezones
+        for tzid in unsorted_tzids
+    ]
+
+    def generate_tree(
+        tzs: list[TZ],
+        step: timedelta = timedelta(hours=1),
+        start: datetime = START,
+        end: datetime = END,
+        todo: Optional[set[str]] = None,
+    ) -> tuple[datetime, dict[timedelta, set[str]]] | set[str]:  # should be recursive
+        """Generate a lookup tree."""
+        if todo is None:
+            todo = [tz.id for tz in tzs]
+        print(f"{len(todo)} left to compute")
+        print(len(tzs))
+        if len(tzs) == 0:
+            raise ValueError("tzs cannot be empty")
+        if len(tzs) == 1:
+            todo.remove(tzs[0].id)
+            return {tzs[0].id}
+        while start < end:
+            offsets: dict[timedelta, list[TZ]] = defaultdict(list)
+            try:
+                # if we are around a timezone change, we must move on
+                # see https://github.com/collective/icalendar/issues/776
+                around_tz_change = not all(
+                    tz.tz.utcoffset(start)
+                    == tz.tz.utcoffset(start - DISTANCE_FROM_TIMEZONE_CHANGE)
+                    == tz.tz.utcoffset(start + DISTANCE_FROM_TIMEZONE_CHANGE)
+                    for tz in tzs
+                )
+            except (NonExistentTimeError, AmbiguousTimeError):
+                around_tz_change = True
+            if around_tz_change:
+                start += DISTANCE_FROM_TIMEZONE_CHANGE
+                continue
+            for tz in tzs:
+                offsets[tz.tz.utcoffset(start)].append(tz)
+            if len(offsets) == 1:
+                start += step
+                continue
+            lookup = {}
+            for offset, tzs in offsets.items():
+                lookup[offset] = generate_tree(
+                    tzs=tzs, step=step, start=start + step, end=end, todo=todo
+                )
+            return start, lookup
+        print(f"reached end with {len(tzs)} timezones - assuming they are equivalent.")
+        result = set()
+        for tz in tzs:
+            result.add(tz.id)
+            todo.remove(tz.id)
+        return result
+
+    lookup = generate_tree(tzs, step=timedelta(hours=33))
+
+    file = Path(__file__).parent / f"equivalent_timezone_ids_{name}.py"
+    print(f"The result is written to {file}.")
+    print("lookup = ", end="")
+    pprint(lookup)
+    with file.open("w") as f:
+        f.write(
+            f"'''This file is automatically generated by {Path(__file__).name}'''\n"
+        )
+        f.write("import datetime\n\n")
+        f.write("\nlookup = ")
+        pprint(lookup, stream=f)
+        f.write("\n\n__all__ = ['lookup']\n")
+
+    return lookup
+
+
+__all__ = ["main"]
+
+if __name__ == "__main__":
+    from dateutil.tz import gettz
+    from pytz import timezone
+    from zoneinfo import ZoneInfo
+
+    # add more timezone implementations if you like
+    main(
+        [ZoneInfo, timezone, gettz],
+        "result",
+    )
diff -pruN 6.0.1-3/src/icalendar/timezone/equivalent_timezone_ids_result.py 6.3.1-1/src/icalendar/timezone/equivalent_timezone_ids_result.py
--- 6.0.1-3/src/icalendar/timezone/equivalent_timezone_ids_result.py	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/timezone/equivalent_timezone_ids_result.py	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,3120 @@
+"""This file is automatically generated by equivalent_timezone_ids.py"""
+
+import datetime
+
+
+lookup = (
+    datetime.datetime(1970, 1, 2, 0, 0),
+    {
+        datetime.timedelta(days=-1, seconds=43200): (
+            datetime.datetime(1979, 10, 2, 0, 0),
+            {
+                datetime.timedelta(days=-1, seconds=43200): (
+                    datetime.datetime(1993, 8, 22, 21, 0),
+                    {
+                        datetime.timedelta(days=-1, seconds=43200): {"Etc/GMT+12"},
+                        datetime.timedelta(seconds=43200): {
+                            "Kwajalein",
+                            "Pacific/Kwajalein",
+                        },
+                    },
+                ),
+                datetime.timedelta(days=-1, seconds=46800): {
+                    "Pacific/Enderbury",
+                    "Pacific/Kanton",
+                },
+            },
+        ),
+        datetime.timedelta(days=-1, seconds=46800): (
+            datetime.datetime(1970, 4, 26, 15, 0),
+            {
+                datetime.timedelta(days=-1, seconds=46800): (
+                    datetime.datetime(2010, 9, 26, 15, 0),
+                    {
+                        datetime.timedelta(days=-1, seconds=46800): (
+                            datetime.datetime(2011, 12, 31, 21, 0),
+                            {
+                                datetime.timedelta(days=-1, seconds=46800): {
+                                    "Etc/GMT+11",
+                                    "Pacific/Midway",
+                                    "Pacific/Niue",
+                                    "Pacific/Pago_Pago",
+                                    "Pacific/Samoa",
+                                    "US/Samoa",
+                                },
+                                datetime.timedelta(seconds=46800): {"Pacific/Fakaofo"},
+                            },
+                        ),
+                        datetime.timedelta(days=-1, seconds=50400): {"Pacific/Apia"},
+                    },
+                ),
+                datetime.timedelta(days=-1, seconds=50400): (
+                    datetime.datetime(1983, 10, 30, 21, 0),
+                    {
+                        datetime.timedelta(days=-1, seconds=50400): {
+                            "America/Adak",
+                            "America/Atka",
+                            "US/Aleutian",
+                        },
+                        datetime.timedelta(days=-1, seconds=54000): {"America/Nome"},
+                    },
+                ),
+            },
+        ),
+        datetime.timedelta(days=-1, seconds=48000): {"Pacific/Kiritimati"},
+        datetime.timedelta(days=-1, seconds=48600): {"Pacific/Rarotonga"},
+        datetime.timedelta(days=-1, seconds=50400): (
+            datetime.datetime(1970, 4, 26, 15, 0),
+            {
+                datetime.timedelta(days=-1, seconds=50400): {
+                    "Etc/GMT+10",
+                    "HST",
+                    "Pacific/Honolulu",
+                    "Pacific/Johnston",
+                    "Pacific/Tahiti",
+                    "US/Hawaii",
+                },
+                datetime.timedelta(days=-1, seconds=54000): {
+                    "America/Anchorage",
+                    "US/Alaska",
+                },
+            },
+        ),
+        datetime.timedelta(days=-1, seconds=52200): {"Pacific/Marquesas"},
+        datetime.timedelta(days=-1, seconds=54000): (
+            datetime.datetime(1970, 4, 26, 15, 0),
+            {
+                datetime.timedelta(days=-1, seconds=54000): (
+                    datetime.datetime(1973, 10, 28, 18, 0),
+                    {
+                        datetime.timedelta(days=-1, seconds=54000): {
+                            "Etc/GMT+9",
+                            "Pacific/Gambier",
+                        },
+                        datetime.timedelta(days=-1, seconds=57600): {"America/Dawson"},
+                    },
+                ),
+                datetime.timedelta(days=-1, seconds=57600): {"America/Yakutat"},
+            },
+        ),
+        datetime.timedelta(days=-1, seconds=55800): {"Pacific/Pitcairn"},
+        datetime.timedelta(days=-1, seconds=57600): (
+            datetime.datetime(1970, 4, 26, 15, 0),
+            {
+                datetime.timedelta(days=-1, seconds=57600): (
+                    datetime.datetime(1972, 4, 30, 21, 0),
+                    {
+                        datetime.timedelta(days=-1, seconds=57600): (
+                            datetime.datetime(1976, 4, 25, 15, 0),
+                            {
+                                datetime.timedelta(days=-1, seconds=57600): (
+                                    datetime.datetime(1980, 4, 27, 15, 0),
+                                    {
+                                        datetime.timedelta(days=-1, seconds=57600): {
+                                            "Etc/GMT+8"
+                                        },
+                                        datetime.timedelta(days=-1, seconds=61200): {
+                                            "America/Whitehorse",
+                                            "Canada/Yukon",
+                                        },
+                                    },
+                                ),
+                                datetime.timedelta(days=-1, seconds=61200): {
+                                    "America/Ensenada",
+                                    "America/Santa_Isabel",
+                                    "America/Tijuana",
+                                    "Mexico/BajaNorte",
+                                },
+                            },
+                        ),
+                        datetime.timedelta(days=-1, seconds=61200): {"America/Inuvik"},
+                    },
+                ),
+                datetime.timedelta(days=-1, seconds=61200): (
+                    datetime.datetime(1972, 10, 30, 0, 0),
+                    {
+                        datetime.timedelta(days=-1, seconds=57600): (
+                            datetime.datetime(1974, 1, 6, 18, 0),
+                            {
+                                datetime.timedelta(days=-1, seconds=57600): (
+                                    datetime.datetime(2015, 11, 1, 21, 0),
+                                    {
+                                        datetime.timedelta(days=-1, seconds=57600): {
+                                            "America/Vancouver",
+                                            "Canada/Pacific",
+                                        },
+                                        datetime.timedelta(days=-1, seconds=61200): {
+                                            "America/Fort_Nelson"
+                                        },
+                                    },
+                                ),
+                                datetime.timedelta(days=-1, seconds=61200): (
+                                    datetime.datetime(1980, 4, 28, 0, 0),
+                                    {
+                                        datetime.timedelta(days=-1, seconds=57600): {
+                                            "America/Juneau"
+                                        },
+                                        datetime.timedelta(days=-1, seconds=61200): (
+                                            datetime.datetime(1983, 10, 30, 21, 0),
+                                            {
+                                                datetime.timedelta(
+                                                    days=-1, seconds=54000
+                                                ): {"America/Sitka"},
+                                                datetime.timedelta(
+                                                    days=-1, seconds=57600
+                                                ): (
+                                                    datetime.datetime(
+                                                        1984, 4, 29, 21, 0
+                                                    ),
+                                                    {
+                                                        datetime.timedelta(
+                                                            days=-1, seconds=57600
+                                                        ): {"America/Metlakatla"},
+                                                        datetime.timedelta(
+                                                            days=-1, seconds=61200
+                                                        ): {
+                                                            "America/Los_Angeles",
+                                                            "PST8PDT",
+                                                            "US/Pacific",
+                                                        },
+                                                    },
+                                                ),
+                                            },
+                                        ),
+                                    },
+                                ),
+                            },
+                        ),
+                        datetime.timedelta(days=-1, seconds=61200): {
+                            "America/Dawson_Creek"
+                        },
+                    },
+                ),
+            },
+        ),
+        datetime.timedelta(days=-1, seconds=61200): (
+            datetime.datetime(1970, 4, 26, 15, 0),
+            {
+                datetime.timedelta(days=-1, seconds=61200): (
+                    datetime.datetime(1972, 4, 30, 21, 0),
+                    {
+                        datetime.timedelta(days=-1, seconds=61200): (
+                            datetime.datetime(1996, 4, 7, 15, 0),
+                            {
+                                datetime.timedelta(days=-1, seconds=61200): {
+                                    "America/Creston",
+                                    "America/Phoenix",
+                                    "Etc/GMT+7",
+                                    "MST",
+                                    "US/Arizona",
+                                },
+                                datetime.timedelta(days=-1, seconds=64800): (
+                                    datetime.datetime(1999, 4, 4, 15, 0),
+                                    {
+                                        datetime.timedelta(days=-1, seconds=61200): {
+                                            "America/Hermosillo"
+                                        },
+                                        datetime.timedelta(days=-1, seconds=64800): (
+                                            datetime.datetime(2010, 4, 5, 0, 0),
+                                            {
+                                                datetime.timedelta(
+                                                    days=-1, seconds=64800
+                                                ): {
+                                                    "America/Mazatlan",
+                                                    "Mexico/BajaSur",
+                                                },
+                                                datetime.timedelta(
+                                                    days=-1, seconds=68400
+                                                ): {"America/Bahia_Banderas"},
+                                            },
+                                        ),
+                                    },
+                                ),
+                            },
+                        ),
+                        datetime.timedelta(days=-1, seconds=64800): (
+                            datetime.datetime(1972, 10, 29, 21, 0),
+                            {
+                                datetime.timedelta(days=-1, seconds=61200): (
+                                    datetime.datetime(1999, 11, 1, 0, 0),
+                                    {
+                                        datetime.timedelta(days=-1, seconds=61200): {
+                                            "America/Edmonton",
+                                            "America/Yellowknife",
+                                            "Canada/Mountain",
+                                        },
+                                        datetime.timedelta(days=-1, seconds=64800): {
+                                            "America/Cambridge_Bay"
+                                        },
+                                    },
+                                ),
+                                datetime.timedelta(days=-1, seconds=64800): {
+                                    "America/Swift_Current"
+                                },
+                            },
+                        ),
+                    },
+                ),
+                datetime.timedelta(days=-1, seconds=64800): (
+                    datetime.datetime(1974, 1, 6, 18, 0),
+                    {
+                        datetime.timedelta(days=-1, seconds=61200): {"America/Boise"},
+                        datetime.timedelta(days=-1, seconds=64800): (
+                            datetime.datetime(1992, 10, 25, 18, 0),
+                            {
+                                datetime.timedelta(days=-1, seconds=61200): (
+                                    datetime.datetime(2003, 10, 26, 15, 0),
+                                    {
+                                        datetime.timedelta(days=-1, seconds=61200): (
+                                            datetime.datetime(2010, 11, 7, 21, 0),
+                                            {
+                                                datetime.timedelta(
+                                                    days=-1, seconds=61200
+                                                ): {
+                                                    "America/Denver",
+                                                    "America/Shiprock",
+                                                    "MST7MDT",
+                                                    "Navajo",
+                                                    "US/Mountain",
+                                                },
+                                                datetime.timedelta(
+                                                    days=-1, seconds=64800
+                                                ): {"America/North_Dakota/Beulah"},
+                                            },
+                                        ),
+                                        datetime.timedelta(days=-1, seconds=64800): {
+                                            "America/North_Dakota/New_Salem"
+                                        },
+                                    },
+                                ),
+                                datetime.timedelta(days=-1, seconds=64800): {
+                                    "America/North_Dakota/Center"
+                                },
+                            },
+                        ),
+                    },
+                ),
+            },
+        ),
+        datetime.timedelta(days=-1, seconds=64800): (
+            datetime.datetime(1970, 3, 29, 15, 0),
+            {
+                datetime.timedelta(days=-1, seconds=61200): {
+                    "Chile/EasterIsland",
+                    "Pacific/Easter",
+                },
+                datetime.timedelta(days=-1, seconds=64800): (
+                    datetime.datetime(1970, 4, 26, 15, 0),
+                    {
+                        datetime.timedelta(days=-1, seconds=64800): (
+                            datetime.datetime(1972, 4, 30, 21, 0),
+                            {
+                                datetime.timedelta(days=-1, seconds=64800): (
+                                    datetime.datetime(1973, 5, 1, 15, 0),
+                                    {
+                                        datetime.timedelta(days=-1, seconds=64800): (
+                                            datetime.datetime(1973, 11, 25, 18, 0),
+                                            {
+                                                datetime.timedelta(
+                                                    days=-1, seconds=64800
+                                                ): (
+                                                    datetime.datetime(
+                                                        1973, 12, 5, 21, 0
+                                                    ),
+                                                    {
+                                                        datetime.timedelta(
+                                                            days=-1, seconds=64800
+                                                        ): (
+                                                            datetime.datetime(
+                                                                1979, 2, 26, 0, 0
+                                                            ),
+                                                            {
+                                                                datetime.timedelta(
+                                                                    days=-1,
+                                                                    seconds=64800,
+                                                                ): (
+                                                                    datetime.datetime(
+                                                                        1981,
+                                                                        12,
+                                                                        27,
+                                                                        0,
+                                                                        0,
+                                                                    ),
+                                                                    {
+                                                                        datetime.timedelta(
+                                                                            days=-1,
+                                                                            seconds=64800,
+                                                                        ): (
+                                                                            datetime.datetime(
+                                                                                1987,
+                                                                                5,
+                                                                                4,
+                                                                                0,
+                                                                                0,
+                                                                            ),
+                                                                            {
+                                                                                datetime.timedelta(
+                                                                                    days=-1,
+                                                                                    seconds=64800,
+                                                                                ): (
+                                                                                    datetime.datetime(
+                                                                                        1988,
+                                                                                        4,
+                                                                                        4,
+                                                                                        0,
+                                                                                        0,
+                                                                                    ),
+                                                                                    {
+                                                                                        datetime.timedelta(
+                                                                                            days=-1,
+                                                                                            seconds=64800,
+                                                                                        ): (
+                                                                                            datetime.datetime(
+                                                                                                1996,
+                                                                                                4,
+                                                                                                7,
+                                                                                                15,
+                                                                                                0,
+                                                                                            ),
+                                                                                            {
+                                                                                                datetime.timedelta(
+                                                                                                    days=-1,
+                                                                                                    seconds=64800,
+                                                                                                ): {
+                                                                                                    "America/Regina",
+                                                                                                    "Canada/Saskatchewan",
+                                                                                                    "Etc/GMT+6",
+                                                                                                },
+                                                                                                datetime.timedelta(
+                                                                                                    days=-1,
+                                                                                                    seconds=68400,
+                                                                                                ): (
+                                                                                                    datetime.datetime(
+                                                                                                        1998,
+                                                                                                        4,
+                                                                                                        5,
+                                                                                                        15,
+                                                                                                        0,
+                                                                                                    ),
+                                                                                                    {
+                                                                                                        datetime.timedelta(
+                                                                                                            days=-1,
+                                                                                                            seconds=64800,
+                                                                                                        ): (
+                                                                                                            datetime.datetime(
+                                                                                                                2010,
+                                                                                                                3,
+                                                                                                                14,
+                                                                                                                21,
+                                                                                                                0,
+                                                                                                            ),
+                                                                                                            {
+                                                                                                                datetime.timedelta(
+                                                                                                                    days=-1,
+                                                                                                                    seconds=61200,
+                                                                                                                ): {
+                                                                                                                    "America/Chihuahua"
+                                                                                                                },
+                                                                                                                datetime.timedelta(
+                                                                                                                    days=-1,
+                                                                                                                    seconds=64800,
+                                                                                                                ): {
+                                                                                                                    "America/Ciudad_Juarez",
+                                                                                                                    "America/Ojinaga",
+                                                                                                                },
+                                                                                                            },
+                                                                                                        ),
+                                                                                                        datetime.timedelta(
+                                                                                                            days=-1,
+                                                                                                            seconds=68400,
+                                                                                                        ): {
+                                                                                                            "America/Mexico_City",
+                                                                                                            "Mexico/General",
+                                                                                                        },
+                                                                                                    },
+                                                                                                ),
+                                                                                            },
+                                                                                        ),
+                                                                                        datetime.timedelta(
+                                                                                            days=-1,
+                                                                                            seconds=68400,
+                                                                                        ): (
+                                                                                            datetime.datetime(
+                                                                                                2010,
+                                                                                                3,
+                                                                                                14,
+                                                                                                21,
+                                                                                                0,
+                                                                                            ),
+                                                                                            {
+                                                                                                datetime.timedelta(
+                                                                                                    days=-1,
+                                                                                                    seconds=64800,
+                                                                                                ): {
+                                                                                                    "America/Monterrey"
+                                                                                                },
+                                                                                                datetime.timedelta(
+                                                                                                    days=-1,
+                                                                                                    seconds=68400,
+                                                                                                ): {
+                                                                                                    "America/Matamoros"
+                                                                                                },
+                                                                                            },
+                                                                                        ),
+                                                                                    },
+                                                                                ),
+                                                                                datetime.timedelta(
+                                                                                    days=-1,
+                                                                                    seconds=68400,
+                                                                                ): (
+                                                                                    datetime.datetime(
+                                                                                        2006,
+                                                                                        5,
+                                                                                        8,
+                                                                                        0,
+                                                                                        0,
+                                                                                    ),
+                                                                                    {
+                                                                                        datetime.timedelta(
+                                                                                            days=-1,
+                                                                                            seconds=64800,
+                                                                                        ): {
+                                                                                            "America/El_Salvador"
+                                                                                        },
+                                                                                        datetime.timedelta(
+                                                                                            days=-1,
+                                                                                            seconds=68400,
+                                                                                        ): {
+                                                                                            "America/Tegucigalpa"
+                                                                                        },
+                                                                                    },
+                                                                                ),
+                                                                            },
+                                                                        ),
+                                                                        datetime.timedelta(
+                                                                            days=-1,
+                                                                            seconds=68400,
+                                                                        ): (
+                                                                            datetime.datetime(
+                                                                                1982,
+                                                                                11,
+                                                                                2,
+                                                                                18,
+                                                                                0,
+                                                                            ),
+                                                                            {
+                                                                                datetime.timedelta(
+                                                                                    days=-1,
+                                                                                    seconds=64800,
+                                                                                ): {
+                                                                                    "America/Merida"
+                                                                                },
+                                                                                datetime.timedelta(
+                                                                                    days=-1,
+                                                                                    seconds=68400,
+                                                                                ): {
+                                                                                    "America/Cancun"
+                                                                                },
+                                                                            },
+                                                                        ),
+                                                                    },
+                                                                ),
+                                                                datetime.timedelta(
+                                                                    days=-1,
+                                                                    seconds=68400,
+                                                                ): {
+                                                                    "America/Costa_Rica"
+                                                                },
+                                                            },
+                                                        ),
+                                                        datetime.timedelta(
+                                                            days=-1, seconds=68400
+                                                        ): {"America/Belize"},
+                                                    },
+                                                ),
+                                                datetime.timedelta(
+                                                    days=-1, seconds=68400
+                                                ): {"America/Guatemala"},
+                                            },
+                                        ),
+                                        datetime.timedelta(days=-1, seconds=68400): {
+                                            "America/Managua"
+                                        },
+                                    },
+                                ),
+                                datetime.timedelta(days=-1, seconds=68400): (
+                                    datetime.datetime(2006, 10, 29, 21, 0),
+                                    {
+                                        datetime.timedelta(days=-1, seconds=64800): {
+                                            "America/Rankin_Inlet"
+                                        },
+                                        datetime.timedelta(days=-1, seconds=68400): {
+                                            "America/Resolute"
+                                        },
+                                    },
+                                ),
+                            },
+                        ),
+                        datetime.timedelta(days=-1, seconds=68400): (
+                            datetime.datetime(1974, 1, 6, 18, 0),
+                            {
+                                datetime.timedelta(days=-1, seconds=64800): {
+                                    "America/Rainy_River",
+                                    "America/Winnipeg",
+                                    "Canada/Central",
+                                },
+                                datetime.timedelta(days=-1, seconds=68400): (
+                                    datetime.datetime(1977, 10, 31, 0, 0),
+                                    {
+                                        datetime.timedelta(days=-1, seconds=64800): (
+                                            datetime.datetime(1991, 10, 27, 18, 0),
+                                            {
+                                                datetime.timedelta(
+                                                    days=-1, seconds=64800
+                                                ): (
+                                                    datetime.datetime(
+                                                        2000, 10, 29, 15, 0
+                                                    ),
+                                                    {
+                                                        datetime.timedelta(
+                                                            days=-1, seconds=64800
+                                                        ): {
+                                                            "America/Chicago",
+                                                            "CST6CDT",
+                                                            "US/Central",
+                                                        },
+                                                        datetime.timedelta(
+                                                            days=-1, seconds=68400
+                                                        ): {
+                                                            "America/Kentucky/Monticello"
+                                                        },
+                                                    },
+                                                ),
+                                                datetime.timedelta(
+                                                    days=-1, seconds=68400
+                                                ): {
+                                                    "America/Indiana/Knox",
+                                                    "America/Knox_IN",
+                                                    "US/Indiana-Starke",
+                                                },
+                                            },
+                                        ),
+                                        datetime.timedelta(days=-1, seconds=68400): {
+                                            "America/Indiana/Petersburg"
+                                        },
+                                    },
+                                ),
+                            },
+                        ),
+                    },
+                ),
+            },
+        ),
+        datetime.timedelta(days=-1, seconds=68400): (
+            datetime.datetime(1970, 4, 26, 15, 0),
+            {
+                datetime.timedelta(days=-1, seconds=68400): (
+                    datetime.datetime(1972, 4, 30, 21, 0),
+                    {
+                        datetime.timedelta(days=-1, seconds=68400): (
+                            datetime.datetime(1973, 4, 29, 21, 0),
+                            {
+                                datetime.timedelta(days=-1, seconds=68400): (
+                                    datetime.datetime(1973, 10, 28, 21, 0),
+                                    {
+                                        datetime.timedelta(days=-1, seconds=64800): {
+                                            "America/Menominee"
+                                        },
+                                        datetime.timedelta(days=-1, seconds=68400): (
+                                            datetime.datetime(1974, 1, 6, 15, 0),
+                                            {
+                                                datetime.timedelta(
+                                                    days=-1, seconds=68400
+                                                ): (
+                                                    datetime.datetime(
+                                                        1979, 4, 29, 21, 0
+                                                    ),
+                                                    {
+                                                        datetime.timedelta(
+                                                            days=-1, seconds=68400
+                                                        ): (
+                                                            datetime.datetime(
+                                                                1983, 5, 8, 18, 0
+                                                            ),
+                                                            {
+                                                                datetime.timedelta(
+                                                                    days=-1,
+                                                                    seconds=68400,
+                                                                ): (
+                                                                    datetime.datetime(
+                                                                        1985,
+                                                                        11,
+                                                                        2,
+                                                                        15,
+                                                                        0,
+                                                                    ),
+                                                                    {
+                                                                        datetime.timedelta(
+                                                                            days=-1,
+                                                                            seconds=68400,
+                                                                        ): (
+                                                                            datetime.datetime(
+                                                                                1986,
+                                                                                1,
+                                                                                1,
+                                                                                18,
+                                                                                0,
+                                                                            ),
+                                                                            {
+                                                                                datetime.timedelta(
+                                                                                    days=-1,
+                                                                                    seconds=64800,
+                                                                                ): {
+                                                                                    "Pacific/Galapagos"
+                                                                                },
+                                                                                datetime.timedelta(
+                                                                                    days=-1,
+                                                                                    seconds=68400,
+                                                                                ): (
+                                                                                    datetime.datetime(
+                                                                                        1992,
+                                                                                        5,
+                                                                                        4,
+                                                                                        0,
+                                                                                        0,
+                                                                                    ),
+                                                                                    {
+                                                                                        datetime.timedelta(
+                                                                                            days=-1,
+                                                                                            seconds=68400,
+                                                                                        ): (
+                                                                                            datetime.datetime(
+                                                                                                1992,
+                                                                                                11,
+                                                                                                28,
+                                                                                                15,
+                                                                                                0,
+                                                                                            ),
+                                                                                            {
+                                                                                                datetime.timedelta(
+                                                                                                    days=-1,
+                                                                                                    seconds=68400,
+                                                                                                ): {
+                                                                                                    "America/Atikokan",
+                                                                                                    "America/Cayman",
+                                                                                                    "America/Coral_Harbour",
+                                                                                                    "America/Panama",
+                                                                                                    "EST",
+                                                                                                    "Etc/GMT+5",
+                                                                                                },
+                                                                                                datetime.timedelta(
+                                                                                                    days=-1,
+                                                                                                    seconds=72000,
+                                                                                                ): {
+                                                                                                    "America/Guayaquil"
+                                                                                                },
+                                                                                            },
+                                                                                        ),
+                                                                                        datetime.timedelta(
+                                                                                            days=-1,
+                                                                                            seconds=72000,
+                                                                                        ): {
+                                                                                            "America/Bogota"
+                                                                                        },
+                                                                                    },
+                                                                                ),
+                                                                                datetime.timedelta(
+                                                                                    days=-1,
+                                                                                    seconds=72000,
+                                                                                ): {
+                                                                                    "America/Lima"
+                                                                                },
+                                                                            },
+                                                                        ),
+                                                                        datetime.timedelta(
+                                                                            days=-1,
+                                                                            seconds=72000,
+                                                                        ): (
+                                                                            datetime.datetime(
+                                                                                1993,
+                                                                                10,
+                                                                                17,
+                                                                                15,
+                                                                                0,
+                                                                            ),
+                                                                            {
+                                                                                datetime.timedelta(
+                                                                                    days=-1,
+                                                                                    seconds=68400,
+                                                                                ): {
+                                                                                    "America/Porto_Acre",
+                                                                                    "America/Rio_Branco",
+                                                                                    "Brazil/Acre",
+                                                                                },
+                                                                                datetime.timedelta(
+                                                                                    days=-1,
+                                                                                    seconds=72000,
+                                                                                ): {
+                                                                                    "America/Eirunepe"
+                                                                                },
+                                                                            },
+                                                                        ),
+                                                                    },
+                                                                ),
+                                                                datetime.timedelta(
+                                                                    days=-1,
+                                                                    seconds=72000,
+                                                                ): {
+                                                                    "America/Port-au-Prince"
+                                                                },
+                                                            },
+                                                        ),
+                                                        datetime.timedelta(
+                                                            days=-1, seconds=72000
+                                                        ): {"America/Grand_Turk"},
+                                                    },
+                                                ),
+                                                datetime.timedelta(
+                                                    days=-1, seconds=72000
+                                                ): {"America/Jamaica", "Jamaica"},
+                                            },
+                                        ),
+                                    },
+                                ),
+                                datetime.timedelta(days=-1, seconds=72000): {
+                                    "America/Detroit",
+                                    "US/Michigan",
+                                },
+                            },
+                        ),
+                        datetime.timedelta(days=-1, seconds=72000): {
+                            "America/Iqaluit",
+                            "America/Pangnirtung",
+                        },
+                    },
+                ),
+                datetime.timedelta(days=-1, seconds=72000): (
+                    datetime.datetime(1971, 4, 25, 15, 0),
+                    {
+                        datetime.timedelta(days=-1, seconds=68400): (
+                            datetime.datetime(2006, 4, 2, 15, 0),
+                            {
+                                datetime.timedelta(days=-1, seconds=68400): (
+                                    datetime.datetime(2007, 3, 12, 3, 0),
+                                    {
+                                        datetime.timedelta(days=-1, seconds=68400): (
+                                            datetime.datetime(2007, 11, 4, 15, 0),
+                                            {
+                                                datetime.timedelta(
+                                                    days=-1, seconds=64800
+                                                ): {"America/Indiana/Tell_City"},
+                                                datetime.timedelta(
+                                                    days=-1, seconds=68400
+                                                ): {"America/Indiana/Vincennes"},
+                                            },
+                                        ),
+                                        datetime.timedelta(days=-1, seconds=72000): {
+                                            "America/Indiana/Winamac"
+                                        },
+                                    },
+                                ),
+                                datetime.timedelta(days=-1, seconds=72000): {
+                                    "America/Fort_Wayne",
+                                    "America/Indiana/Indianapolis",
+                                    "America/Indianapolis",
+                                    "US/East-Indiana",
+                                },
+                            },
+                        ),
+                        datetime.timedelta(days=-1, seconds=72000): (
+                            datetime.datetime(1972, 10, 8, 12, 0),
+                            {
+                                datetime.timedelta(days=-1, seconds=68400): {
+                                    "America/Havana",
+                                    "Cuba",
+                                },
+                                datetime.timedelta(days=-1, seconds=72000): (
+                                    datetime.datetime(1973, 4, 29, 15, 0),
+                                    {
+                                        datetime.timedelta(days=-1, seconds=68400): {
+                                            "America/Indiana/Vevay"
+                                        },
+                                        datetime.timedelta(days=-1, seconds=72000): (
+                                            datetime.datetime(1974, 1, 6, 18, 0),
+                                            {
+                                                datetime.timedelta(
+                                                    days=-1, seconds=68400
+                                                ): (
+                                                    datetime.datetime(
+                                                        1974, 4, 28, 15, 0
+                                                    ),
+                                                    {
+                                                        datetime.timedelta(
+                                                            days=-1, seconds=68400
+                                                        ): (
+                                                            datetime.datetime(
+                                                                1976, 4, 26, 0, 0
+                                                            ),
+                                                            {
+                                                                datetime.timedelta(
+                                                                    days=-1,
+                                                                    seconds=68400,
+                                                                ): {
+                                                                    "America/Indiana/Marengo"
+                                                                },
+                                                                datetime.timedelta(
+                                                                    days=-1,
+                                                                    seconds=72000,
+                                                                ): {
+                                                                    "America/Kentucky/Louisville",
+                                                                    "America/Louisville",
+                                                                },
+                                                            },
+                                                        ),
+                                                        datetime.timedelta(
+                                                            days=-1, seconds=72000
+                                                        ): {
+                                                            "America/Montreal",
+                                                            "America/Nassau",
+                                                            "America/Nipigon",
+                                                            "America/Thunder_Bay",
+                                                            "America/Toronto",
+                                                            "Canada/Eastern",
+                                                        },
+                                                    },
+                                                ),
+                                                datetime.timedelta(
+                                                    days=-1, seconds=72000
+                                                ): {
+                                                    "America/New_York",
+                                                    "EST5EDT",
+                                                    "US/Eastern",
+                                                },
+                                            },
+                                        ),
+                                    },
+                                ),
+                            },
+                        ),
+                    },
+                ),
+            },
+        ),
+        datetime.timedelta(days=-1, seconds=70200): {"America/Santo_Domingo"},
+        datetime.timedelta(days=-1, seconds=72000): (
+            datetime.datetime(1970, 4, 26, 15, 0),
+            {
+                datetime.timedelta(days=-1, seconds=72000): (
+                    datetime.datetime(1972, 4, 30, 21, 0),
+                    {
+                        datetime.timedelta(days=-1, seconds=72000): (
+                            datetime.datetime(1972, 10, 2, 0, 0),
+                            {
+                                datetime.timedelta(days=-1, seconds=72000): (
+                                    datetime.datetime(1974, 4, 28, 21, 0),
+                                    {
+                                        datetime.timedelta(days=-1, seconds=72000): (
+                                            datetime.datetime(1977, 6, 12, 18, 0),
+                                            {
+                                                datetime.timedelta(
+                                                    days=-1, seconds=72000
+                                                ): (
+                                                    datetime.datetime(
+                                                        1980, 4, 6, 18, 0
+                                                    ),
+                                                    {
+                                                        datetime.timedelta(
+                                                            days=-1, seconds=72000
+                                                        ): (
+                                                            datetime.datetime(
+                                                                1980, 5, 2, 0, 0
+                                                            ),
+                                                            {
+                                                                datetime.timedelta(
+                                                                    days=-1,
+                                                                    seconds=72000,
+                                                                ): (
+                                                                    datetime.datetime(
+                                                                        1983, 5, 2, 0, 0
+                                                                    ),
+                                                                    {
+                                                                        datetime.timedelta(
+                                                                            days=-1,
+                                                                            seconds=72000,
+                                                                        ): (
+                                                                            datetime.datetime(
+                                                                                1985,
+                                                                                11,
+                                                                                2,
+                                                                                18,
+                                                                                0,
+                                                                            ),
+                                                                            {
+                                                                                datetime.timedelta(
+                                                                                    days=-1,
+                                                                                    seconds=72000,
+                                                                                ): (
+                                                                                    datetime.datetime(
+                                                                                        1991,
+                                                                                        3,
+                                                                                        31,
+                                                                                        18,
+                                                                                        0,
+                                                                                    ),
+                                                                                    {
+                                                                                        datetime.timedelta(
+                                                                                            days=-1,
+                                                                                            seconds=72000,
+                                                                                        ): (
+                                                                                            datetime.datetime(
+                                                                                                2007,
+                                                                                                12,
+                                                                                                10,
+                                                                                                0,
+                                                                                                0,
+                                                                                            ),
+                                                                                            {
+                                                                                                datetime.timedelta(
+                                                                                                    days=-1,
+                                                                                                    seconds=70200,
+                                                                                                ): {
+                                                                                                    "America/Caracas"
+                                                                                                },
+                                                                                                datetime.timedelta(
+                                                                                                    days=-1,
+                                                                                                    seconds=72000,
+                                                                                                ): {
+                                                                                                    "America/Anguilla",
+                                                                                                    "America/Antigua",
+                                                                                                    "America/Aruba",
+                                                                                                    "America/Blanc-Sablon",
+                                                                                                    "America/Curacao",
+                                                                                                    "America/Dominica",
+                                                                                                    "America/Grenada",
+                                                                                                    "America/Guadeloupe",
+                                                                                                    "America/Kralendijk",
+                                                                                                    "America/La_Paz",
+                                                                                                    "America/Lower_Princes",
+                                                                                                    "America/Marigot",
+                                                                                                    "America/Montserrat",
+                                                                                                    "America/Port_of_Spain",
+                                                                                                    "America/Puerto_Rico",
+                                                                                                    "America/St_Barthelemy",
+                                                                                                    "America/St_Kitts",
+                                                                                                    "America/St_Lucia",
+                                                                                                    "America/St_Thomas",
+                                                                                                    "America/St_Vincent",
+                                                                                                    "America/Tortola",
+                                                                                                    "America/Virgin",
+                                                                                                    "Etc/GMT+4",
+                                                                                                },
+                                                                                            },
+                                                                                        ),
+                                                                                        datetime.timedelta(
+                                                                                            days=-1,
+                                                                                            seconds=75600,
+                                                                                        ): {
+                                                                                            "America/Thule"
+                                                                                        },
+                                                                                    },
+                                                                                ),
+                                                                                datetime.timedelta(
+                                                                                    days=-1,
+                                                                                    seconds=75600,
+                                                                                ): (
+                                                                                    datetime.datetime(
+                                                                                        1988,
+                                                                                        10,
+                                                                                        16,
+                                                                                        15,
+                                                                                        0,
+                                                                                    ),
+                                                                                    {
+                                                                                        datetime.timedelta(
+                                                                                            days=-1,
+                                                                                            seconds=72000,
+                                                                                        ): (
+                                                                                            datetime.datetime(
+                                                                                                1993,
+                                                                                                10,
+                                                                                                17,
+                                                                                                15,
+                                                                                                0,
+                                                                                            ),
+                                                                                            {
+                                                                                                datetime.timedelta(
+                                                                                                    days=-1,
+                                                                                                    seconds=72000,
+                                                                                                ): (
+                                                                                                    datetime.datetime(
+                                                                                                        1999,
+                                                                                                        10,
+                                                                                                        3,
+                                                                                                        18,
+                                                                                                        0,
+                                                                                                    ),
+                                                                                                    {
+                                                                                                        datetime.timedelta(
+                                                                                                            days=-1,
+                                                                                                            seconds=72000,
+                                                                                                        ): (
+                                                                                                            datetime.datetime(
+                                                                                                                2008,
+                                                                                                                6,
+                                                                                                                24,
+                                                                                                                15,
+                                                                                                                0,
+                                                                                                            ),
+                                                                                                            {
+                                                                                                                datetime.timedelta(
+                                                                                                                    days=-1,
+                                                                                                                    seconds=72000,
+                                                                                                                ): {
+                                                                                                                    "America/Porto_Velho"
+                                                                                                                },
+                                                                                                                datetime.timedelta(
+                                                                                                                    days=-1,
+                                                                                                                    seconds=75600,
+                                                                                                                ): {
+                                                                                                                    "America/Santarem"
+                                                                                                                },
+                                                                                                            },
+                                                                                                        ),
+                                                                                                        datetime.timedelta(
+                                                                                                            days=-1,
+                                                                                                            seconds=75600,
+                                                                                                        ): {
+                                                                                                            "America/Boa_Vista"
+                                                                                                        },
+                                                                                                    },
+                                                                                                ),
+                                                                                                datetime.timedelta(
+                                                                                                    days=-1,
+                                                                                                    seconds=75600,
+                                                                                                ): {
+                                                                                                    "America/Manaus",
+                                                                                                    "Brazil/West",
+                                                                                                },
+                                                                                            },
+                                                                                        ),
+                                                                                        datetime.timedelta(
+                                                                                            days=-1,
+                                                                                            seconds=75600,
+                                                                                        ): (
+                                                                                            datetime.datetime(
+                                                                                                2003,
+                                                                                                10,
+                                                                                                19,
+                                                                                                21,
+                                                                                                0,
+                                                                                            ),
+                                                                                            {
+                                                                                                datetime.timedelta(
+                                                                                                    days=-1,
+                                                                                                    seconds=72000,
+                                                                                                ): {
+                                                                                                    "America/Cuiaba"
+                                                                                                },
+                                                                                                datetime.timedelta(
+                                                                                                    days=-1,
+                                                                                                    seconds=75600,
+                                                                                                ): {
+                                                                                                    "America/Campo_Grande"
+                                                                                                },
+                                                                                            },
+                                                                                        ),
+                                                                                    },
+                                                                                ),
+                                                                            },
+                                                                        ),
+                                                                        datetime.timedelta(
+                                                                            days=-1,
+                                                                            seconds=75600,
+                                                                        ): {
+                                                                            "Atlantic/Stanley"
+                                                                        },
+                                                                    },
+                                                                ),
+                                                                datetime.timedelta(
+                                                                    days=-1,
+                                                                    seconds=75600,
+                                                                ): {"America/Miquelon"},
+                                                            },
+                                                        ),
+                                                        datetime.timedelta(
+                                                            days=-1, seconds=75600
+                                                        ): {"America/Martinique"},
+                                                    },
+                                                ),
+                                                datetime.timedelta(
+                                                    days=-1, seconds=75600
+                                                ): {"America/Barbados"},
+                                            },
+                                        ),
+                                        datetime.timedelta(days=-1, seconds=75600): {
+                                            "Atlantic/Bermuda"
+                                        },
+                                    },
+                                ),
+                                datetime.timedelta(days=-1, seconds=75600): {
+                                    "America/Asuncion"
+                                },
+                            },
+                        ),
+                        datetime.timedelta(days=-1, seconds=75600): {
+                            "America/Glace_Bay"
+                        },
+                    },
+                ),
+                datetime.timedelta(days=-1, seconds=75600): (
+                    datetime.datetime(1973, 4, 30, 0, 0),
+                    {
+                        datetime.timedelta(days=-1, seconds=72000): {"America/Moncton"},
+                        datetime.timedelta(days=-1, seconds=75600): (
+                            datetime.datetime(1988, 4, 3, 15, 0),
+                            {
+                                datetime.timedelta(days=-1, seconds=75600): {
+                                    "America/Halifax",
+                                    "Canada/Atlantic",
+                                },
+                                datetime.timedelta(days=-1, seconds=79200): {
+                                    "America/Goose_Bay"
+                                },
+                            },
+                        ),
+                    },
+                ),
+            },
+        ),
+        datetime.timedelta(days=-1, seconds=72900): {"America/Guyana"},
+        datetime.timedelta(days=-1, seconds=73800): (
+            datetime.datetime(1970, 4, 26, 15, 0),
+            {
+                datetime.timedelta(days=-1, seconds=73800): {"America/Paramaribo"},
+                datetime.timedelta(days=-1, seconds=77400): {
+                    "America/St_Johns",
+                    "Canada/Newfoundland",
+                },
+            },
+        ),
+        datetime.timedelta(days=-1, seconds=75600): (
+            datetime.datetime(1970, 3, 29, 15, 0),
+            {
+                datetime.timedelta(days=-1, seconds=72000): (
+                    datetime.datetime(2017, 5, 14, 18, 0),
+                    {
+                        datetime.timedelta(days=-1, seconds=72000): {
+                            "America/Santiago",
+                            "Chile/Continental",
+                        },
+                        datetime.timedelta(days=-1, seconds=75600): {
+                            "America/Punta_Arenas"
+                        },
+                    },
+                ),
+                datetime.timedelta(days=-1, seconds=75600): (
+                    datetime.datetime(1970, 4, 25, 18, 0),
+                    {
+                        datetime.timedelta(days=-1, seconds=75600): (
+                            datetime.datetime(1974, 1, 23, 21, 0),
+                            {
+                                datetime.timedelta(days=-1, seconds=75600): (
+                                    datetime.datetime(1980, 4, 7, 0, 0),
+                                    {
+                                        datetime.timedelta(days=-1, seconds=75600): (
+                                            datetime.datetime(1985, 11, 3, 0, 0),
+                                            {
+                                                datetime.timedelta(
+                                                    days=-1, seconds=75600
+                                                ): {"America/Cayenne", "Etc/GMT+3"},
+                                                datetime.timedelta(
+                                                    days=-1, seconds=79200
+                                                ): (
+                                                    datetime.datetime(
+                                                        1988, 10, 16, 15, 0
+                                                    ),
+                                                    {
+                                                        datetime.timedelta(
+                                                            days=-1, seconds=75600
+                                                        ): {"America/Belem"},
+                                                        datetime.timedelta(
+                                                            days=-1, seconds=79200
+                                                        ): (
+                                                            datetime.datetime(
+                                                                1990, 10, 22, 0, 0
+                                                            ),
+                                                            {
+                                                                datetime.timedelta(
+                                                                    days=-1,
+                                                                    seconds=75600,
+                                                                ): (
+                                                                    datetime.datetime(
+                                                                        1995,
+                                                                        10,
+                                                                        15,
+                                                                        15,
+                                                                        0,
+                                                                    ),
+                                                                    {
+                                                                        datetime.timedelta(
+                                                                            days=-1,
+                                                                            seconds=75600,
+                                                                        ): (
+                                                                            datetime.datetime(
+                                                                                2000,
+                                                                                10,
+                                                                                15,
+                                                                                12,
+                                                                                0,
+                                                                            ),
+                                                                            {
+                                                                                datetime.timedelta(
+                                                                                    days=-1,
+                                                                                    seconds=75600,
+                                                                                ): {
+                                                                                    "America/Recife"
+                                                                                },
+                                                                                datetime.timedelta(
+                                                                                    days=-1,
+                                                                                    seconds=79200,
+                                                                                ): {
+                                                                                    "America/Fortaleza"
+                                                                                },
+                                                                            },
+                                                                        ),
+                                                                        datetime.timedelta(
+                                                                            days=-1,
+                                                                            seconds=79200,
+                                                                        ): (
+                                                                            datetime.datetime(
+                                                                                1996,
+                                                                                10,
+                                                                                6,
+                                                                                18,
+                                                                                0,
+                                                                            ),
+                                                                            {
+                                                                                datetime.timedelta(
+                                                                                    days=-1,
+                                                                                    seconds=75600,
+                                                                                ): {
+                                                                                    "America/Maceio"
+                                                                                },
+                                                                                datetime.timedelta(
+                                                                                    days=-1,
+                                                                                    seconds=79200,
+                                                                                ): {
+                                                                                    "America/Araguaina"
+                                                                                },
+                                                                            },
+                                                                        ),
+                                                                    },
+                                                                ),
+                                                                datetime.timedelta(
+                                                                    days=-1,
+                                                                    seconds=79200,
+                                                                ): (
+                                                                    datetime.datetime(
+                                                                        2003,
+                                                                        10,
+                                                                        19,
+                                                                        21,
+                                                                        0,
+                                                                    ),
+                                                                    {
+                                                                        datetime.timedelta(
+                                                                            days=-1,
+                                                                            seconds=75600,
+                                                                        ): {
+                                                                            "America/Bahia"
+                                                                        },
+                                                                        datetime.timedelta(
+                                                                            days=-1,
+                                                                            seconds=79200,
+                                                                        ): {
+                                                                            "America/Sao_Paulo",
+                                                                            "Brazil/East",
+                                                                        },
+                                                                    },
+                                                                ),
+                                                            },
+                                                        ),
+                                                    },
+                                                ),
+                                            },
+                                        ),
+                                        datetime.timedelta(days=-1, seconds=79200): (
+                                            datetime.datetime(1996, 1, 2, 0, 0),
+                                            {
+                                                datetime.timedelta(
+                                                    days=-1, seconds=75600
+                                                ): {"America/Godthab", "America/Nuuk"},
+                                                datetime.timedelta(0): {
+                                                    "America/Danmarkshavn"
+                                                },
+                                            },
+                                        ),
+                                    },
+                                ),
+                                datetime.timedelta(days=-1, seconds=79200): (
+                                    datetime.datetime(1982, 5, 1, 21, 0),
+                                    {
+                                        datetime.timedelta(days=-1, seconds=72000): {
+                                            "Antarctica/Palmer"
+                                        },
+                                        datetime.timedelta(days=-1, seconds=75600): (
+                                            datetime.datetime(1990, 3, 4, 21, 0),
+                                            {
+                                                datetime.timedelta(
+                                                    days=-1, seconds=72000
+                                                ): (
+                                                    datetime.datetime(
+                                                        1990, 10, 16, 0, 0
+                                                    ),
+                                                    {
+                                                        datetime.timedelta(
+                                                            days=-1, seconds=72000
+                                                        ): {
+                                                            "America/Argentina/Jujuy",
+                                                            "America/Jujuy",
+                                                        },
+                                                        datetime.timedelta(
+                                                            days=-1, seconds=75600
+                                                        ): {
+                                                            "America/Argentina/Mendoza",
+                                                            "America/Mendoza",
+                                                        },
+                                                    },
+                                                ),
+                                                datetime.timedelta(
+                                                    days=-1, seconds=75600
+                                                ): (
+                                                    datetime.datetime(
+                                                        1991, 3, 1, 15, 0
+                                                    ),
+                                                    {
+                                                        datetime.timedelta(
+                                                            days=-1, seconds=72000
+                                                        ): (
+                                                            datetime.datetime(
+                                                                2004, 6, 20, 18, 0
+                                                            ),
+                                                            {
+                                                                datetime.timedelta(
+                                                                    days=-1,
+                                                                    seconds=72000,
+                                                                ): {
+                                                                    "America/Argentina/San_Juan"
+                                                                },
+                                                                datetime.timedelta(
+                                                                    days=-1,
+                                                                    seconds=75600,
+                                                                ): {
+                                                                    "America/Argentina/La_Rioja"
+                                                                },
+                                                            },
+                                                        ),
+                                                        datetime.timedelta(
+                                                            days=-1, seconds=79200
+                                                        ): (
+                                                            datetime.datetime(
+                                                                1991, 3, 4, 0, 0
+                                                            ),
+                                                            {
+                                                                datetime.timedelta(
+                                                                    days=-1,
+                                                                    seconds=72000,
+                                                                ): (
+                                                                    datetime.datetime(
+                                                                        2004,
+                                                                        6,
+                                                                        1,
+                                                                        12,
+                                                                        0,
+                                                                    ),
+                                                                    {
+                                                                        datetime.timedelta(
+                                                                            days=-1,
+                                                                            seconds=72000,
+                                                                        ): (
+                                                                            datetime.datetime(
+                                                                                2004,
+                                                                                6,
+                                                                                14,
+                                                                                0,
+                                                                                0,
+                                                                            ),
+                                                                            {
+                                                                                datetime.timedelta(
+                                                                                    days=-1,
+                                                                                    seconds=72000,
+                                                                                ): {
+                                                                                    "America/Argentina/Catamarca",
+                                                                                    "America/Argentina/ComodRivadavia",
+                                                                                    "America/Catamarca",
+                                                                                },
+                                                                                datetime.timedelta(
+                                                                                    days=-1,
+                                                                                    seconds=75600,
+                                                                                ): {
+                                                                                    "America/Argentina/Tucuman"
+                                                                                },
+                                                                            },
+                                                                        ),
+                                                                        datetime.timedelta(
+                                                                            days=-1,
+                                                                            seconds=75600,
+                                                                        ): (
+                                                                            datetime.datetime(
+                                                                                2008,
+                                                                                10,
+                                                                                19,
+                                                                                15,
+                                                                                0,
+                                                                            ),
+                                                                            {
+                                                                                datetime.timedelta(
+                                                                                    days=-1,
+                                                                                    seconds=75600,
+                                                                                ): {
+                                                                                    "America/Argentina/Salta"
+                                                                                },
+                                                                                datetime.timedelta(
+                                                                                    days=-1,
+                                                                                    seconds=79200,
+                                                                                ): {
+                                                                                    "America/Argentina/Cordoba",
+                                                                                    "America/Cordoba",
+                                                                                    "America/Rosario",
+                                                                                },
+                                                                            },
+                                                                        ),
+                                                                    },
+                                                                ),
+                                                                datetime.timedelta(
+                                                                    days=-1,
+                                                                    seconds=75600,
+                                                                ): (
+                                                                    datetime.datetime(
+                                                                        2004,
+                                                                        5,
+                                                                        30,
+                                                                        15,
+                                                                        0,
+                                                                    ),
+                                                                    {
+                                                                        datetime.timedelta(
+                                                                            days=-1,
+                                                                            seconds=72000,
+                                                                        ): {
+                                                                            "America/Argentina/Ushuaia"
+                                                                        },
+                                                                        datetime.timedelta(
+                                                                            days=-1,
+                                                                            seconds=75600,
+                                                                        ): (
+                                                                            datetime.datetime(
+                                                                                2004,
+                                                                                6,
+                                                                                1,
+                                                                                12,
+                                                                                0,
+                                                                            ),
+                                                                            {
+                                                                                datetime.timedelta(
+                                                                                    days=-1,
+                                                                                    seconds=72000,
+                                                                                ): {
+                                                                                    "America/Argentina/Rio_Gallegos"
+                                                                                },
+                                                                                datetime.timedelta(
+                                                                                    days=-1,
+                                                                                    seconds=75600,
+                                                                                ): {
+                                                                                    "America/Argentina/Buenos_Aires",
+                                                                                    "America/Buenos_Aires",
+                                                                                },
+                                                                            },
+                                                                        ),
+                                                                    },
+                                                                ),
+                                                            },
+                                                        ),
+                                                    },
+                                                ),
+                                                datetime.timedelta(
+                                                    days=-1, seconds=79200
+                                                ): {"America/Argentina/San_Luis"},
+                                            },
+                                        ),
+                                    },
+                                ),
+                            },
+                        ),
+                        datetime.timedelta(days=-1, seconds=79200): {
+                            "America/Montevideo"
+                        },
+                    },
+                ),
+            },
+        ),
+        datetime.timedelta(days=-1, seconds=79200): (
+            datetime.datetime(1975, 11, 25, 18, 0),
+            {
+                datetime.timedelta(days=-1, seconds=79200): (
+                    datetime.datetime(1980, 4, 6, 21, 0),
+                    {
+                        datetime.timedelta(days=-1, seconds=79200): (
+                            datetime.datetime(1985, 11, 2, 21, 0),
+                            {
+                                datetime.timedelta(days=-1, seconds=79200): {
+                                    "Atlantic/South_Georgia",
+                                    "Etc/GMT+2",
+                                },
+                                datetime.timedelta(days=-1, seconds=82800): {
+                                    "America/Noronha",
+                                    "Brazil/DeNoronha",
+                                },
+                            },
+                        ),
+                        datetime.timedelta(days=-1, seconds=82800): {
+                            "America/Scoresbysund"
+                        },
+                    },
+                ),
+                datetime.timedelta(days=-1, seconds=82800): {"Atlantic/Cape_Verde"},
+            },
+        ),
+        datetime.timedelta(days=-1, seconds=82800): (
+            datetime.datetime(1975, 1, 1, 15, 0),
+            {
+                datetime.timedelta(days=-1, seconds=82800): (
+                    datetime.datetime(1976, 4, 15, 0, 0),
+                    {
+                        datetime.timedelta(days=-1, seconds=82800): (
+                            datetime.datetime(1982, 3, 29, 0, 0),
+                            {
+                                datetime.timedelta(days=-1, seconds=82800): {
+                                    "Etc/GMT+1"
+                                },
+                                datetime.timedelta(0): {"Atlantic/Azores"},
+                            },
+                        ),
+                        datetime.timedelta(0): {"Africa/El_Aaiun"},
+                    },
+                ),
+                datetime.timedelta(0): {"Africa/Bissau"},
+            },
+        ),
+        datetime.timedelta(days=-1, seconds=83730): {"Africa/Monrovia"},
+        datetime.timedelta(days=-1, seconds=83760): {"Africa/Monrovia"},
+        datetime.timedelta(0): (
+            datetime.datetime(1971, 4, 26, 12, 0),
+            {
+                datetime.timedelta(0): (
+                    datetime.datetime(1974, 6, 25, 0, 0),
+                    {
+                        datetime.timedelta(0): (
+                            datetime.datetime(1976, 12, 1, 15, 0),
+                            {
+                                datetime.timedelta(days=-1, seconds=75600): {
+                                    "Antarctica/Rothera"
+                                },
+                                datetime.timedelta(0): (
+                                    datetime.datetime(1977, 4, 4, 0, 0),
+                                    {
+                                        datetime.timedelta(0): (
+                                            datetime.datetime(1980, 4, 6, 15, 0),
+                                            {
+                                                datetime.timedelta(0): (
+                                                    datetime.datetime(
+                                                        1981, 3, 29, 18, 0
+                                                    ),
+                                                    {
+                                                        datetime.timedelta(0): (
+                                                            datetime.datetime(
+                                                                1982, 4, 4, 15, 0
+                                                            ),
+                                                            {
+                                                                datetime.timedelta(0): (
+                                                                    datetime.datetime(
+                                                                        2005,
+                                                                        3,
+                                                                        27,
+                                                                        15,
+                                                                        0,
+                                                                    ),
+                                                                    {
+                                                                        datetime.timedelta(
+                                                                            0
+                                                                        ): (
+                                                                            datetime.datetime(
+                                                                                2018,
+                                                                                1,
+                                                                                1,
+                                                                                18,
+                                                                                0,
+                                                                            ),
+                                                                            {
+                                                                                datetime.timedelta(
+                                                                                    0
+                                                                                ): {
+                                                                                    "Africa/Abidjan",
+                                                                                    "Africa/Accra",
+                                                                                    "Africa/Bamako",
+                                                                                    "Africa/Banjul",
+                                                                                    "Africa/Conakry",
+                                                                                    "Africa/Dakar",
+                                                                                    "Africa/Freetown",
+                                                                                    "Africa/Lome",
+                                                                                    "Africa/Nouakchott",
+                                                                                    "Africa/Ouagadougou",
+                                                                                    "Africa/Timbuktu",
+                                                                                    "Atlantic/Reykjavik",
+                                                                                    "Atlantic/St_Helena",
+                                                                                    "Etc/GMT",
+                                                                                    "Etc/GMT+0",
+                                                                                    "Etc/GMT-0",
+                                                                                    "Etc/GMT0",
+                                                                                    "Etc/Greenwich",
+                                                                                    "Etc/UCT",
+                                                                                    "Etc/UTC",
+                                                                                    "Etc/Universal",
+                                                                                    "Etc/Zulu",
+                                                                                    "GMT",
+                                                                                    "GMT+0",
+                                                                                    "GMT-0",
+                                                                                    "GMT0",
+                                                                                    "Greenwich",
+                                                                                    "Iceland",
+                                                                                    "UCT",
+                                                                                    "UTC",
+                                                                                    "Universal",
+                                                                                    "Zulu",
+                                                                                },
+                                                                                datetime.timedelta(
+                                                                                    seconds=3600
+                                                                                ): {
+                                                                                    "Africa/Sao_Tome"
+                                                                                },
+                                                                            },
+                                                                        ),
+                                                                        datetime.timedelta(
+                                                                            seconds=7200
+                                                                        ): {
+                                                                            "Antarctica/Troll"
+                                                                        },
+                                                                    },
+                                                                ),
+                                                                datetime.timedelta(
+                                                                    seconds=3600
+                                                                ): {"Atlantic/Madeira"},
+                                                            },
+                                                        ),
+                                                        datetime.timedelta(
+                                                            seconds=3600
+                                                        ): {
+                                                            "Atlantic/Faeroe",
+                                                            "Atlantic/Faroe",
+                                                        },
+                                                    },
+                                                ),
+                                                datetime.timedelta(seconds=3600): {
+                                                    "Atlantic/Canary"
+                                                },
+                                            },
+                                        ),
+                                        datetime.timedelta(seconds=3600): {"WET"},
+                                    },
+                                ),
+                            },
+                        ),
+                        datetime.timedelta(seconds=3600): (
+                            datetime.datetime(1986, 1, 1, 12, 0),
+                            {
+                                datetime.timedelta(0): {"Africa/Casablanca"},
+                                datetime.timedelta(seconds=3600): {"Africa/Ceuta"},
+                            },
+                        ),
+                    },
+                ),
+                datetime.timedelta(seconds=3600): {"Africa/Algiers"},
+            },
+        ),
+        datetime.timedelta(seconds=3600): (
+            datetime.datetime(1970, 6, 1, 0, 0),
+            {
+                datetime.timedelta(seconds=3600): (
+                    datetime.datetime(1971, 11, 1, 0, 0),
+                    {
+                        datetime.timedelta(0): {
+                            "Eire",
+                            "Europe/Belfast",
+                            "Europe/Dublin",
+                            "Europe/Guernsey",
+                            "Europe/Isle_of_Man",
+                            "Europe/Jersey",
+                            "Europe/London",
+                            "GB",
+                            "GB-Eire",
+                        },
+                        datetime.timedelta(seconds=3600): (
+                            datetime.datetime(1974, 4, 14, 15, 0),
+                            {
+                                datetime.timedelta(seconds=3600): (
+                                    datetime.datetime(1974, 5, 4, 21, 0),
+                                    {
+                                        datetime.timedelta(seconds=3600): (
+                                            datetime.datetime(1976, 3, 28, 21, 0),
+                                            {
+                                                datetime.timedelta(seconds=3600): (
+                                                    datetime.datetime(
+                                                        1976, 9, 26, 21, 0
+                                                    ),
+                                                    {
+                                                        datetime.timedelta(0): (
+                                                            datetime.datetime(
+                                                                1980, 3, 30, 18, 0
+                                                            ),
+                                                            {
+                                                                datetime.timedelta(0): {
+                                                                    "Europe/Lisbon",
+                                                                    "Portugal",
+                                                                    "WET",
+                                                                },
+                                                                datetime.timedelta(
+                                                                    seconds=3600
+                                                                ): {"Portugal"},
+                                                            },
+                                                        ),
+                                                        datetime.timedelta(
+                                                            seconds=3600
+                                                        ): (
+                                                            datetime.datetime(
+                                                                1977, 4, 3, 18, 0
+                                                            ),
+                                                            {
+                                                                datetime.timedelta(
+                                                                    seconds=3600
+                                                                ): (
+                                                                    datetime.datetime(
+                                                                        1977,
+                                                                        4,
+                                                                        30,
+                                                                        21,
+                                                                        0,
+                                                                    ),
+                                                                    {
+                                                                        datetime.timedelta(
+                                                                            seconds=3600
+                                                                        ): (
+                                                                            datetime.datetime(
+                                                                                1979,
+                                                                                4,
+                                                                                1,
+                                                                                18,
+                                                                                0,
+                                                                            ),
+                                                                            {
+                                                                                datetime.timedelta(
+                                                                                    seconds=3600
+                                                                                ): (
+                                                                                    datetime.datetime(
+                                                                                        1979,
+                                                                                        10,
+                                                                                        15,
+                                                                                        0,
+                                                                                        0,
+                                                                                    ),
+                                                                                    {
+                                                                                        datetime.timedelta(
+                                                                                            seconds=3600
+                                                                                        ): (
+                                                                                            datetime.datetime(
+                                                                                                1980,
+                                                                                                4,
+                                                                                                6,
+                                                                                                15,
+                                                                                                0,
+                                                                                            ),
+                                                                                            {
+                                                                                                datetime.timedelta(
+                                                                                                    seconds=3600
+                                                                                                ): (
+                                                                                                    datetime.datetime(
+                                                                                                        1981,
+                                                                                                        3,
+                                                                                                        29,
+                                                                                                        18,
+                                                                                                        0,
+                                                                                                    ),
+                                                                                                    {
+                                                                                                        datetime.timedelta(
+                                                                                                            seconds=3600
+                                                                                                        ): (
+                                                                                                            datetime.datetime(
+                                                                                                                1982,
+                                                                                                                3,
+                                                                                                                28,
+                                                                                                                18,
+                                                                                                                0,
+                                                                                                            ),
+                                                                                                            {
+                                                                                                                datetime.timedelta(
+                                                                                                                    seconds=3600
+                                                                                                                ): (
+                                                                                                                    datetime.datetime(
+                                                                                                                        1983,
+                                                                                                                        3,
+                                                                                                                        27,
+                                                                                                                        18,
+                                                                                                                        0,
+                                                                                                                    ),
+                                                                                                                    {
+                                                                                                                        datetime.timedelta(
+                                                                                                                            seconds=3600
+                                                                                                                        ): (
+                                                                                                                            datetime.datetime(
+                                                                                                                                1985,
+                                                                                                                                4,
+                                                                                                                                1,
+                                                                                                                                0,
+                                                                                                                                0,
+                                                                                                                            ),
+                                                                                                                            {
+                                                                                                                                datetime.timedelta(
+                                                                                                                                    seconds=3600
+                                                                                                                                ): {
+                                                                                                                                    "Africa/Bangui",
+                                                                                                                                    "Africa/Brazzaville",
+                                                                                                                                    "Africa/Douala",
+                                                                                                                                    "Africa/Kinshasa",
+                                                                                                                                    "Africa/Lagos",
+                                                                                                                                    "Africa/Libreville",
+                                                                                                                                    "Africa/Luanda",
+                                                                                                                                    "Africa/Malabo",
+                                                                                                                                    "Africa/Niamey",
+                                                                                                                                    "Africa/Porto-Novo",
+                                                                                                                                    "Etc/GMT-1",
+                                                                                                                                },
+                                                                                                                                datetime.timedelta(
+                                                                                                                                    seconds=7200
+                                                                                                                                ): {
+                                                                                                                                    "Europe/Andorra"
+                                                                                                                                },
+                                                                                                                            },
+                                                                                                                        ),
+                                                                                                                        datetime.timedelta(
+                                                                                                                            seconds=7200
+                                                                                                                        ): {
+                                                                                                                            "Europe/Belgrade",
+                                                                                                                            "Europe/Ljubljana",
+                                                                                                                            "Europe/Podgorica",
+                                                                                                                            "Europe/Sarajevo",
+                                                                                                                            "Europe/Skopje",
+                                                                                                                            "Europe/Zagreb",
+                                                                                                                        },
+                                                                                                                    },
+                                                                                                                ),
+                                                                                                                datetime.timedelta(
+                                                                                                                    seconds=7200
+                                                                                                                ): {
+                                                                                                                    "Europe/Gibraltar"
+                                                                                                                },
+                                                                                                            },
+                                                                                                        ),
+                                                                                                        datetime.timedelta(
+                                                                                                            seconds=7200
+                                                                                                        ): {
+                                                                                                            "Europe/Busingen",
+                                                                                                            "Europe/Vaduz",
+                                                                                                            "Europe/Zurich",
+                                                                                                        },
+                                                                                                    },
+                                                                                                ),
+                                                                                                datetime.timedelta(
+                                                                                                    seconds=7200
+                                                                                                ): {
+                                                                                                    "Arctic/Longyearbyen",
+                                                                                                    "Atlantic/Jan_Mayen",
+                                                                                                    "Europe/Berlin",
+                                                                                                    "Europe/Budapest",
+                                                                                                    "Europe/Copenhagen",
+                                                                                                    "Europe/Oslo",
+                                                                                                    "Europe/Stockholm",
+                                                                                                    "Europe/Vienna",
+                                                                                                },
+                                                                                            },
+                                                                                        ),
+                                                                                        datetime.timedelta(
+                                                                                            seconds=7200
+                                                                                        ): {
+                                                                                            "Africa/Ndjamena"
+                                                                                        },
+                                                                                    },
+                                                                                ),
+                                                                                datetime.timedelta(
+                                                                                    seconds=7200
+                                                                                ): {
+                                                                                    "Europe/Bratislava",
+                                                                                    "Europe/Prague",
+                                                                                },
+                                                                            },
+                                                                        ),
+                                                                        datetime.timedelta(
+                                                                            seconds=7200
+                                                                        ): {
+                                                                            "Africa/Tunis"
+                                                                        },
+                                                                    },
+                                                                ),
+                                                                datetime.timedelta(
+                                                                    seconds=7200
+                                                                ): {
+                                                                    "CET",
+                                                                    "Europe/Amsterdam",
+                                                                    "Europe/Brussels",
+                                                                    "Europe/Luxembourg",
+                                                                    "Europe/Warsaw",
+                                                                    "MET",
+                                                                    "Poland",
+                                                                },
+                                                            },
+                                                        ),
+                                                    },
+                                                ),
+                                                datetime.timedelta(seconds=7200): {
+                                                    "Europe/Monaco",
+                                                    "Europe/Paris",
+                                                },
+                                            },
+                                        ),
+                                        datetime.timedelta(seconds=7200): {
+                                            "Europe/Tirane"
+                                        },
+                                    },
+                                ),
+                                datetime.timedelta(seconds=7200): {"Europe/Madrid"},
+                            },
+                        ),
+                    },
+                ),
+                datetime.timedelta(seconds=7200): (
+                    datetime.datetime(1973, 3, 31, 18, 0),
+                    {
+                        datetime.timedelta(seconds=3600): {
+                            "Europe/Rome",
+                            "Europe/San_Marino",
+                            "Europe/Vatican",
+                        },
+                        datetime.timedelta(seconds=7200): {"Europe/Malta"},
+                    },
+                ),
+            },
+        ),
+        datetime.timedelta(seconds=7200): (
+            datetime.datetime(1970, 5, 1, 15, 0),
+            {
+                datetime.timedelta(seconds=7200): (
+                    datetime.datetime(1972, 6, 23, 0, 0),
+                    {
+                        datetime.timedelta(seconds=7200): (
+                            datetime.datetime(1973, 6, 3, 15, 0),
+                            {
+                                datetime.timedelta(seconds=7200): (
+                                    datetime.datetime(1973, 6, 6, 21, 0),
+                                    {
+                                        datetime.timedelta(seconds=7200): (
+                                            datetime.datetime(1974, 7, 8, 0, 0),
+                                            {
+                                                datetime.timedelta(seconds=7200): (
+                                                    datetime.datetime(
+                                                        1975, 4, 13, 18, 0
+                                                    ),
+                                                    {
+                                                        datetime.timedelta(
+                                                            seconds=7200
+                                                        ): (
+                                                            datetime.datetime(
+                                                                1977, 4, 3, 18, 0
+                                                            ),
+                                                            {
+                                                                datetime.timedelta(
+                                                                    seconds=7200
+                                                                ): (
+                                                                    datetime.datetime(
+                                                                        1979,
+                                                                        4,
+                                                                        1,
+                                                                        15,
+                                                                        0,
+                                                                    ),
+                                                                    {
+                                                                        datetime.timedelta(
+                                                                            seconds=7200
+                                                                        ): (
+                                                                            datetime.datetime(
+                                                                                1979,
+                                                                                5,
+                                                                                27,
+                                                                                15,
+                                                                                0,
+                                                                            ),
+                                                                            {
+                                                                                datetime.timedelta(
+                                                                                    seconds=7200
+                                                                                ): (
+                                                                                    datetime.datetime(
+                                                                                        1981,
+                                                                                        3,
+                                                                                        29,
+                                                                                        15,
+                                                                                        0,
+                                                                                    ),
+                                                                                    {
+                                                                                        datetime.timedelta(
+                                                                                            seconds=7200
+                                                                                        ): (
+                                                                                            datetime.datetime(
+                                                                                                1982,
+                                                                                                1,
+                                                                                                1,
+                                                                                                21,
+                                                                                                0,
+                                                                                            ),
+                                                                                            {
+                                                                                                datetime.timedelta(
+                                                                                                    seconds=3600
+                                                                                                ): {
+                                                                                                    "Africa/Tripoli",
+                                                                                                    "Libya",
+                                                                                                },
+                                                                                                datetime.timedelta(
+                                                                                                    seconds=7200
+                                                                                                ): (
+                                                                                                    datetime.datetime(
+                                                                                                        1994,
+                                                                                                        3,
+                                                                                                        21,
+                                                                                                        18,
+                                                                                                        0,
+                                                                                                    ),
+                                                                                                    {
+                                                                                                        datetime.timedelta(
+                                                                                                            seconds=3600
+                                                                                                        ): {
+                                                                                                            "Africa/Windhoek"
+                                                                                                        },
+                                                                                                        datetime.timedelta(
+                                                                                                            seconds=7200
+                                                                                                        ): {
+                                                                                                            "Africa/Blantyre",
+                                                                                                            "Africa/Bujumbura",
+                                                                                                            "Africa/Gaborone",
+                                                                                                            "Africa/Harare",
+                                                                                                            "Africa/Johannesburg",
+                                                                                                            "Africa/Kigali",
+                                                                                                            "Africa/Lubumbashi",
+                                                                                                            "Africa/Lusaka",
+                                                                                                            "Africa/Maputo",
+                                                                                                            "Africa/Maseru",
+                                                                                                            "Africa/Mbabane",
+                                                                                                            "Etc/GMT-2",
+                                                                                                        },
+                                                                                                    },
+                                                                                                ),
+                                                                                            },
+                                                                                        ),
+                                                                                        datetime.timedelta(
+                                                                                            seconds=10800
+                                                                                        ): {
+                                                                                            "Europe/Helsinki",
+                                                                                            "Europe/Mariehamn",
+                                                                                        },
+                                                                                    },
+                                                                                ),
+                                                                                datetime.timedelta(
+                                                                                    seconds=10800
+                                                                                ): {
+                                                                                    "Europe/Bucharest"
+                                                                                },
+                                                                            },
+                                                                        ),
+                                                                        datetime.timedelta(
+                                                                            seconds=10800
+                                                                        ): {
+                                                                            "Europe/Sofia"
+                                                                        },
+                                                                    },
+                                                                ),
+                                                                datetime.timedelta(
+                                                                    seconds=10800
+                                                                ): {"EET"},
+                                                            },
+                                                        ),
+                                                        datetime.timedelta(
+                                                            seconds=10800
+                                                        ): (
+                                                            datetime.datetime(
+                                                                1975, 10, 12, 18, 0
+                                                            ),
+                                                            {
+                                                                datetime.timedelta(
+                                                                    seconds=7200
+                                                                ): (
+                                                                    datetime.datetime(
+                                                                        2016,
+                                                                        10,
+                                                                        31,
+                                                                        3,
+                                                                        0,
+                                                                    ),
+                                                                    {
+                                                                        datetime.timedelta(
+                                                                            seconds=7200
+                                                                        ): {
+                                                                            "Asia/Nicosia",
+                                                                            "Europe/Nicosia",
+                                                                        },
+                                                                        datetime.timedelta(
+                                                                            seconds=10800
+                                                                        ): {
+                                                                            "Asia/Famagusta"
+                                                                        },
+                                                                    },
+                                                                ),
+                                                                datetime.timedelta(
+                                                                    seconds=10800
+                                                                ): {
+                                                                    "EET",
+                                                                    "Europe/Athens",
+                                                                },
+                                                            },
+                                                        ),
+                                                    },
+                                                ),
+                                                datetime.timedelta(seconds=10800): (
+                                                    datetime.datetime(
+                                                        1996, 3, 15, 21, 0
+                                                    ),
+                                                    {
+                                                        datetime.timedelta(
+                                                            seconds=7200
+                                                        ): (
+                                                            datetime.datetime(
+                                                                2008, 8, 29, 18, 0
+                                                            ),
+                                                            {
+                                                                datetime.timedelta(
+                                                                    seconds=7200
+                                                                ): {"Asia/Gaza"},
+                                                                datetime.timedelta(
+                                                                    seconds=10800
+                                                                ): {"Asia/Hebron"},
+                                                            },
+                                                        ),
+                                                        datetime.timedelta(
+                                                            seconds=10800
+                                                        ): {
+                                                            "Asia/Jerusalem",
+                                                            "Asia/Tel_Aviv",
+                                                            "Israel",
+                                                        },
+                                                    },
+                                                ),
+                                            },
+                                        ),
+                                        datetime.timedelta(seconds=10800): {
+                                            "Asia/Amman"
+                                        },
+                                    },
+                                ),
+                                datetime.timedelta(seconds=10800): {
+                                    "Asia/Istanbul",
+                                    "Europe/Istanbul",
+                                    "Turkey",
+                                },
+                            },
+                        ),
+                        datetime.timedelta(seconds=10800): {"Asia/Beirut"},
+                    },
+                ),
+                datetime.timedelta(seconds=10800): (
+                    datetime.datetime(1970, 10, 1, 18, 0),
+                    {
+                        datetime.timedelta(seconds=7200): (
+                            datetime.datetime(1977, 9, 2, 0, 0),
+                            {
+                                datetime.timedelta(seconds=7200): {"Asia/Damascus"},
+                                datetime.timedelta(seconds=10800): {
+                                    "Africa/Cairo",
+                                    "Egypt",
+                                },
+                            },
+                        ),
+                        datetime.timedelta(seconds=10800): (
+                            datetime.datetime(2017, 11, 1, 18, 0),
+                            {
+                                datetime.timedelta(seconds=7200): {"Africa/Khartoum"},
+                                datetime.timedelta(seconds=10800): {"Africa/Juba"},
+                            },
+                        ),
+                    },
+                ),
+            },
+        ),
+        datetime.timedelta(seconds=10800): (
+            datetime.datetime(1981, 4, 1, 15, 0),
+            {
+                datetime.timedelta(seconds=10800): (
+                    datetime.datetime(1982, 5, 1, 18, 0),
+                    {
+                        datetime.timedelta(seconds=10800): {
+                            "Africa/Addis_Ababa",
+                            "Africa/Asmara",
+                            "Africa/Asmera",
+                            "Africa/Dar_es_Salaam",
+                            "Africa/Djibouti",
+                            "Africa/Kampala",
+                            "Africa/Mogadishu",
+                            "Africa/Nairobi",
+                            "Antarctica/Syowa",
+                            "Asia/Aden",
+                            "Asia/Kuwait",
+                            "Asia/Riyadh",
+                            "Etc/GMT-3",
+                            "Indian/Antananarivo",
+                            "Indian/Comoro",
+                            "Indian/Mayotte",
+                        },
+                        datetime.timedelta(seconds=14400): {"Asia/Baghdad"},
+                    },
+                ),
+                datetime.timedelta(seconds=14400): (
+                    datetime.datetime(1989, 3, 26, 21, 0),
+                    {
+                        datetime.timedelta(seconds=10800): (
+                            datetime.datetime(1996, 9, 29, 15, 0),
+                            {
+                                datetime.timedelta(seconds=7200): {"Europe/Riga"},
+                                datetime.timedelta(seconds=10800): (
+                                    datetime.datetime(1998, 3, 29, 15, 0),
+                                    {
+                                        datetime.timedelta(seconds=7200): {
+                                            "Europe/Vilnius"
+                                        },
+                                        datetime.timedelta(seconds=10800): (
+                                            datetime.datetime(2000, 3, 26, 21, 0),
+                                            {
+                                                datetime.timedelta(seconds=7200): {
+                                                    "Europe/Tallinn"
+                                                },
+                                                datetime.timedelta(seconds=10800): {
+                                                    "Europe/Kaliningrad"
+                                                },
+                                            },
+                                        ),
+                                    },
+                                ),
+                            },
+                        ),
+                        datetime.timedelta(seconds=14400): (
+                            datetime.datetime(1990, 3, 25, 21, 0),
+                            {
+                                datetime.timedelta(seconds=10800): (
+                                    datetime.datetime(1990, 7, 2, 0, 0),
+                                    {
+                                        datetime.timedelta(seconds=7200): {
+                                            "Europe/Simferopol"
+                                        },
+                                        datetime.timedelta(seconds=10800): {
+                                            "Europe/Minsk"
+                                        },
+                                    },
+                                ),
+                                datetime.timedelta(seconds=14400): (
+                                    datetime.datetime(1990, 5, 6, 15, 0),
+                                    {
+                                        datetime.timedelta(seconds=10800): {
+                                            "Europe/Chisinau",
+                                            "Europe/Tiraspol",
+                                        },
+                                        datetime.timedelta(seconds=14400): (
+                                            datetime.datetime(1990, 7, 1, 15, 0),
+                                            {
+                                                datetime.timedelta(seconds=10800): {
+                                                    "Europe/Kiev",
+                                                    "Europe/Kyiv",
+                                                    "Europe/Uzhgorod",
+                                                    "Europe/Zaporozhye",
+                                                },
+                                                datetime.timedelta(seconds=14400): {
+                                                    "Europe/Moscow",
+                                                    "W-SU",
+                                                },
+                                            },
+                                        ),
+                                    },
+                                ),
+                            },
+                        ),
+                    },
+                ),
+            },
+        ),
+        datetime.timedelta(seconds=12600): {"Iran", "Asia/Tehran"},
+        datetime.timedelta(seconds=14400): (
+            datetime.datetime(1972, 6, 1, 21, 0),
+            {
+                datetime.timedelta(seconds=10800): {"Asia/Bahrain", "Asia/Qatar"},
+                datetime.timedelta(seconds=14400): (
+                    datetime.datetime(1981, 4, 1, 15, 0),
+                    {
+                        datetime.timedelta(seconds=14400): (
+                            datetime.datetime(1982, 10, 11, 0, 0),
+                            {
+                                datetime.timedelta(seconds=14400): {
+                                    "Asia/Dubai",
+                                    "Asia/Muscat",
+                                    "Etc/GMT-4",
+                                    "Indian/Mahe",
+                                    "Indian/Reunion",
+                                },
+                                datetime.timedelta(seconds=18000): {"Indian/Mauritius"},
+                            },
+                        ),
+                        datetime.timedelta(seconds=18000): (
+                            datetime.datetime(1988, 3, 27, 21, 0),
+                            {
+                                datetime.timedelta(seconds=14400): (
+                                    datetime.datetime(2016, 12, 4, 18, 0),
+                                    {
+                                        datetime.timedelta(seconds=10800): {
+                                            "Europe/Volgograd"
+                                        },
+                                        datetime.timedelta(seconds=14400): {
+                                            "Europe/Saratov"
+                                        },
+                                    },
+                                ),
+                                datetime.timedelta(seconds=18000): (
+                                    datetime.datetime(1989, 3, 26, 21, 0),
+                                    {
+                                        datetime.timedelta(seconds=14400): (
+                                            datetime.datetime(1991, 3, 31, 18, 0),
+                                            {
+                                                datetime.timedelta(seconds=10800): (
+                                                    datetime.datetime(
+                                                        1991, 9, 29, 18, 0
+                                                    ),
+                                                    {
+                                                        datetime.timedelta(
+                                                            seconds=7200
+                                                        ): {"Europe/Ulyanovsk"},
+                                                        datetime.timedelta(
+                                                            seconds=10800
+                                                        ): {"Europe/Samara"},
+                                                    },
+                                                ),
+                                                datetime.timedelta(seconds=14400): (
+                                                    datetime.datetime(
+                                                        2016, 3, 27, 18, 0
+                                                    ),
+                                                    {
+                                                        datetime.timedelta(
+                                                            seconds=10800
+                                                        ): {"Europe/Kirov"},
+                                                        datetime.timedelta(
+                                                            seconds=14400
+                                                        ): {"Europe/Astrakhan"},
+                                                    },
+                                                ),
+                                            },
+                                        ),
+                                        datetime.timedelta(seconds=18000): (
+                                            datetime.datetime(1992, 9, 27, 18, 0),
+                                            {
+                                                datetime.timedelta(seconds=10800): (
+                                                    datetime.datetime(
+                                                        1994, 9, 25, 18, 0
+                                                    ),
+                                                    {
+                                                        datetime.timedelta(
+                                                            seconds=10800
+                                                        ): {"Asia/Yerevan"},
+                                                        datetime.timedelta(
+                                                            seconds=14400
+                                                        ): {"Asia/Tbilisi"},
+                                                    },
+                                                ),
+                                                datetime.timedelta(seconds=14400): {
+                                                    "Asia/Baku"
+                                                },
+                                            },
+                                        ),
+                                    },
+                                ),
+                            },
+                        ),
+                    },
+                ),
+            },
+        ),
+        datetime.timedelta(seconds=16200): {"Asia/Kabul"},
+        datetime.timedelta(seconds=18000): (
+            datetime.datetime(1981, 4, 1, 15, 0),
+            {
+                datetime.timedelta(seconds=18000): (
+                    datetime.datetime(1981, 10, 2, 0, 0),
+                    {
+                        datetime.timedelta(seconds=18000): (
+                            datetime.datetime(1996, 1, 1, 21, 0),
+                            {
+                                datetime.timedelta(seconds=18000): (
+                                    datetime.datetime(2002, 4, 8, 0, 0),
+                                    {
+                                        datetime.timedelta(seconds=18000): {
+                                            "Etc/GMT-5",
+                                            "Indian/Kerguelen",
+                                            "Indian/Maldives",
+                                        },
+                                        datetime.timedelta(seconds=21600): {
+                                            "Asia/Karachi"
+                                        },
+                                    },
+                                ),
+                                datetime.timedelta(seconds=21600): {"Indian/Chagos"},
+                            },
+                        ),
+                        datetime.timedelta(seconds=21600): (
+                            datetime.datetime(1994, 9, 26, 3, 0),
+                            {
+                                datetime.timedelta(seconds=14400): {"Asia/Aqtau"},
+                                datetime.timedelta(seconds=18000): {"Asia/Atyrau"},
+                            },
+                        ),
+                    },
+                ),
+                datetime.timedelta(seconds=21600): (
+                    datetime.datetime(1981, 10, 1, 12, 0),
+                    {
+                        datetime.timedelta(seconds=18000): (
+                            datetime.datetime(1992, 3, 29, 18, 0),
+                            {
+                                datetime.timedelta(seconds=18000): {
+                                    "Asia/Ashgabat",
+                                    "Asia/Ashkhabad",
+                                },
+                                datetime.timedelta(seconds=21600): {
+                                    "Asia/Yekaterinburg"
+                                },
+                            },
+                        ),
+                        datetime.timedelta(seconds=21600): (
+                            datetime.datetime(1989, 3, 26, 15, 0),
+                            {
+                                datetime.timedelta(seconds=18000): {"Asia/Oral"},
+                                datetime.timedelta(seconds=21600): (
+                                    datetime.datetime(1991, 4, 1, 0, 0),
+                                    {
+                                        datetime.timedelta(seconds=18000): (
+                                            datetime.datetime(1991, 9, 30, 0, 0),
+                                            {
+                                                datetime.timedelta(seconds=14400): (
+                                                    datetime.datetime(
+                                                        2004, 10, 31, 18, 0
+                                                    ),
+                                                    {
+                                                        datetime.timedelta(
+                                                            seconds=18000
+                                                        ): {"Asia/Aqtobe"},
+                                                        datetime.timedelta(
+                                                            seconds=21600
+                                                        ): {"Asia/Qostanay"},
+                                                    },
+                                                ),
+                                                datetime.timedelta(seconds=18000): {
+                                                    "Asia/Qyzylorda"
+                                                },
+                                            },
+                                        ),
+                                        datetime.timedelta(seconds=21600): {
+                                            "Asia/Samarkand"
+                                        },
+                                    },
+                                ),
+                            },
+                        ),
+                    },
+                ),
+            },
+        ),
+        datetime.timedelta(seconds=19800): (
+            datetime.datetime(1986, 1, 1, 18, 0),
+            {
+                datetime.timedelta(seconds=19800): (
+                    datetime.datetime(1987, 10, 1, 18, 0),
+                    {
+                        datetime.timedelta(seconds=19800): (
+                            datetime.datetime(1996, 5, 25, 15, 0),
+                            {
+                                datetime.timedelta(seconds=19800): {
+                                    "Asia/Calcutta",
+                                    "Asia/Kolkata",
+                                },
+                                datetime.timedelta(seconds=23400): {"Asia/Colombo"},
+                            },
+                        ),
+                        datetime.timedelta(seconds=21600): {
+                            "Asia/Thimbu",
+                            "Asia/Thimphu",
+                        },
+                    },
+                ),
+                datetime.timedelta(seconds=20700): {"Asia/Kathmandu", "Asia/Katmandu"},
+            },
+        ),
+        datetime.timedelta(seconds=21600): (
+            datetime.datetime(1978, 1, 2, 0, 0),
+            {
+                datetime.timedelta(seconds=21600): (
+                    datetime.datetime(1981, 4, 1, 18, 0),
+                    {
+                        datetime.timedelta(seconds=21600): (
+                            datetime.datetime(2009, 6, 20, 18, 0),
+                            {
+                                datetime.timedelta(seconds=21600): (
+                                    datetime.datetime(2009, 10, 18, 21, 0),
+                                    {
+                                        datetime.timedelta(seconds=18000): {
+                                            "Antarctica/Mawson"
+                                        },
+                                        datetime.timedelta(seconds=21600): {
+                                            "Asia/Kashgar",
+                                            "Asia/Urumqi",
+                                            "Etc/GMT-6",
+                                        },
+                                    },
+                                ),
+                                datetime.timedelta(seconds=25200): {
+                                    "Asia/Dacca",
+                                    "Asia/Dhaka",
+                                },
+                            },
+                        ),
+                        datetime.timedelta(seconds=25200): (
+                            datetime.datetime(1991, 8, 31, 21, 0),
+                            {
+                                datetime.timedelta(seconds=18000): {"Asia/Bishkek"},
+                                datetime.timedelta(seconds=21600): (
+                                    datetime.datetime(1991, 9, 9, 15, 0),
+                                    {
+                                        datetime.timedelta(seconds=18000): {
+                                            "Asia/Dushanbe"
+                                        },
+                                        datetime.timedelta(seconds=21600): (
+                                            datetime.datetime(1992, 1, 19, 18, 0),
+                                            {
+                                                datetime.timedelta(seconds=18000): {
+                                                    "Asia/Tashkent"
+                                                },
+                                                datetime.timedelta(seconds=21600): (
+                                                    datetime.datetime(
+                                                        2005, 3, 27, 15, 0
+                                                    ),
+                                                    {
+                                                        datetime.timedelta(
+                                                            seconds=21600
+                                                        ): {"Asia/Almaty"},
+                                                        datetime.timedelta(
+                                                            seconds=25200
+                                                        ): {"Asia/Omsk"},
+                                                    },
+                                                ),
+                                            },
+                                        ),
+                                    },
+                                ),
+                            },
+                        ),
+                    },
+                ),
+                datetime.timedelta(seconds=25200): {"Asia/Hovd"},
+            },
+        ),
+        datetime.timedelta(seconds=23400): {
+            "Asia/Rangoon",
+            "Asia/Yangon",
+            "Indian/Cocos",
+        },
+        datetime.timedelta(seconds=25200): (
+            datetime.datetime(1978, 1, 2, 0, 0),
+            {
+                datetime.timedelta(seconds=25200): (
+                    datetime.datetime(1981, 4, 1, 18, 0),
+                    {
+                        datetime.timedelta(seconds=25200): (
+                            datetime.datetime(1994, 2, 1, 12, 0),
+                            {
+                                datetime.timedelta(0): {"Antarctica/Vostok"},
+                                datetime.timedelta(seconds=25200): (
+                                    datetime.datetime(2009, 10, 18, 21, 0),
+                                    {
+                                        datetime.timedelta(seconds=18000): {
+                                            "Antarctica/Davis"
+                                        },
+                                        datetime.timedelta(seconds=25200): {
+                                            "Asia/Bangkok",
+                                            "Asia/Jakarta",
+                                            "Asia/Phnom_Penh",
+                                            "Asia/Vientiane",
+                                            "Etc/GMT-7",
+                                            "Indian/Christmas",
+                                        },
+                                    },
+                                ),
+                            },
+                        ),
+                        datetime.timedelta(seconds=28800): (
+                            datetime.datetime(1993, 5, 23, 18, 0),
+                            {
+                                datetime.timedelta(seconds=25200): {"Asia/Novosibirsk"},
+                                datetime.timedelta(seconds=28800): (
+                                    datetime.datetime(1995, 5, 28, 18, 0),
+                                    {
+                                        datetime.timedelta(seconds=25200): {
+                                            "Asia/Barnaul"
+                                        },
+                                        datetime.timedelta(seconds=28800): (
+                                            datetime.datetime(2002, 5, 2, 0, 0),
+                                            {
+                                                datetime.timedelta(seconds=25200): {
+                                                    "Asia/Tomsk"
+                                                },
+                                                datetime.timedelta(seconds=28800): (
+                                                    datetime.datetime(
+                                                        2010, 3, 28, 15, 0
+                                                    ),
+                                                    {
+                                                        datetime.timedelta(
+                                                            seconds=25200
+                                                        ): {"Asia/Novokuznetsk"},
+                                                        datetime.timedelta(
+                                                            seconds=28800
+                                                        ): {"Asia/Krasnoyarsk"},
+                                                    },
+                                                ),
+                                            },
+                                        ),
+                                    },
+                                ),
+                            },
+                        ),
+                    },
+                ),
+                datetime.timedelta(seconds=28800): {
+                    "Asia/Choibalsan",
+                    "Asia/Ulaanbaatar",
+                    "Asia/Ulan_Bator",
+                },
+            },
+        ),
+        datetime.timedelta(seconds=27000): {
+            "Asia/Kuala_Lumpur",
+            "Asia/Singapore",
+            "Singapore",
+        },
+        datetime.timedelta(seconds=28800): (
+            datetime.datetime(1970, 4, 19, 18, 0),
+            {
+                datetime.timedelta(seconds=28800): (
+                    datetime.datetime(1974, 4, 1, 15, 0),
+                    {
+                        datetime.timedelta(seconds=28800): (
+                            datetime.datetime(1974, 10, 27, 15, 0),
+                            {
+                                datetime.timedelta(seconds=28800): (
+                                    datetime.datetime(1975, 6, 13, 21, 0),
+                                    {
+                                        datetime.timedelta(seconds=25200): {
+                                            "Asia/Ho_Chi_Minh",
+                                            "Asia/Saigon",
+                                        },
+                                        datetime.timedelta(seconds=28800): (
+                                            datetime.datetime(1978, 3, 22, 21, 0),
+                                            {
+                                                datetime.timedelta(seconds=28800): (
+                                                    datetime.datetime(
+                                                        1981, 4, 1, 21, 0
+                                                    ),
+                                                    {
+                                                        datetime.timedelta(
+                                                            seconds=28800
+                                                        ): (
+                                                            datetime.datetime(
+                                                                1986, 5, 4, 21, 0
+                                                            ),
+                                                            {
+                                                                datetime.timedelta(
+                                                                    seconds=28800
+                                                                ): (
+                                                                    datetime.datetime(
+                                                                        1988,
+                                                                        1,
+                                                                        1,
+                                                                        18,
+                                                                        0,
+                                                                    ),
+                                                                    {
+                                                                        datetime.timedelta(
+                                                                            seconds=25200
+                                                                        ): {
+                                                                            "Asia/Pontianak"
+                                                                        },
+                                                                        datetime.timedelta(
+                                                                            seconds=28800
+                                                                        ): (
+                                                                            datetime.datetime(
+                                                                                2009,
+                                                                                10,
+                                                                                19,
+                                                                                3,
+                                                                                0,
+                                                                            ),
+                                                                            {
+                                                                                datetime.timedelta(
+                                                                                    seconds=28800
+                                                                                ): {
+                                                                                    "Asia/Brunei",
+                                                                                    "Asia/Kuching",
+                                                                                    "Asia/Makassar",
+                                                                                    "Asia/Ujung_Pandang",
+                                                                                    "Etc/GMT-8",
+                                                                                },
+                                                                                datetime.timedelta(
+                                                                                    seconds=39600
+                                                                                ): {
+                                                                                    "Antarctica/Casey"
+                                                                                },
+                                                                            },
+                                                                        ),
+                                                                    },
+                                                                ),
+                                                                datetime.timedelta(
+                                                                    seconds=32400
+                                                                ): {
+                                                                    "Asia/Chongqing",
+                                                                    "Asia/Chungking",
+                                                                    "Asia/Harbin",
+                                                                    "Asia/Shanghai",
+                                                                    "PRC",
+                                                                },
+                                                            },
+                                                        ),
+                                                        datetime.timedelta(
+                                                            seconds=32400
+                                                        ): {"Asia/Irkutsk"},
+                                                    },
+                                                ),
+                                                datetime.timedelta(seconds=32400): {
+                                                    "Asia/Manila"
+                                                },
+                                            },
+                                        ),
+                                    },
+                                ),
+                                datetime.timedelta(seconds=32400): {
+                                    "Australia/Perth",
+                                    "Australia/West",
+                                },
+                            },
+                        ),
+                        datetime.timedelta(seconds=32400): {"Asia/Taipei", "ROC"},
+                    },
+                ),
+                datetime.timedelta(seconds=32400): {
+                    "Asia/Hong_Kong",
+                    "Asia/Macao",
+                    "Asia/Macau",
+                    "Hongkong",
+                },
+            },
+        ),
+        datetime.timedelta(seconds=31500): {"Australia/Eucla"},
+        datetime.timedelta(seconds=32400): (
+            datetime.datetime(1976, 5, 3, 18, 0),
+            {
+                datetime.timedelta(seconds=28800): {"Asia/Dili"},
+                datetime.timedelta(seconds=32400): (
+                    datetime.datetime(1981, 4, 1, 18, 0),
+                    {
+                        datetime.timedelta(seconds=32400): (
+                            datetime.datetime(1987, 5, 10, 15, 0),
+                            {
+                                datetime.timedelta(seconds=32400): (
+                                    datetime.datetime(2015, 8, 15, 15, 0),
+                                    {
+                                        datetime.timedelta(seconds=30600): {
+                                            "Asia/Pyongyang"
+                                        },
+                                        datetime.timedelta(seconds=32400): {
+                                            "Asia/Jayapura",
+                                            "Asia/Tokyo",
+                                            "Etc/GMT-9",
+                                            "Japan",
+                                            "Pacific/Palau",
+                                        },
+                                    },
+                                ),
+                                datetime.timedelta(seconds=36000): {
+                                    "Asia/Seoul",
+                                    "ROK",
+                                },
+                            },
+                        ),
+                        datetime.timedelta(seconds=36000): (
+                            datetime.datetime(2004, 1, 1, 21, 0),
+                            {
+                                datetime.timedelta(seconds=32400): (
+                                    datetime.datetime(2014, 10, 27, 0, 0),
+                                    {
+                                        datetime.timedelta(seconds=28800): {
+                                            "Asia/Chita"
+                                        },
+                                        datetime.timedelta(seconds=32400): {
+                                            "Asia/Yakutsk"
+                                        },
+                                    },
+                                ),
+                                datetime.timedelta(seconds=36000): {"Asia/Khandyga"},
+                            },
+                        ),
+                        datetime.timedelta(seconds=43200): {"Asia/Ust-Nera"},
+                    },
+                ),
+            },
+        ),
+        datetime.timedelta(seconds=34200): (
+            datetime.datetime(1971, 10, 31, 21, 0),
+            {
+                datetime.timedelta(seconds=34200): {
+                    "Australia/Darwin",
+                    "Australia/North",
+                },
+                datetime.timedelta(seconds=37800): (
+                    datetime.datetime(1982, 3, 7, 18, 0),
+                    {
+                        datetime.timedelta(seconds=34200): {
+                            "Australia/Adelaide",
+                            "Australia/South",
+                        },
+                        datetime.timedelta(seconds=37800): {
+                            "Australia/Broken_Hill",
+                            "Australia/Yancowinna",
+                        },
+                    },
+                ),
+            },
+        ),
+        datetime.timedelta(seconds=36000): (
+            datetime.datetime(1970, 4, 26, 15, 0),
+            {
+                datetime.timedelta(seconds=36000): (
+                    datetime.datetime(1971, 10, 31, 21, 0),
+                    {
+                        datetime.timedelta(seconds=36000): (
+                            datetime.datetime(1981, 3, 2, 0, 0),
+                            {
+                                datetime.timedelta(seconds=36000): (
+                                    datetime.datetime(1981, 4, 1, 18, 0),
+                                    {
+                                        datetime.timedelta(seconds=36000): (
+                                            datetime.datetime(2014, 12, 28, 21, 0),
+                                            {
+                                                datetime.timedelta(seconds=36000): {
+                                                    "Antarctica/DumontDUrville",
+                                                    "Etc/GMT-10",
+                                                    "Pacific/Chuuk",
+                                                    "Pacific/Port_Moresby",
+                                                    "Pacific/Truk",
+                                                    "Pacific/Yap",
+                                                },
+                                                datetime.timedelta(seconds=39600): {
+                                                    "Pacific/Bougainville"
+                                                },
+                                            },
+                                        ),
+                                        datetime.timedelta(seconds=39600): {
+                                            "Asia/Vladivostok"
+                                        },
+                                    },
+                                ),
+                                datetime.timedelta(seconds=37800): {
+                                    "Australia/LHI",
+                                    "Australia/Lord_Howe",
+                                },
+                            },
+                        ),
+                        datetime.timedelta(seconds=39600): (
+                            datetime.datetime(1972, 10, 29, 21, 0),
+                            {
+                                datetime.timedelta(seconds=36000): (
+                                    datetime.datetime(1992, 10, 26, 0, 0),
+                                    {
+                                        datetime.timedelta(seconds=36000): {
+                                            "Australia/Brisbane",
+                                            "Australia/Queensland",
+                                        },
+                                        datetime.timedelta(seconds=39600): {
+                                            "Australia/Lindeman"
+                                        },
+                                    },
+                                ),
+                                datetime.timedelta(seconds=39600): (
+                                    datetime.datetime(1982, 3, 7, 18, 0),
+                                    {
+                                        datetime.timedelta(seconds=36000): {
+                                            "Australia/Melbourne",
+                                            "Australia/Victoria",
+                                        },
+                                        datetime.timedelta(seconds=39600): {
+                                            "Australia/ACT",
+                                            "Australia/Canberra",
+                                            "Australia/NSW",
+                                            "Australia/Sydney",
+                                        },
+                                    },
+                                ),
+                            },
+                        ),
+                    },
+                ),
+                datetime.timedelta(seconds=39600): {"Pacific/Guam", "Pacific/Saipan"},
+            },
+        ),
+        datetime.timedelta(seconds=39600): (
+            datetime.datetime(1970, 3, 8, 15, 0),
+            {
+                datetime.timedelta(seconds=36000): (
+                    datetime.datetime(2010, 4, 4, 21, 0),
+                    {
+                        datetime.timedelta(seconds=36000): {
+                            "Australia/Currie",
+                            "Australia/Hobart",
+                            "Australia/Tasmania",
+                        },
+                        datetime.timedelta(seconds=39600): {"Antarctica/Macquarie"},
+                    },
+                ),
+                datetime.timedelta(seconds=39600): (
+                    datetime.datetime(1973, 12, 23, 15, 0),
+                    {
+                        datetime.timedelta(seconds=39600): (
+                            datetime.datetime(1977, 12, 4, 15, 0),
+                            {
+                                datetime.timedelta(seconds=39600): (
+                                    datetime.datetime(1981, 4, 1, 18, 0),
+                                    {
+                                        datetime.timedelta(seconds=39600): {
+                                            "Etc/GMT-11",
+                                            "Pacific/Guadalcanal",
+                                            "Pacific/Pohnpei",
+                                            "Pacific/Ponape",
+                                        },
+                                        datetime.timedelta(seconds=43200): (
+                                            datetime.datetime(1997, 3, 30, 15, 0),
+                                            {
+                                                datetime.timedelta(seconds=39600): {
+                                                    "Asia/Sakhalin"
+                                                },
+                                                datetime.timedelta(seconds=43200): (
+                                                    datetime.datetime(
+                                                        2014, 10, 26, 18, 0
+                                                    ),
+                                                    {
+                                                        datetime.timedelta(
+                                                            seconds=36000
+                                                        ): {"Asia/Magadan"},
+                                                        datetime.timedelta(
+                                                            seconds=39600
+                                                        ): {"Asia/Srednekolymsk"},
+                                                    },
+                                                ),
+                                            },
+                                        ),
+                                    },
+                                ),
+                                datetime.timedelta(seconds=43200): {"Pacific/Noumea"},
+                            },
+                        ),
+                        datetime.timedelta(seconds=43200): {"Pacific/Efate"},
+                    },
+                ),
+            },
+        ),
+        datetime.timedelta(seconds=41400): (
+            datetime.datetime(1974, 10, 27, 15, 0),
+            {
+                datetime.timedelta(seconds=41400): {"Pacific/Nauru"},
+                datetime.timedelta(seconds=45000): {"Pacific/Norfolk"},
+            },
+        ),
+        datetime.timedelta(seconds=43200): (
+            datetime.datetime(1974, 11, 3, 21, 0),
+            {
+                datetime.timedelta(seconds=43200): (
+                    datetime.datetime(1981, 4, 1, 15, 0),
+                    {
+                        datetime.timedelta(seconds=43200): (
+                            datetime.datetime(1998, 11, 1, 18, 0),
+                            {
+                                datetime.timedelta(seconds=43200): (
+                                    datetime.datetime(1999, 1, 1, 18, 0),
+                                    {
+                                        datetime.timedelta(seconds=39600): {
+                                            "Pacific/Kosrae"
+                                        },
+                                        datetime.timedelta(seconds=43200): {
+                                            "Etc/GMT-12",
+                                            "Pacific/Funafuti",
+                                            "Pacific/Majuro",
+                                            "Pacific/Tarawa",
+                                            "Pacific/Wake",
+                                            "Pacific/Wallis",
+                                        },
+                                    },
+                                ),
+                                datetime.timedelta(seconds=46800): {"Pacific/Fiji"},
+                            },
+                        ),
+                        datetime.timedelta(seconds=46800): {"Asia/Kamchatka"},
+                    },
+                ),
+                datetime.timedelta(seconds=46800): {
+                    "Antarctica/McMurdo",
+                    "Antarctica/South_Pole",
+                    "NZ",
+                    "Pacific/Auckland",
+                },
+            },
+        ),
+        datetime.timedelta(seconds=45900): {"NZ-CHAT", "Pacific/Chatham"},
+        datetime.timedelta(seconds=46800): (
+            datetime.datetime(1981, 4, 1, 15, 0),
+            {
+                datetime.timedelta(seconds=46800): (
+                    datetime.datetime(1999, 10, 7, 21, 0),
+                    {
+                        datetime.timedelta(seconds=46800): {"Etc/GMT-13"},
+                        datetime.timedelta(seconds=50400): {"Pacific/Tongatapu"},
+                    },
+                ),
+                datetime.timedelta(seconds=50400): {"Asia/Anadyr"},
+            },
+        ),
+        datetime.timedelta(seconds=50400): {"Etc/GMT-14"},
+    },
+)
+
+
+__all__ = ["lookup"]
diff -pruN 6.0.1-3/src/icalendar/timezone/provider.py 6.3.1-1/src/icalendar/timezone/provider.py
--- 6.0.1-3/src/icalendar/timezone/provider.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/timezone/provider.py	2025-05-20 07:31:39.000000000 +0000
@@ -1,14 +1,23 @@
 """The interface for timezone implementations."""
+
 from __future__ import annotations
-from abc import ABC, abstractmethod, abstractproperty
-from icalendar import prop
-from dateutil.rrule import rrule
-from datetime import datetime, tzinfo
+
+from abc import ABC, abstractmethod
+from typing import TYPE_CHECKING, Optional
+
+if TYPE_CHECKING:
+    from datetime import datetime, tzinfo
+
+    from dateutil.rrule import rrule
+
+    from icalendar import prop
+
 
 class TZProvider(ABC):
     """Interface for timezone implementations."""
 
-    @abstractproperty
+    @property
+    @abstractmethod
     def name(self) -> str:
         """The name of the implementation."""
 
@@ -25,7 +34,7 @@ class TZProvider(ABC):
         """Whether the timezone is already cached by the implementation."""
 
     @abstractmethod
-    def fix_rrule_until(self, rrule:rrule, ical_rrule:prop.vRecur) -> None:
+    def fix_rrule_until(self, rrule: rrule, ical_rrule: prop.vRecur) -> None:
         """Make sure the until value works for the rrule generated from the ical_rrule."""
 
     @abstractmethod
@@ -44,4 +53,5 @@ class TZProvider(ABC):
     def uses_zoneinfo(self) -> bool:
         """Whether we use zoneinfo."""
 
+
 __all__ = ["TZProvider"]
diff -pruN 6.0.1-3/src/icalendar/timezone/pytz.py 6.3.1-1/src/icalendar/timezone/pytz.py
--- 6.0.1-3/src/icalendar/timezone/pytz.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/timezone/pytz.py	2025-05-20 07:31:39.000000000 +0000
@@ -1,4 +1,5 @@
 """Use pytz timezones."""
+
 from __future__ import annotations
 import pytz
 from .. import cal
@@ -10,7 +11,6 @@ from icalendar import prop
 from dateutil.rrule import rrule
 
 
-
 class PYTZ(TZProvider):
     """Provide icalendar with timezones from pytz."""
 
@@ -18,7 +18,7 @@ class PYTZ(TZProvider):
 
     def localize_utc(self, dt: datetime) -> datetime:
         """Return the datetime in UTC."""
-        if getattr(dt, 'tzinfo', False) and dt.tzinfo is not None:
+        if getattr(dt, "tzinfo", False) and dt.tzinfo is not None:
             return dt.astimezone(pytz.utc)
         # assume UTC for naive datetime instances
         return pytz.utc.localize(dt)
@@ -31,9 +31,9 @@ class PYTZ(TZProvider):
         """Whether the timezone is already cached by the implementation."""
         return id in pytz.all_timezones
 
-    def fix_rrule_until(self, rrule:rrule, ical_rrule:prop.vRecur) -> None:
+    def fix_rrule_until(self, rrule: rrule, ical_rrule: prop.vRecur) -> None:
         """Make sure the until value works for the rrule generated from the ical_rrule."""
-        if not {'UNTIL', 'COUNT'}.intersection(ical_rrule.keys()):
+        if not {"UNTIL", "COUNT"}.intersection(ical_rrule.keys()):
             # pytz.timezones don't know any transition dates after 2038
             # either
             rrule._until = datetime(2038, 12, 31, tzinfo=pytz.UTC)
@@ -42,11 +42,15 @@ class PYTZ(TZProvider):
         """Create a pytz timezone from the given information."""
         transition_times, transition_info = tz.get_transitions()
         name = tz.tz_name
-        cls = type(name, (DstTzInfo,), {
-            'zone': name,
-            '_utc_transition_times': transition_times,
-            '_transition_info': transition_info
-        })
+        cls = type(
+            name,
+            (DstTzInfo,),
+            {
+                "zone": name,
+                "_utc_transition_times": transition_times,
+                "_transition_info": transition_info,
+            },
+        )
         return cls()
 
     def timezone(self, name: str) -> Optional[tzinfo]:
diff -pruN 6.0.1-3/src/icalendar/timezone/tzid.py 6.3.1-1/src/icalendar/timezone/tzid.py
--- 6.0.1-3/src/icalendar/timezone/tzid.py	1970-01-01 00:00:00.000000000 +0000
+++ 6.3.1-1/src/icalendar/timezone/tzid.py	2025-05-20 07:31:39.000000000 +0000
@@ -0,0 +1,112 @@
+"""This module identifies timezones.
+
+Normally, timezones have ids.
+This is a way to access the ids if you have a
+datetime.tzinfo object.
+"""
+
+from __future__ import annotations
+
+from collections import defaultdict
+from pathlib import Path
+from typing import TYPE_CHECKING, Optional
+
+from dateutil.tz import tz
+
+from icalendar.timezone import equivalent_timezone_ids_result
+
+if TYPE_CHECKING:
+    from datetime import datetime, tzinfo
+
+DATEUTIL_UTC = tz.gettz("UTC")
+DATEUTIL_UTC_PATH : Optional[str] = getattr(DATEUTIL_UTC, "_filename", None)
+DATEUTIL_ZONEINFO_PATH = (
+    None if DATEUTIL_UTC_PATH is None else Path(DATEUTIL_UTC_PATH).parent
+)
+
+def tzids_from_tzinfo(tzinfo: Optional[tzinfo]) -> tuple[str]:
+    """Get several timezone ids if we can identify the timezone.
+
+    >>> import zoneinfo
+    >>> from icalendar.timezone.tzid import tzids_from_tzinfo
+    >>> tzids_from_tzinfo(zoneinfo.ZoneInfo("Arctic/Longyearbyen"))
+    ('Arctic/Longyearbyen', 'Atlantic/Jan_Mayen', 'Europe/Berlin', 'Europe/Budapest', 'Europe/Copenhagen', 'Europe/Oslo', 'Europe/Stockholm', 'Europe/Vienna')
+    >>> from dateutil.tz import gettz
+    >>> tzids_from_tzinfo(gettz("Europe/Berlin"))
+    ('Europe/Berlin', 'Arctic/Longyearbyen', 'Atlantic/Jan_Mayen', 'Europe/Budapest', 'Europe/Copenhagen', 'Europe/Oslo', 'Europe/Stockholm', 'Europe/Vienna')
+
+    """  # The example might need to change if you recreate the lookup tree
+    if tzinfo is None:
+        return ()
+    if hasattr(tzinfo, "zone"):
+        return get_equivalent_tzids(tzinfo.zone)  # pytz implementation
+    if hasattr(tzinfo, "key"):
+        return get_equivalent_tzids(tzinfo.key)  # ZoneInfo implementation
+    if isinstance(tzinfo, tz._tzicalvtz):  # noqa: SLF001
+        return get_equivalent_tzids(tzinfo._tzid)  # noqa: SLF001
+    if isinstance(tzinfo, tz.tzstr):
+        return get_equivalent_tzids(tzinfo._s)  # noqa: SLF001
+    if hasattr(tzinfo, "_filename"): # dateutil.tz.tzfile  # noqa: SIM102
+        if DATEUTIL_ZONEINFO_PATH is not None:
+            # tzfile('/usr/share/zoneinfo/Europe/Berlin')
+            path = tzinfo._filename  # noqa: SLF001
+            if path.startswith(str(DATEUTIL_ZONEINFO_PATH)):
+                tzid = str(Path(path).relative_to(DATEUTIL_ZONEINFO_PATH))
+                return get_equivalent_tzids(tzid)
+            return get_equivalent_tzids(path)
+    if isinstance(tzinfo, tz.tzutc):
+        return get_equivalent_tzids("UTC")
+    return ()
+
+
+def tzid_from_tzinfo(tzinfo: Optional[tzinfo]) -> Optional[str]:
+    """Retrieve the timezone id from the tzinfo object.
+
+    Some timezones are equivalent.
+    Thus, we might return one ID that is equivelant to others.
+    """
+    tzids = tzids_from_tzinfo(tzinfo)
+    if "UTC" in tzids:
+        return "UTC"
+    if not tzids:
+        return None
+    return tzids[0]
+
+
+def tzid_from_dt(dt: datetime) -> Optional[str]:
+    """Retrieve the timezone id from the datetime object."""
+    tzid = tzid_from_tzinfo(dt.tzinfo)
+    if tzid is None:
+        return dt.tzname()
+    return tzid
+
+
+_EQUIVALENT_IDS : dict[str, set[str]] = defaultdict(set)
+
+def _add_equivalent_ids(value:tuple|dict|set):
+    """This adds equivalent ids/
+
+    As soon as one timezone implementation used claims their equivalence, 
+    they are considered equivalent.
+    Have a look at icalendar.timezone.equivalent_timezone_ids.
+    """
+    if isinstance(value, set):
+        for tzid in value:
+            _EQUIVALENT_IDS[tzid].update(value)
+    elif isinstance(value, tuple):
+        _add_equivalent_ids(value[1])
+    elif isinstance(value, dict):
+        for value in value.values():
+            _add_equivalent_ids(value)
+    else:
+        raise TypeError(f"Expected tuple, dict or set, not {value.__class__.__name__}: {value!r}")
+
+_add_equivalent_ids(equivalent_timezone_ids_result.lookup)
+
+def get_equivalent_tzids(tzid: str) -> tuple[str]:
+    """This returns the tzids which are equivalent to this one."""
+    ids = _EQUIVALENT_IDS.get(tzid, set())
+    return (tzid,) + tuple(sorted(ids - {tzid}))
+
+
+__all__ = ["tzid_from_tzinfo", "tzid_from_dt", "tzids_from_tzinfo"]
diff -pruN 6.0.1-3/src/icalendar/timezone/tzp.py 6.3.1-1/src/icalendar/timezone/tzp.py
--- 6.0.1-3/src/icalendar/timezone/tzp.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/timezone/tzp.py	2025-05-20 07:31:39.000000000 +0000
@@ -1,12 +1,19 @@
 from __future__ import annotations
-import datetime
-from .. import cal
-from typing import Optional, Union
+
+from typing import TYPE_CHECKING, Optional, Union
+
+from icalendar.tools import to_datetime
+
 from .windows_to_olson import WINDOWS_TO_OLSON
-from .provider import TZProvider
-from icalendar import prop
-from dateutil.rrule import rrule
 
+if TYPE_CHECKING:
+    import datetime
+
+    from dateutil.rrule import rrule
+
+    from icalendar import cal, prop
+
+    from .provider import TZProvider
 
 DEFAULT_TIMEZONE_PROVIDER = "zoneinfo"
 
@@ -19,32 +26,36 @@ class TZP:
     All of icalendar will then use this timezone implementation.
     """
 
-    def __init__(self, provider:Union[str, TZProvider]=DEFAULT_TIMEZONE_PROVIDER):
+    def __init__(self, provider: Union[str, TZProvider] = DEFAULT_TIMEZONE_PROVIDER):
         """Create a new timezone implementation proxy."""
         self.use(provider)
 
     def use_pytz(self) -> None:
         """Use pytz as the timezone provider."""
         from .pytz import PYTZ
+
         self._use(PYTZ())
 
     def use_zoneinfo(self) -> None:
         """Use zoneinfo as the timezone provider."""
         from .zoneinfo import ZONEINFO
+
         self._use(ZONEINFO())
 
-    def _use(self, provider:TZProvider) -> None:
+    def _use(self, provider: TZProvider) -> None:
         """Use a timezone implementation."""
         self.__tz_cache = {}
         self.__provider = provider
 
-    def use(self, provider:Union[str, TZProvider]):
+    def use(self, provider: Union[str, TZProvider]):
         """Switch to a different timezone provider."""
         if isinstance(provider, str):
-            provider = getattr(self, f"use_{provider}", None)
-            if provider is None:
-                raise ValueError(f"Unknown provider {provider_name}. Use 'pytz' or 'zoneinfo'.")
-            provider()
+            use_provider = getattr(self, f"use_{provider}", None)
+            if use_provider is None:
+                raise ValueError(
+                    f"Unknown provider {provider}. Use 'pytz' or 'zoneinfo'."
+                )
+            use_provider()
         else:
             self._use(provider)
 
@@ -52,34 +63,40 @@ class TZP:
         """Use the default timezone provider."""
         self.use(DEFAULT_TIMEZONE_PROVIDER)
 
-    def localize_utc(self, dt: datetime.datetime) -> datetime.datetime:
+    def localize_utc(self, dt: datetime.date) -> datetime.datetime:
         """Return the datetime in UTC.
 
         If the datetime has no timezone, set UTC as its timezone.
         """
-        return self.__provider.localize_utc(dt)
+        return self.__provider.localize_utc(to_datetime(dt))
 
-    def localize(self, dt: datetime.datetime, tz: Union[datetime.tzinfo, str]) -> datetime.datetime:
+    def localize(
+        self, dt: datetime.date, tz: Union[datetime.tzinfo, str, None]
+    ) -> datetime.datetime:
         """Localize a datetime to a timezone."""
         if isinstance(tz, str):
             tz = self.timezone(tz)
-        return self.__provider.localize(dt, tz)
+        if tz is None:
+            return dt.replace(tzinfo=None)
+        return self.__provider.localize(to_datetime(dt), tz)
 
-    def cache_timezone_component(self, timezone_component: cal.VTIMEZONE) -> None:
+    def cache_timezone_component(self, timezone_component: cal.Timezone) -> None:
         """Cache the timezone that is created from a timezone component
         if it is not already known.
 
         This can influence the result from timezone(): Once cached, the
         custom timezone is returned from timezone().
         """
-        _unclean_id = timezone_component['TZID']
-        id = self.clean_timezone_id(_unclean_id)
-        if not self.__provider.knows_timezone_id(id) \
-            and not self.__provider.knows_timezone_id(_unclean_id) \
-            and id not in self.__tz_cache:
-            self.__tz_cache[id] = timezone_component.to_tz(self)
+        _unclean_id = timezone_component["TZID"]
+        _id = self.clean_timezone_id(_unclean_id)
+        if (
+            not self.__provider.knows_timezone_id(_id)
+            and not self.__provider.knows_timezone_id(_unclean_id)
+            and _id not in self.__tz_cache
+        ):
+            self.__tz_cache[_id] = timezone_component.to_tz(self, lookup_tzid=False)
 
-    def fix_rrule_until(self, rrule:rrule, ical_rrule:prop.vRecur) -> None:
+    def fix_rrule_until(self, rrule: rrule, ical_rrule: prop.vRecur) -> None:
         """Make sure the until value works."""
         self.__provider.fix_rrule_until(rrule, ical_rrule)
 
@@ -98,16 +115,16 @@ class TZP:
         """
         return tzid.strip("/")
 
-    def timezone(self, id: str) -> Optional[datetime.tzinfo]:
+    def timezone(self, tz_id: str) -> Optional[datetime.tzinfo]:
         """Return a timezone with an id or None if we cannot find it."""
-        _unclean_id = id
-        id = self.clean_timezone_id(id)
-        tz = self.__provider.timezone(id)
+        _unclean_id = tz_id
+        tz_id = self.clean_timezone_id(tz_id)
+        tz = self.__provider.timezone(tz_id)
         if tz is not None:
             return tz
-        if id in WINDOWS_TO_OLSON:
-            tz = self.__provider.timezone(WINDOWS_TO_OLSON[id])
-        return tz or self.__provider.timezone(_unclean_id) or self.__tz_cache.get(id)
+        if tz_id in WINDOWS_TO_OLSON:
+            tz = self.__provider.timezone(WINDOWS_TO_OLSON[tz_id])
+        return tz or self.__provider.timezone(_unclean_id) or self.__tz_cache.get(tz_id)
 
     def uses_pytz(self) -> bool:
         """Whether we use pytz at all."""
@@ -125,4 +142,5 @@ class TZP:
     def __repr__(self) -> str:
         return f"{self.__class__.__name__}({repr(self.name)})"
 
+
 __all__ = ["TZP"]
diff -pruN 6.0.1-3/src/icalendar/timezone/windows_to_olson.py 6.3.1-1/src/icalendar/timezone/windows_to_olson.py
--- 6.0.1-3/src/icalendar/timezone/windows_to_olson.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/timezone/windows_to_olson.py	2025-05-20 07:31:39.000000000 +0000
@@ -10,110 +10,110 @@ for this mapping is also available at th
 """
 
 WINDOWS_TO_OLSON = {
-    'AUS Central Standard Time': 'Australia/Darwin',
-    'AUS Eastern Standard Time': 'Australia/Sydney',
-    'Afghanistan Standard Time': 'Asia/Kabul',
-    'Alaskan Standard Time': 'America/Anchorage',
-    'Arab Standard Time': 'Asia/Riyadh',
-    'Arabian Standard Time': 'Asia/Dubai',
-    'Arabic Standard Time': 'Asia/Baghdad',
-    'Argentina Standard Time': 'America/Argentina/Buenos_Aires',
-    'Atlantic Standard Time': 'America/Halifax',
-    'Azerbaijan Standard Time': 'Asia/Baku',
-    'Azores Standard Time': 'Atlantic/Azores',
-    'Bahia Standard Time': 'America/Bahia',
-    'Bangladesh Standard Time': 'Asia/Dhaka',
-    'Belarus Standard Time': 'Europe/Minsk',
-    'Canada Central Standard Time': 'America/Regina',
-    'Cape Verde Standard Time': 'Atlantic/Cape_Verde',
-    'Caucasus Standard Time': 'Asia/Yerevan',
-    'Cen. Australia Standard Time': 'Australia/Adelaide',
-    'Central America Standard Time': 'America/Guatemala',
-    'Central Asia Standard Time': 'Asia/Almaty',
-    'Central Brazilian Standard Time': 'America/Cuiaba',
-    'Central Europe Standard Time': 'Europe/Budapest',
-    'Central European Standard Time': 'Europe/Warsaw',
-    'Central Pacific Standard Time': 'Pacific/Guadalcanal',
-    'Central Standard Time': 'America/Chicago',
-    'Central Standard Time (Mexico)': 'America/Mexico_City',
-    'China Standard Time': 'Asia/Shanghai',
-    'Dateline Standard Time': 'Etc/GMT+12',
-    'E. Africa Standard Time': 'Africa/Nairobi',
-    'E. Australia Standard Time': 'Australia/Brisbane',
-    'E. Europe Standard Time': 'Europe/Chisinau',
-    'E. South America Standard Time': 'America/Sao_Paulo',
-    'Eastern Standard Time': 'America/New_York',
-    'Eastern Standard Time (Mexico)': 'America/Cancun',
-    'Egypt Standard Time': 'Africa/Cairo',
-    'Ekaterinburg Standard Time': 'Asia/Yekaterinburg',
-    'FLE Standard Time': 'Europe/Kyiv',
-    'Fiji Standard Time': 'Pacific/Fiji',
-    'GMT Standard Time': 'Europe/London',
-    'GTB Standard Time': 'Europe/Bucharest',
-    'Georgian Standard Time': 'Asia/Tbilisi',
-    'Greenland Standard Time': 'America/Nuuk',
-    'Greenwich Standard Time': 'Atlantic/Reykjavik',
-    'Hawaiian Standard Time': 'Pacific/Honolulu',
-    'India Standard Time': 'Asia/Kolkata',
-    'Iran Standard Time': 'Asia/Tehran',
-    'Israel Standard Time': 'Asia/Jerusalem',
-    'Jordan Standard Time': 'Asia/Amman',
-    'Kaliningrad Standard Time': 'Europe/Kaliningrad',
-    'Korea Standard Time': 'Asia/Seoul',
-    'Libya Standard Time': 'Africa/Tripoli',
-    'Line Islands Standard Time': 'Pacific/Kiritimati',
-    'Magadan Standard Time': 'Asia/Magadan',
-    'Mauritius Standard Time': 'Indian/Mauritius',
-    'Middle East Standard Time': 'Asia/Beirut',
-    'Montevideo Standard Time': 'America/Montevideo',
-    'Morocco Standard Time': 'Africa/Casablanca',
-    'Mountain Standard Time': 'America/Denver',
-    'Mountain Standard Time (Mexico)': 'America/Chihuahua',
-    'Myanmar Standard Time': 'Asia/Yangon',
-    'N. Central Asia Standard Time': 'Asia/Novosibirsk',
-    'Namibia Standard Time': 'Africa/Windhoek',
-    'Nepal Standard Time': 'Asia/Kathmandu',
-    'New Zealand Standard Time': 'Pacific/Auckland',
-    'Newfoundland Standard Time': 'America/St_Johns',
-    'North Asia East Standard Time': 'Asia/Irkutsk',
-    'North Asia Standard Time': 'Asia/Krasnoyarsk',
-    'North Korea Standard Time': 'Asia/Pyongyang',
-    'Pacific SA Standard Time': 'America/Santiago',
-    'Pacific Standard Time': 'America/Los_Angeles',
-    'Pakistan Standard Time': 'Asia/Karachi',
-    'Paraguay Standard Time': 'America/Asuncion',
-    'Romance Standard Time': 'Europe/Paris',
-    'Russia Time Zone 10': 'Asia/Srednekolymsk',
-    'Russia Time Zone 11': 'Asia/Kamchatka',
-    'Russia Time Zone 3': 'Europe/Samara',
-    'Russian Standard Time': 'Europe/Moscow',
-    'SA Eastern Standard Time': 'America/Cayenne',
-    'SA Pacific Standard Time': 'America/Bogota',
-    'SA Western Standard Time': 'America/La_Paz',
-    'SE Asia Standard Time': 'Asia/Bangkok',
-    'Samoa Standard Time': 'Pacific/Apia',
-    'Singapore Standard Time': 'Asia/Singapore',
-    'South Africa Standard Time': 'Africa/Johannesburg',
-    'Sri Lanka Standard Time': 'Asia/Colombo',
-    'Syria Standard Time': 'Asia/Damascus',
-    'Taipei Standard Time': 'Asia/Taipei',
-    'Tasmania Standard Time': 'Australia/Hobart',
-    'Tokyo Standard Time': 'Asia/Tokyo',
-    'Tonga Standard Time': 'Pacific/Tongatapu',
-    'Turkey Standard Time': 'Europe/Istanbul',
-    'US Eastern Standard Time': 'America/Indiana/Indianapolis',
-    'US Mountain Standard Time': 'America/Phoenix',
-    'UTC': 'Etc/GMT',
-    'UTC+12': 'Etc/GMT-12',
-    'UTC-02': 'Etc/GMT+2',
-    'UTC-11': 'Etc/GMT+11',
-    'Ulaanbaatar Standard Time': 'Asia/Ulaanbaatar',
-    'Venezuela Standard Time': 'America/Caracas',
-    'Vladivostok Standard Time': 'Asia/Vladivostok',
-    'W. Australia Standard Time': 'Australia/Perth',
-    'W. Central Africa Standard Time': 'Africa/Lagos',
-    'W. Europe Standard Time': 'Europe/Berlin',
-    'West Asia Standard Time': 'Asia/Tashkent',
-    'West Pacific Standard Time': 'Pacific/Port_Moresby',
-    'Yakutsk Standard Time': 'Asia/Yakutsk',
+    "AUS Central Standard Time": "Australia/Darwin",
+    "AUS Eastern Standard Time": "Australia/Sydney",
+    "Afghanistan Standard Time": "Asia/Kabul",
+    "Alaskan Standard Time": "America/Anchorage",
+    "Arab Standard Time": "Asia/Riyadh",
+    "Arabian Standard Time": "Asia/Dubai",
+    "Arabic Standard Time": "Asia/Baghdad",
+    "Argentina Standard Time": "America/Argentina/Buenos_Aires",
+    "Atlantic Standard Time": "America/Halifax",
+    "Azerbaijan Standard Time": "Asia/Baku",
+    "Azores Standard Time": "Atlantic/Azores",
+    "Bahia Standard Time": "America/Bahia",
+    "Bangladesh Standard Time": "Asia/Dhaka",
+    "Belarus Standard Time": "Europe/Minsk",
+    "Canada Central Standard Time": "America/Regina",
+    "Cape Verde Standard Time": "Atlantic/Cape_Verde",
+    "Caucasus Standard Time": "Asia/Yerevan",
+    "Cen. Australia Standard Time": "Australia/Adelaide",
+    "Central America Standard Time": "America/Guatemala",
+    "Central Asia Standard Time": "Asia/Almaty",
+    "Central Brazilian Standard Time": "America/Cuiaba",
+    "Central Europe Standard Time": "Europe/Budapest",
+    "Central European Standard Time": "Europe/Warsaw",
+    "Central Pacific Standard Time": "Pacific/Guadalcanal",
+    "Central Standard Time": "America/Chicago",
+    "Central Standard Time (Mexico)": "America/Mexico_City",
+    "China Standard Time": "Asia/Shanghai",
+    "Dateline Standard Time": "Etc/GMT+12",
+    "E. Africa Standard Time": "Africa/Nairobi",
+    "E. Australia Standard Time": "Australia/Brisbane",
+    "E. Europe Standard Time": "Europe/Chisinau",
+    "E. South America Standard Time": "America/Sao_Paulo",
+    "Eastern Standard Time": "America/New_York",
+    "Eastern Standard Time (Mexico)": "America/Cancun",
+    "Egypt Standard Time": "Africa/Cairo",
+    "Ekaterinburg Standard Time": "Asia/Yekaterinburg",
+    "FLE Standard Time": "Europe/Kyiv",
+    "Fiji Standard Time": "Pacific/Fiji",
+    "GMT Standard Time": "Europe/London",
+    "GTB Standard Time": "Europe/Bucharest",
+    "Georgian Standard Time": "Asia/Tbilisi",
+    "Greenland Standard Time": "America/Nuuk",
+    "Greenwich Standard Time": "Atlantic/Reykjavik",
+    "Hawaiian Standard Time": "Pacific/Honolulu",
+    "India Standard Time": "Asia/Kolkata",
+    "Iran Standard Time": "Asia/Tehran",
+    "Israel Standard Time": "Asia/Jerusalem",
+    "Jordan Standard Time": "Asia/Amman",
+    "Kaliningrad Standard Time": "Europe/Kaliningrad",
+    "Korea Standard Time": "Asia/Seoul",
+    "Libya Standard Time": "Africa/Tripoli",
+    "Line Islands Standard Time": "Pacific/Kiritimati",
+    "Magadan Standard Time": "Asia/Magadan",
+    "Mauritius Standard Time": "Indian/Mauritius",
+    "Middle East Standard Time": "Asia/Beirut",
+    "Montevideo Standard Time": "America/Montevideo",
+    "Morocco Standard Time": "Africa/Casablanca",
+    "Mountain Standard Time": "America/Denver",
+    "Mountain Standard Time (Mexico)": "America/Chihuahua",
+    "Myanmar Standard Time": "Asia/Yangon",
+    "N. Central Asia Standard Time": "Asia/Novosibirsk",
+    "Namibia Standard Time": "Africa/Windhoek",
+    "Nepal Standard Time": "Asia/Kathmandu",
+    "New Zealand Standard Time": "Pacific/Auckland",
+    "Newfoundland Standard Time": "America/St_Johns",
+    "North Asia East Standard Time": "Asia/Irkutsk",
+    "North Asia Standard Time": "Asia/Krasnoyarsk",
+    "North Korea Standard Time": "Asia/Pyongyang",
+    "Pacific SA Standard Time": "America/Santiago",
+    "Pacific Standard Time": "America/Los_Angeles",
+    "Pakistan Standard Time": "Asia/Karachi",
+    "Paraguay Standard Time": "America/Asuncion",
+    "Romance Standard Time": "Europe/Paris",
+    "Russia Time Zone 10": "Asia/Srednekolymsk",
+    "Russia Time Zone 11": "Asia/Kamchatka",
+    "Russia Time Zone 3": "Europe/Samara",
+    "Russian Standard Time": "Europe/Moscow",
+    "SA Eastern Standard Time": "America/Cayenne",
+    "SA Pacific Standard Time": "America/Bogota",
+    "SA Western Standard Time": "America/La_Paz",
+    "SE Asia Standard Time": "Asia/Bangkok",
+    "Samoa Standard Time": "Pacific/Apia",
+    "Singapore Standard Time": "Asia/Singapore",
+    "South Africa Standard Time": "Africa/Johannesburg",
+    "Sri Lanka Standard Time": "Asia/Colombo",
+    "Syria Standard Time": "Asia/Damascus",
+    "Taipei Standard Time": "Asia/Taipei",
+    "Tasmania Standard Time": "Australia/Hobart",
+    "Tokyo Standard Time": "Asia/Tokyo",
+    "Tonga Standard Time": "Pacific/Tongatapu",
+    "Turkey Standard Time": "Europe/Istanbul",
+    "US Eastern Standard Time": "America/Indiana/Indianapolis",
+    "US Mountain Standard Time": "America/Phoenix",
+    "UTC": "Etc/GMT",
+    "UTC+12": "Etc/GMT-12",
+    "UTC-02": "Etc/GMT+2",
+    "UTC-11": "Etc/GMT+11",
+    "Ulaanbaatar Standard Time": "Asia/Ulaanbaatar",
+    "Venezuela Standard Time": "America/Caracas",
+    "Vladivostok Standard Time": "Asia/Vladivostok",
+    "W. Australia Standard Time": "Australia/Perth",
+    "W. Central Africa Standard Time": "Africa/Lagos",
+    "W. Europe Standard Time": "Europe/Berlin",
+    "West Asia Standard Time": "Asia/Tashkent",
+    "West Pacific Standard Time": "Pacific/Port_Moresby",
+    "Yakutsk Standard Time": "Asia/Yakutsk",
 }
diff -pruN 6.0.1-3/src/icalendar/timezone/zoneinfo.py 6.3.1-1/src/icalendar/timezone/zoneinfo.py
--- 6.0.1-3/src/icalendar/timezone/zoneinfo.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/timezone/zoneinfo.py	2025-05-20 07:31:39.000000000 +0000
@@ -1,21 +1,29 @@
 """Use zoneinfo timezones"""
+
 from __future__ import annotations
+
+from icalendar.tools import is_date, to_datetime
+
 try:
     import zoneinfo
-except:
-    from backports import zoneinfo
-from icalendar import prop
-from dateutil.rrule import rrule, rruleset
+except ImportError:
+    from backports import zoneinfo  # type: ignore  # noqa: PGH003
+import copy
+import copyreg
+import functools
 from datetime import datetime, tzinfo
-from typing import Optional
-from .provider import TZProvider
-from .. import cal
 from io import StringIO
+from typing import TYPE_CHECKING, Optional
+
+from dateutil.rrule import rrule, rruleset
 from dateutil.tz import tzical
 from dateutil.tz.tz import _tzicalvtz
-import copyreg
-import functools
-import copy
+
+from .provider import TZProvider
+
+if TYPE_CHECKING:
+    from icalendar import cal, prop
+    from icalendar.prop import vDDDTypes
 
 
 class ZONEINFO(TZProvider):
@@ -31,7 +39,7 @@ class ZONEINFO(TZProvider):
 
     def localize_utc(self, dt: datetime) -> datetime:
         """Return the datetime in UTC."""
-        if getattr(dt, 'tzinfo', False) and dt.tzinfo is not None:
+        if getattr(dt, "tzinfo", False) and dt.tzinfo is not None:
             return dt.astimezone(self.utc)
         return self.localize(dt, self.utc)
 
@@ -49,9 +57,9 @@ class ZONEINFO(TZProvider):
         """Whether the timezone is already cached by the implementation."""
         return id in self._available_timezones
 
-    def fix_rrule_until(self, rrule:rrule, ical_rrule:prop.vRecur) -> None:
+    def fix_rrule_until(self, rrule: rrule, ical_rrule: prop.vRecur) -> None:
         """Make sure the until value works for the rrule generated from the ical_rrule."""
-        if not {'UNTIL', 'COUNT'}.intersection(ical_rrule.keys()):
+        if not {"UNTIL", "COUNT"}.intersection(ical_rrule.keys()):
             # zoninfo does not know any transition dates after 2038
             rrule._until = datetime(2038, 12, 31, tzinfo=self.utc)
 
@@ -67,6 +75,11 @@ class ZONEINFO(TZProvider):
                 for attr in list(sub.keys()):
                     if attr.lower().startswith("x-"):
                         sub.pop(attr)
+            for sub in tz.subcomponents:
+                start : vDDDTypes = sub.get("DTSTART")
+                if start and is_date(start.dt):
+                    # ValueError: Unsupported DTSTART param in VTIMEZONE: VALUE=DATE
+                    sub.DTSTART = to_datetime(start.dt)
             return self._create_timezone(tz)
 
     def _create_timezone(self, tz: cal.Timezone) -> tzinfo:
@@ -83,10 +96,11 @@ class ZONEINFO(TZProvider):
         return True
 
 
-def pickle_tzicalvtz(tzicalvtz:tz._tzicalvtz):
+def pickle_tzicalvtz(tzicalvtz: tz._tzicalvtz):
     """Because we use dateutil.tzical, we need to make it pickle-able."""
     return _tzicalvtz, (tzicalvtz._tzid, tzicalvtz._comps)
 
+
 copyreg.pickle(_tzicalvtz, pickle_tzicalvtz)
 
 
@@ -95,19 +109,23 @@ def pickle_rrule_with_cache(self: rrule)
 
     This is mainly copied from rrule.replace.
     """
-    new_kwargs = {"interval": self._interval,
-                  "count": self._count,
-                  "dtstart": self._dtstart,
-                  "freq": self._freq,
-                  "until": self._until,
-                  "wkst": self._wkst,
-                  "cache": False if self._cache is None else True }
+    new_kwargs = {
+        "interval": self._interval,
+        "count": self._count,
+        "dtstart": self._dtstart,
+        "freq": self._freq,
+        "until": self._until,
+        "wkst": self._wkst,
+        "cache": False if self._cache is None else True,
+    }
     new_kwargs.update(self._original_rule)
     # from https://stackoverflow.com/a/64915638/1320237
     return functools.partial(rrule, new_kwargs.pop("freq"), **new_kwargs), ()
 
+
 copyreg.pickle(rrule, pickle_rrule_with_cache)
 
+
 def pickle_rruleset_with_cache(rs: rruleset):
     """Pickle an rruleset."""
     # self._rrule = []
@@ -115,19 +133,28 @@ def pickle_rruleset_with_cache(rs: rrule
     # self._exrule = []
     # self._exdate = []
     return unpickle_rruleset_with_cache, (
-        rs._rrule, rs._rdate, rs._exrule,
-        rs._exdate, False if rs._cache is None else True
+        rs._rrule,
+        rs._rdate,
+        rs._exrule,
+        rs._exdate,
+        False if rs._cache is None else True,
     )
 
+
 def unpickle_rruleset_with_cache(rrule, rdate, exrule, exdate, cache):
     """unpickling the rruleset."""
     rs = rruleset(cache)
-    for o in rrule: rs.rrule(o)
-    for o in rdate: rs.rdate(o)
-    for o in exrule: rs.exrule(o)
-    for o in exdate: rs.exdate(o)
+    for o in rrule:
+        rs.rrule(o)
+    for o in rdate:
+        rs.rdate(o)
+    for o in exrule:
+        rs.exrule(o)
+    for o in exdate:
+        rs.exdate(o)
     return rs
 
+
 copyreg.pickle(rruleset, pickle_rruleset_with_cache)
 
 __all__ = ["ZONEINFO"]
diff -pruN 6.0.1-3/src/icalendar/tools.py 6.3.1-1/src/icalendar/tools.py
--- 6.0.1-3/src/icalendar/tools.py	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/src/icalendar/tools.py	2025-05-20 07:31:39.000000000 +0000
@@ -1,35 +1,113 @@
-from datetime import datetime
-from icalendar.parser_tools import to_unicode
-from icalendar.prop import vDatetime
-from icalendar.prop import vText
-from string import ascii_letters
-from string import digits
+"""Utility functions for icalendar."""
+
+from __future__ import annotations
 
 import random
+from datetime import date, datetime, tzinfo
+from string import ascii_letters, digits
+from warnings import warn
+
+from icalendar.parser_tools import to_unicode
+
+from .error import WillBeRemovedInVersion7
 
 
 class UIDGenerator:
-    """If you are too lazy to create real uid's.
+    """Use this only if you're too lazy to create real UUIDs.
+    
+    .. deprecated:: 6.2.1
 
+        Use the Python standard library's :func:`uuid.uuid4` instead.
     """
+
     chars = list(ascii_letters + digits)
 
     @staticmethod
-    def rnd_string(length=16):
+    def rnd_string(length=16) -> str:
         """Generates a string with random characters of length.
+
+         .. deprecated:: 6.2.1
+
+             Use the Python standard library's :func:`uuid.uuid4` instead.
         """
-        return ''.join([random.choice(UIDGenerator.chars) for _ in range(length)])
+        warn(
+            "Use https://docs.python.org/3/library/uuid.html#uuid.uuid4 instead.",
+            WillBeRemovedInVersion7,
+            stacklevel=1
+        )
+        return "".join([random.choice(UIDGenerator.chars) for _ in range(length)])
 
     @staticmethod
-    def uid(host_name='example.com', unique=''):
-        """Generates a unique id consisting of:
-            datetime-uniquevalue@host.
-        Like:
-            20050105T225746Z-HKtJMqUgdO0jDUwm@example.com
+    def uid(host_name="example.com", unique=""):
+        """Generates a unique ID consisting of ``datetime-uniquevalue@host``.
+
+        For example:
+            
+            .. code-block:: text
+
+                20050105T225746Z-HKtJMqUgdO0jDUwm@example.com
+        
+        .. deprecated:: 6.2.1
+
+            Use the Python standard library's :func:`uuid.uuid5` instead.
         """
+        from icalendar.prop import vDatetime, vText
+        warn(
+            "Use https://docs.python.org/3/library/uuid.html#uuid.uuid5 instead.",
+            WillBeRemovedInVersion7,
+            stacklevel=1
+        )
+
         host_name = to_unicode(host_name)
         unique = unique or UIDGenerator.rnd_string()
         today = to_unicode(vDatetime(datetime.today()).to_ical())
-        return vText(f'{today}-{unique}@{host_name}')
+        return vText(f"{today}-{unique}@{host_name}")
+
+
+def is_date(dt: date) -> bool:
+    """Whether this is a date and not a datetime."""
+    return isinstance(dt, date) and not isinstance(dt, datetime)
+
+
+def is_datetime(dt: date) -> bool:
+    """Whether this is a date and not a datetime."""
+    return isinstance(dt, datetime)
+
+
+def to_datetime(dt: date) -> datetime:
+    """Make sure we have a datetime, not a date."""
+    if is_date(dt):
+        return datetime(dt.year, dt.month, dt.day)  # noqa: DTZ001
+    return dt
+
+
+def is_pytz(tz: tzinfo):
+    """Whether the timezone requires localize() and normalize()."""
+    return hasattr(tz, "localize")
+
+
+def is_pytz_dt(dt: date):
+    """Whether the time requires localize() and normalize()."""
+    return is_datetime(dt) and is_pytz(dt.tzinfo)
+
+
+def normalize_pytz(dt: date):
+    """We have to normalize the time after a calculation if we use pytz.
+
+    pytz requires this function to be used in order to correctly calculate the
+    timezone's offset after calculations.
+    """
+    if is_pytz_dt(dt):
+        return dt.tzinfo.normalize(dt)
+    return dt
+
 
-__all__ = ["UIDGenerator"]
+__all__ = [
+    "UIDGenerator",
+    "is_date",
+    "is_datetime",
+    "to_datetime",
+    "is_pytz",
+    "is_pytz_dt",
+    "normalize_pytz",
+]
diff -pruN 6.0.1-3/tox.ini 6.3.1-1/tox.ini
--- 6.0.1-3/tox.ini	2024-10-13 16:38:15.000000000 +0000
+++ 6.3.1-1/tox.ini	2025-05-20 07:31:39.000000000 +0000
@@ -1,6 +1,6 @@
 # to run for a specific environment, use ``tox -e ENVNAME``
 [tox]
-envlist = py38,py39,py310,py311,312,pypy3,docs,nopytz
+envlist = py38,py39,py310,py311,py312,py313,pypy3,docs,nopytz
 # Note: the 'docs' env creates a 'build' directory which may interfere in strange ways
 # with the other environments.  You might see this when you run the tests in parallel.
 # See https://github.com/collective/icalendar/pull/359#issuecomment-1214150269
@@ -35,9 +35,10 @@ deps =
     -r {toxinidir}/requirements_docs.txt
     setuptools
 changedir = docs
-allowlist_externals = make
+allowlist_externals =
+    make
 commands =
-    make html
+    make clean html
 
 [testenv:ruff]
 # use tox -e ruff to format the code base
