22
33import datetime as _datetime
44
5- from typing import Optional
65from typing import Union
6+ from typing import cast
77
88from pendulum .__version__ import __version__
99from pendulum .constants import DAYS_PER_WEEK
4040from pendulum .parser import parse
4141from pendulum .period import Period
4242from pendulum .time import Time
43- from pendulum .tz import POST_TRANSITION
44- from pendulum .tz import PRE_TRANSITION
45- from pendulum .tz import TRANSITION_ERROR
4643from pendulum .tz import UTC
4744from pendulum .tz import local_timezone
4845from pendulum .tz import set_local_timezone
5249from pendulum .tz .timezone import FixedTimezone
5350from pendulum .tz .timezone import Timezone
5451
55-
5652_TEST_NOW : DateTime | None = None
5753_LOCALE = "en"
5854_WEEK_STARTS_AT = MONDAY
6157_formatter = Formatter ()
6258
6359
64- def _safe_timezone (obj : str | float | _datetime .tzinfo | Timezone | None ) -> Timezone :
60+ def _safe_timezone (
61+ obj : str | float | _datetime .tzinfo | Timezone | FixedTimezone | None ,
62+ dt : _datetime .datetime | None = None ,
63+ ) -> Timezone | FixedTimezone :
6564 """
6665 Creates a timezone instance
6766 from a string, Timezone, TimezoneInfo or integer offset.
@@ -75,19 +74,24 @@ def _safe_timezone(obj: str | float | _datetime.tzinfo | Timezone | None) -> Tim
7574 if isinstance (obj , (int , float )):
7675 obj = int (obj * 60 * 60 )
7776 elif isinstance (obj , _datetime .tzinfo ):
77+ # zoneinfo
78+ if hasattr (obj , "key" ):
79+ obj = obj .key # type: ignore
7880 # pytz
79- if hasattr (obj , "localize" ):
80- obj = obj .zone
81+ elif hasattr (obj , "localize" ):
82+ obj = obj .zone # type: ignore
8183 elif obj .tzname (None ) == "UTC" :
8284 return UTC
8385 else :
84- offset = obj .utcoffset (None )
86+ offset = obj .utcoffset (dt )
8587
8688 if offset is None :
8789 offset = _datetime .timedelta (0 )
8890
8991 obj = int (offset .total_seconds ())
9092
93+ obj = cast (Union [str , int ], obj )
94+
9195 return timezone (obj )
9296
9397
@@ -100,8 +104,8 @@ def datetime(
100104 minute : int = 0 ,
101105 second : int = 0 ,
102106 microsecond : int = 0 ,
103- tz : str | float | Timezone | None = UTC ,
104- fold : int | None = 1 ,
107+ tz : str | float | Timezone | FixedTimezone | _datetime . tzinfo | None = UTC ,
108+ fold : int = 1 ,
105109 raise_on_unknown_times : bool = False ,
106110) -> DateTime :
107111 """
@@ -146,7 +150,7 @@ def naive(
146150 minute : int = 0 ,
147151 second : int = 0 ,
148152 microsecond : int = 0 ,
149- fold : int | None = 1 ,
153+ fold : int = 1 ,
150154) -> DateTime :
151155 """
152156 Return a naive DateTime.
@@ -168,7 +172,10 @@ def time(hour: int, minute: int = 0, second: int = 0, microsecond: int = 0) -> T
168172 return Time (hour , minute , second , microsecond )
169173
170174
171- def instance (dt : _datetime .datetime , tz : str | Timezone | None = UTC ) -> DateTime :
175+ def instance (
176+ dt : _datetime .datetime ,
177+ tz : str | Timezone | FixedTimezone | _datetime .tzinfo | None = UTC ,
178+ ) -> DateTime :
172179 """
173180 Create a DateTime instance from a datetime one.
174181 """
@@ -180,19 +187,18 @@ def instance(dt: _datetime.datetime, tz: str | Timezone | None = UTC) -> DateTim
180187
181188 tz = dt .tzinfo or tz
182189
183- # Checking for pytz/tzinfo
184- if isinstance (tz , _datetime .tzinfo ) and not isinstance (tz , Timezone ):
185- # pytz
186- if hasattr (tz , "localize" ) and tz .zone :
187- tz = tz .zone
188- else :
189- # We have no sure way to figure out
190- # the timezone name, we fallback
191- # on a fixed offset
192- tz = tz .utcoffset (dt ).total_seconds () / 3600
190+ if tz is not None :
191+ tz = _safe_timezone (tz , dt = dt )
193192
194193 return datetime (
195- dt .year , dt .month , dt .day , dt .hour , dt .minute , dt .second , dt .microsecond , tz = tz
194+ dt .year ,
195+ dt .month ,
196+ dt .day ,
197+ dt .hour ,
198+ dt .minute ,
199+ dt .second ,
200+ dt .microsecond ,
201+ tz = cast (Union [str , int , Timezone , FixedTimezone , None ], tz ),
196202 )
197203
198204
@@ -228,12 +234,13 @@ def from_format(
228234 string : str ,
229235 fmt : str ,
230236 tz : str | Timezone = UTC ,
231- locale : str | None = None , # noqa
237+ locale : str | None = None ,
232238) -> DateTime :
233239 """
234240 Creates a DateTime instance from a specific format.
235241 """
236242 parts = _formatter .parse (string , fmt , now (), locale = locale )
243+
237244 if parts ["tz" ] is None :
238245 parts ["tz" ] = tz
239246
@@ -288,3 +295,64 @@ def period(start: DateTime, end: DateTime, absolute: bool = False) -> Period:
288295 Create a Period instance.
289296 """
290297 return Period (start , end , absolute = absolute )
298+
299+
300+ __all__ = [
301+ "__version__" ,
302+ "DAYS_PER_WEEK" ,
303+ "FRIDAY" ,
304+ "HOURS_PER_DAY" ,
305+ "MINUTES_PER_HOUR" ,
306+ "MONDAY" ,
307+ "MONTHS_PER_YEAR" ,
308+ "SATURDAY" ,
309+ "SECONDS_PER_DAY" ,
310+ "SECONDS_PER_HOUR" ,
311+ "SECONDS_PER_MINUTE" ,
312+ "SUNDAY" ,
313+ "THURSDAY" ,
314+ "TUESDAY" ,
315+ "WEDNESDAY" ,
316+ "WEEKS_PER_YEAR" ,
317+ "YEARS_PER_CENTURY" ,
318+ "YEARS_PER_DECADE" ,
319+ "Date" ,
320+ "DateTime" ,
321+ "Duration" ,
322+ "Formatter" ,
323+ "date" ,
324+ "datetime" ,
325+ "duration" ,
326+ "format_diff" ,
327+ "from_format" ,
328+ "from_timestamp" ,
329+ "get_locale" ,
330+ "get_test_now" ,
331+ "has_test_now" ,
332+ "instance" ,
333+ "local" ,
334+ "locale" ,
335+ "naive" ,
336+ "now" ,
337+ "period" ,
338+ "set_locale" ,
339+ "set_test_now" ,
340+ "test" ,
341+ "week_ends_at" ,
342+ "week_starts_at" ,
343+ "parse" ,
344+ "Period" ,
345+ "Time" ,
346+ "UTC" ,
347+ "local_timezone" ,
348+ "set_local_timezone" ,
349+ "test_local_timezone" ,
350+ "time" ,
351+ "timezone" ,
352+ "timezones" ,
353+ "today" ,
354+ "tomorrow" ,
355+ "FixedTimezone" ,
356+ "Timezone" ,
357+ "yesterday" ,
358+ ]
0 commit comments