Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pendulum/_extensions/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ def _get_tzinfo_name(tzinfo: datetime.tzinfo | None) -> str | None:

if hasattr(tzinfo, "key"):
# zoneinfo timezone
return cast(str, cast(zoneinfo.ZoneInfo, tzinfo).key)
return cast(zoneinfo.ZoneInfo, tzinfo).key
elif hasattr(tzinfo, "name"):
# Pendulum timezone
return cast(Timezone, tzinfo).name
Expand Down
10 changes: 5 additions & 5 deletions pendulum/formatting/formatter.py
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,7 @@ def _check_parsed(

if parsed["quarter"] is not None:
if validated["year"] is not None:
dt = pendulum.datetime(validated["year"], 1, 1)
dt = pendulum.datetime(cast(int, validated["year"]), 1, 1)
else:
dt = now

Expand Down Expand Up @@ -476,8 +476,8 @@ def _check_parsed(
if parsed["day_of_week"] is not None:
dt = pendulum.datetime(
cast(int, validated["year"]),
validated["month"] or now.month,
validated["day"] or now.day,
cast(int, validated["month"]) or now.month,
cast(int, validated["day"]) or now.day,
)
dt = dt.start_of("week").subtract(days=1)
dt = dt.next(parsed["day_of_week"])
Expand All @@ -502,9 +502,9 @@ def _check_parsed(
raise ValueError("Invalid date")

pm = parsed["meridiem"] == "pm"
validated["hour"] %= 12
validated["hour"] %= 12 # type: ignore
if pm:
validated["hour"] += 12
validated["hour"] += 12 # type: ignore

if validated["month"] is None:
if parsed["year"] is not None:
Expand Down
3 changes: 2 additions & 1 deletion pendulum/parsing/iso8601.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from pendulum.parsing.exceptions import ParserError
from pendulum.tz.timezone import UTC
from pendulum.tz.timezone import FixedTimezone
from pendulum.tz.timezone import Timezone

ISO8601_DT = re.compile(
# Date (optional) # noqa: E800
Expand Down Expand Up @@ -107,7 +108,7 @@ def parse_iso8601(
minute = 0
second = 0
microsecond = 0
tzinfo: FixedTimezone | None = None
tzinfo: FixedTimezone | Timezone | None = None

if m.group("date"):
# A date has been specified
Expand Down
4 changes: 2 additions & 2 deletions pendulum/tz/local_timezone.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ def _get_unix_timezone(_root: str = "/") -> Timezone:
continue

with open(tzpath, "rb") as f:
return cast(Timezone, Timezone.from_file(f))
return Timezone.from_file(f)

raise RuntimeError("Unable to find any timezone configuration")

Expand All @@ -251,7 +251,7 @@ def _tz_from_env(tzenv: str) -> Timezone:
# TZ specifies a file
if os.path.isfile(tzenv):
with open(tzenv, "rb") as f:
return cast(Timezone, Timezone.from_file(f))
return Timezone.from_file(f)

# TZ specifies a zoneinfo zone.
try:
Expand Down
27 changes: 20 additions & 7 deletions pendulum/tz/timezone.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def datetime(
raise NotImplementedError


class Timezone(zoneinfo.ZoneInfo, PendulumTimezone): # type: ignore[misc]
class Timezone(zoneinfo.ZoneInfo, PendulumTimezone):
"""
Represents a named timezone.

Expand All @@ -54,13 +54,13 @@ class Timezone(zoneinfo.ZoneInfo, PendulumTimezone): # type: ignore[misc]

def __new__(cls, key: str) -> Timezone:
try:
return cast(Timezone, super().__new__(cls, key))
return super().__new__(cls, key) # type: ignore[call-arg]
except zoneinfo.ZoneInfoNotFoundError:
raise InvalidTimezone(key)

@property
def name(self) -> str:
return cast(str, self.key)
return self.key

def convert(
self, dt: datetime_.datetime, raise_on_unknown_times: bool = False
Expand All @@ -86,11 +86,24 @@ def convert(
'2013-03-30T21:30:00-04:00'
"""
if dt.tzinfo is None:
offset_before = (
self.utcoffset(dt.replace(fold=0)) if dt.fold else self.utcoffset(dt)
# Technically, utcoffset() can return None, but none of the zone information
# in tzdata sets _tti_before to None. This can be checked with the following
# code:
#
# >>> import zoneinfo
# >>> from zoneinfo._zoneinfo import ZoneInfo
#
# >>> for tzname in zoneinfo.available_timezones():
# >>> if ZoneInfo(tzname)._tti_before is None:
# >>> print(tzname)

offset_before = cast(
datetime_.timedelta,
(self.utcoffset(dt.replace(fold=0)) if dt.fold else self.utcoffset(dt)),
)
offset_after = (
self.utcoffset(dt) if dt.fold else self.utcoffset(dt.replace(fold=1))
offset_after = cast(
datetime_.timedelta,
(self.utcoffset(dt) if dt.fold else self.utcoffset(dt.replace(fold=1))),
)

if offset_after > offset_before:
Expand Down
6 changes: 3 additions & 3 deletions pendulum/utils/_compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
PYPY = hasattr(sys, "pypy_version_info")
PY38 = sys.version_info[:2] >= (3, 8)

try:
if sys.version_info < (3, 9):
from backports import zoneinfo
except ImportError:
import zoneinfo # type: ignore[no-redef]
else:
import zoneinfo

__all__ = ["zoneinfo"]