Source code for icalendar.prop.dt.utc_offset
"""UTC-Offset property type from :rfc:`5545`."""
import re
from datetime import timedelta
from typing import Any, ClassVar
from icalendar.compatibility import Self
from icalendar.error import JCalParsingError
from icalendar.parser import Parameters
UTC_OFFSET_JCAL_REGEX = re.compile(
r"^(?P<sign>[+-])?(?P<hours>\d\d):(?P<minutes>\d\d)(?::(?P<seconds>\d\d))?$"
)
[docs]
class vUTCOffset:
"""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)
"""
default_value: ClassVar[str] = "UTC-OFFSET"
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: timedelta, /, params: dict[str, Any] | None = None):
if not isinstance(td, timedelta):
raise TypeError("Offset value MUST be a timedelta instance")
self.td = td
self.params = Parameters(params)
[docs]
def to_ical(self) -> str:
"""Return the ical representation."""
return self.format("")
[docs]
@classmethod
def from_ical(cls, ical):
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),
)
offset = timedelta(hours=hours, minutes=minutes, seconds=seconds)
except Exception as e:
raise ValueError(f"Expected UTC offset, got: {ical}") from e
if not cls.ignore_exceptions and offset >= timedelta(hours=24):
raise ValueError(f"Offset must be less than 24 hours, was {ical}")
if sign == "-":
return -offset
return offset
def __eq__(self, other):
if not isinstance(other, vUTCOffset):
return False
return self.td == other.td
def __hash__(self):
return hash(self.td)
def __repr__(self):
return f"vUTCOffset({self.td!r})"
[docs]
@classmethod
def examples(cls) -> list[Self]:
"""Examples of vUTCOffset."""
return [
cls(timedelta(hours=3)),
cls(timedelta(0)),
]
from icalendar.param import VALUE
[docs]
def to_jcal(self, name: str) -> list:
"""The jCal representation of this property according to :rfc:`7265`."""
return [name, self.params.to_jcal(), self.VALUE.lower(), self.format(":")]
[docs]
@classmethod
def from_jcal(cls, jcal_property: list) -> Self:
"""Parse jCal from :rfc:`7265`.
Parameters:
jcal_property: The jCal property to parse.
Raises:
~error.JCalParsingError: If the provided jCal is invalid.
"""
JCalParsingError.validate_property(jcal_property, cls)
match = UTC_OFFSET_JCAL_REGEX.match(jcal_property[3])
if match is None:
raise JCalParsingError(f"Cannot parse {jcal_property!r} as UTC-OFFSET.")
negative = match.group("sign") == "-"
hours = int(match.group("hours"))
minutes = int(match.group("minutes"))
seconds = int(match.group("seconds") or 0)
t = timedelta(hours=hours, minutes=minutes, seconds=seconds)
if negative:
t = -t
return cls(t, Parameters.from_jcal_property(jcal_property))
__all__ = ["vUTCOffset"]