1try:
2 import pytz
3except ModuleNotFoundError:
4 pytz = None
5
6try:
7 import zoneinfo
8except ModuleNotFoundError:
9 zoneinfo = None
10
11
12def _get_tzinfo(tzenv: str):
13 """Get the tzinfo from `zoneinfo` or `pytz`
14
15 :param tzenv: timezone in the form of Continent/City
16 :return: tzinfo object or None if not found
17 """
18 if pytz:
19 try:
20 return pytz.timezone(tzenv)
21 except pytz.UnknownTimeZoneError:
22 pass
23 else:
24 try:
25 return zoneinfo.ZoneInfo(tzenv)
26 except ValueError as ve:
27 # This is somewhat hacky, but since _validate_tzfile_path() doesn't
28 # raise a specific error type, we'll need to check the message to be
29 # one we know to be from that function.
30 # If so, we pretend it meant that the TZ didn't exist, for the benefit
31 # of `babel.localtime` catching the `LookupError` raised by
32 # `_get_tzinfo_or_raise()`.
33 # See https://github.com/python-babel/babel/issues/1092
34 if str(ve).startswith("ZoneInfo keys "):
35 return None
36 except zoneinfo.ZoneInfoNotFoundError:
37 pass
38
39 return None
40
41
42def _get_tzinfo_or_raise(tzenv: str):
43 tzinfo = _get_tzinfo(tzenv)
44 if tzinfo is None:
45 raise LookupError(
46 f"Can not find timezone {tzenv}. \n"
47 "Timezone names are generally in the form `Continent/City`.",
48 )
49 return tzinfo
50
51
52def _get_tzinfo_from_file(tzfilename: str):
53 with open(tzfilename, 'rb') as tzfile:
54 if pytz:
55 return pytz.tzfile.build_tzinfo('local', tzfile)
56 else:
57 return zoneinfo.ZoneInfo.from_file(tzfile)