22
33import functools
44import os
5+ import sys
56from datetime import datetime , time , tzinfo
7+ from zoneinfo import ZoneInfo as _ZoneInfo
8+ from zoneinfo import ZoneInfoNotFoundError
69
7- import pytz
10+ if sys .version_info >= (3 , 12 ):
11+ from datetime import UTC
12+ else :
13+ from datetime import timezone
14+
15+ UTC = timezone .utc
816
917
1018@functools .cache
@@ -28,7 +36,7 @@ def now() -> datetime:
2836 Return an aware datetime.datetime, depending on use_tz and timezone.
2937 """
3038 if get_use_tz ():
31- return datetime .now (tz = pytz . utc )
39+ return datetime .now (tz = UTC )
3240 else :
3341 return datetime .now (get_default_timezone ())
3442
@@ -40,7 +48,32 @@ def get_default_timezone() -> tzinfo:
4048
4149 This is the time zone defined by Tortoise config.
4250 """
43- return pytz .timezone (get_timezone ())
51+ return parse_timezone (get_timezone ())
52+
53+
54+ class ZoneInfo (_ZoneInfo ):
55+ @property
56+ def zone (self ) -> str :
57+ # Compatible with pytz:
58+ # >>> ZoneInfo('UTC').key == pytz.timezone('UTC').zone == 'UTC'
59+ return self .key
60+
61+
62+ def parse_timezone (zone : str ) -> tzinfo :
63+ if zone .upper () == "UTC" :
64+ return ZoneInfo ("UTC" )
65+ try :
66+ return ZoneInfo (zone )
67+ except ZoneInfoNotFoundError as e :
68+ words = zone .split ("/" )
69+ # Compatible with `pytz.timezone`:
70+ # US/central -> US/Central
71+ # Europe/moscow -> Europe/Moscow
72+ # asia/ShangHai -> Asia/Shanghai
73+ styled = "/" .join ([i if i .isupper () else i .title () for i in words ])
74+ if styled != zone :
75+ return ZoneInfo (zone )
76+ raise e
4477
4578
4679def _reset_timezone_cache () -> None :
@@ -64,7 +97,7 @@ def localtime(value: datetime | None = None, timezone: str | None = None) -> dat
6497 """
6598 if value is None :
6699 value = now ()
67- tz = get_default_timezone () if timezone is None else pytz . timezone (timezone )
100+ tz = get_default_timezone () if timezone is None else parse_timezone (timezone )
68101 if is_naive (value ):
69102 raise ValueError ("localtime() cannot be applied to a naive datetime" )
70103 return value .astimezone (tz )
@@ -104,7 +137,7 @@ def make_aware(
104137
105138 :raises ValueError: when value is not naive datetime
106139 """
107- tz = get_default_timezone () if timezone is None else pytz . timezone (timezone )
140+ tz = get_default_timezone () if timezone is None else parse_timezone (timezone )
108141 if hasattr (tz , "localize" ):
109142 return tz .localize (value , is_dst = is_dst )
110143 if is_aware (value ):
@@ -119,7 +152,7 @@ def make_naive(value: datetime, timezone: str | None = None) -> datetime:
119152
120153 :raises ValueError: when value is naive datetime
121154 """
122- tz = get_default_timezone () if timezone is None else pytz . timezone (timezone )
155+ tz = get_default_timezone () if timezone is None else parse_timezone (timezone )
123156 if is_naive (value ):
124157 raise ValueError ("make_naive() cannot be applied to a naive datetime" )
125158 return value .astimezone (tz ).replace (tzinfo = None )
0 commit comments