Skip to content

Commit 46b27c1

Browse files
authored
Fix typing of Timezone and ZoneInfo (#670)
1 parent 9d06ff3 commit 46b27c1

File tree

6 files changed

+33
-19
lines changed

6 files changed

+33
-19
lines changed

pendulum/_extensions/helpers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,7 @@ def _get_tzinfo_name(tzinfo: datetime.tzinfo | None) -> str | None:
353353

354354
if hasattr(tzinfo, "key"):
355355
# zoneinfo timezone
356-
return cast(str, cast(zoneinfo.ZoneInfo, tzinfo).key)
356+
return cast(zoneinfo.ZoneInfo, tzinfo).key
357357
elif hasattr(tzinfo, "name"):
358358
# Pendulum timezone
359359
return cast(Timezone, tzinfo).name

pendulum/formatting/formatter.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -448,7 +448,7 @@ def _check_parsed(
448448

449449
if parsed["quarter"] is not None:
450450
if validated["year"] is not None:
451-
dt = pendulum.datetime(validated["year"], 1, 1)
451+
dt = pendulum.datetime(cast(int, validated["year"]), 1, 1)
452452
else:
453453
dt = now
454454

@@ -476,8 +476,8 @@ def _check_parsed(
476476
if parsed["day_of_week"] is not None:
477477
dt = pendulum.datetime(
478478
cast(int, validated["year"]),
479-
validated["month"] or now.month,
480-
validated["day"] or now.day,
479+
cast(int, validated["month"]) or now.month,
480+
cast(int, validated["day"]) or now.day,
481481
)
482482
dt = dt.start_of("week").subtract(days=1)
483483
dt = dt.next(parsed["day_of_week"])
@@ -502,9 +502,9 @@ def _check_parsed(
502502
raise ValueError("Invalid date")
503503

504504
pm = parsed["meridiem"] == "pm"
505-
validated["hour"] %= 12
505+
validated["hour"] %= 12 # type: ignore
506506
if pm:
507-
validated["hour"] += 12
507+
validated["hour"] += 12 # type: ignore
508508

509509
if validated["month"] is None:
510510
if parsed["year"] is not None:

pendulum/parsing/iso8601.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from pendulum.parsing.exceptions import ParserError
1818
from pendulum.tz.timezone import UTC
1919
from pendulum.tz.timezone import FixedTimezone
20+
from pendulum.tz.timezone import Timezone
2021

2122
ISO8601_DT = re.compile(
2223
# Date (optional) # noqa: E800
@@ -107,7 +108,7 @@ def parse_iso8601(
107108
minute = 0
108109
second = 0
109110
microsecond = 0
110-
tzinfo: FixedTimezone | None = None
111+
tzinfo: FixedTimezone | Timezone | None = None
111112

112113
if m.group("date"):
113114
# A date has been specified

pendulum/tz/local_timezone.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ def _get_unix_timezone(_root: str = "/") -> Timezone:
239239
continue
240240

241241
with open(tzpath, "rb") as f:
242-
return cast(Timezone, Timezone.from_file(f))
242+
return Timezone.from_file(f)
243243

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

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

256256
# TZ specifies a zoneinfo zone.
257257
try:

pendulum/tz/timezone.py

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def datetime(
4242
raise NotImplementedError
4343

4444

45-
class Timezone(zoneinfo.ZoneInfo, PendulumTimezone): # type: ignore[misc]
45+
class Timezone(zoneinfo.ZoneInfo, PendulumTimezone):
4646
"""
4747
Represents a named timezone.
4848
@@ -54,13 +54,13 @@ class Timezone(zoneinfo.ZoneInfo, PendulumTimezone): # type: ignore[misc]
5454

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

6161
@property
6262
def name(self) -> str:
63-
return cast(str, self.key)
63+
return self.key
6464

6565
def convert(
6666
self, dt: datetime_.datetime, raise_on_unknown_times: bool = False
@@ -86,11 +86,24 @@ def convert(
8686
'2013-03-30T21:30:00-04:00'
8787
"""
8888
if dt.tzinfo is None:
89-
offset_before = (
90-
self.utcoffset(dt.replace(fold=0)) if dt.fold else self.utcoffset(dt)
89+
# Technically, utcoffset() can return None, but none of the zone information
90+
# in tzdata sets _tti_before to None. This can be checked with the following
91+
# code:
92+
#
93+
# >>> import zoneinfo
94+
# >>> from zoneinfo._zoneinfo import ZoneInfo
95+
#
96+
# >>> for tzname in zoneinfo.available_timezones():
97+
# >>> if ZoneInfo(tzname)._tti_before is None:
98+
# >>> print(tzname)
99+
100+
offset_before = cast(
101+
datetime_.timedelta,
102+
(self.utcoffset(dt.replace(fold=0)) if dt.fold else self.utcoffset(dt)),
91103
)
92-
offset_after = (
93-
self.utcoffset(dt) if dt.fold else self.utcoffset(dt.replace(fold=1))
104+
offset_after = cast(
105+
datetime_.timedelta,
106+
(self.utcoffset(dt) if dt.fold else self.utcoffset(dt.replace(fold=1))),
94107
)
95108

96109
if offset_after > offset_before:

pendulum/utils/_compat.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
PYPY = hasattr(sys, "pypy_version_info")
66
PY38 = sys.version_info[:2] >= (3, 8)
77

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

1313
__all__ = ["zoneinfo"]

0 commit comments

Comments
 (0)