Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/icalendar/tools.py: 91%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1"""Utility functions for icalendar."""
3from __future__ import annotations
5from datetime import date, datetime, tzinfo
6from typing import TYPE_CHECKING, Union, cast
9if TYPE_CHECKING:
10 from icalendar.compatibility import TypeGuard, TypeIs
13def is_date(dt: Union[date, datetime]) -> bool:
14 """Check if a value is a date but not a datetime.
16 This function distinguishes between ``date`` and ``datetime`` objects,
17 returning ``True`` only for pure ``date`` instances.
19 Args:
20 dt: The date or datetime object to check.
22 Returns:
23 ``True`` if the value is a ``date`` but not a ``datetime``,
24 ``False`` otherwise.
26 Example:
27 .. code-block:: pycon
29 >>> from datetime import date, datetime
30 >>> from icalendar.tools import is_date
31 >>> is_date(date(2024, 1, 15))
32 True
33 >>> is_date(datetime(2024, 1, 15, 10, 30))
34 False
35 """
36 return isinstance(dt, date) and not isinstance(dt, datetime)
39def is_datetime(dt: Union[date, datetime]) -> TypeIs[datetime]:
40 """Check if a value is a datetime.
42 Args:
43 dt: The date or datetime object to check.
45 Returns:
46 ``True`` if the value is a ``datetime``, ``False`` if it is
47 only a ``date``.
49 Example:
50 .. code-block:: pycon
52 >>> from datetime import date, datetime
53 >>> from icalendar.tools import is_datetime
54 >>> is_datetime(datetime(2024, 1, 15, 10, 30))
55 True
56 >>> is_datetime(date(2024, 1, 15))
57 False
58 """
59 return isinstance(dt, datetime)
62def to_datetime(dt: Union[date, datetime]) -> datetime:
63 """Convert a date to a datetime.
65 If the input is already a ``datetime``, it is returned unchanged.
66 If the input is a ``date``, it is converted to a ``datetime`` at midnight.
68 Args:
69 dt: The date or datetime to convert.
71 Returns:
72 A ``datetime`` object. If the input was a ``date``, the time
73 component will be set to midnight (00:00:00).
75 Example:
76 .. code-block:: pycon
78 >>> from datetime import date, datetime
79 >>> from icalendar.tools import to_datetime
80 >>> to_datetime(date(2024, 1, 15))
81 datetime.datetime(2024, 1, 15, 0, 0)
82 >>> to_datetime(datetime(2024, 1, 15, 10, 30))
83 datetime.datetime(2024, 1, 15, 10, 30)
84 """
85 if is_date(dt):
86 return datetime(dt.year, dt.month, dt.day) # noqa: DTZ001
87 return cast("datetime", dt)
90def is_pytz(tz: tzinfo) -> bool:
91 """Check if a timezone is a pytz timezone.
93 pytz timezones require special handling with ``localize()`` and
94 ``normalize()`` methods for correct timezone calculations.
96 Args:
97 tz: The timezone info object to check.
99 Returns:
100 ``True`` if the timezone is a pytz timezone (has a ``localize``
101 attribute), ``False`` otherwise.
102 """
103 return hasattr(tz, "localize")
106def is_pytz_dt(dt: Union[date, datetime]) -> TypeGuard[datetime]:
107 """Check if a datetime uses a pytz timezone.
109 This function checks whether the datetime has a timezone attached
110 and whether that timezone is a pytz timezone requiring special handling.
112 Args:
113 dt: The date or datetime object to check.
115 Returns:
116 ``True`` if the value is a ``datetime`` with a pytz timezone,
117 ``False`` otherwise.
118 """
119 return is_datetime(dt) and (tzinfo := dt.tzinfo) is not None and is_pytz(tzinfo)
122def normalize_pytz(dt: Union[date, datetime]) -> Union[date, datetime]:
123 """Normalize a datetime after calculations when using pytz.
125 pytz requires the ``normalize()`` function to be called after arithmetic
126 operations to correctly adjust the timezone offset, especially around
127 daylight saving time transitions.
129 Args:
130 dt: The date or datetime to normalize.
132 Returns:
133 The normalized datetime if it uses pytz, otherwise the input unchanged.
134 """
135 if is_pytz_dt(dt):
136 return dt.tzinfo.normalize(dt) # type: ignore[attr-defined]
137 return dt
140__all__ = [
141 "is_date",
142 "is_datetime",
143 "is_pytz",
144 "is_pytz_dt",
145 "normalize_pytz",
146 "to_datetime",
147]