Use zoneinfo instead of dateutil (#50387)
Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
parent
3fab21ebc7
commit
f8584c3ded
4 changed files with 31 additions and 9 deletions
|
@ -8,6 +8,7 @@ async-upnp-client==0.17.0
|
||||||
async_timeout==3.0.1
|
async_timeout==3.0.1
|
||||||
attrs==21.2.0
|
attrs==21.2.0
|
||||||
awesomeversion==21.2.3
|
awesomeversion==21.2.3
|
||||||
|
backports.zoneinfo;python_version<"3.9"
|
||||||
bcrypt==3.1.7
|
bcrypt==3.1.7
|
||||||
certifi>=2020.12.5
|
certifi>=2020.12.5
|
||||||
ciso8601==2.1.3
|
ciso8601==2.1.3
|
||||||
|
@ -24,7 +25,6 @@ paho-mqtt==1.5.1
|
||||||
pillow==8.1.2
|
pillow==8.1.2
|
||||||
pip>=8.0.3,<20.3
|
pip>=8.0.3,<20.3
|
||||||
pyroute2==0.5.18
|
pyroute2==0.5.18
|
||||||
python-dateutil==2.8.1
|
|
||||||
python-slugify==4.0.1
|
python-slugify==4.0.1
|
||||||
pyyaml==5.4.1
|
pyyaml==5.4.1
|
||||||
requests==2.25.1
|
requests==2.25.1
|
||||||
|
|
|
@ -6,8 +6,12 @@ import datetime as dt
|
||||||
import re
|
import re
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
try:
|
||||||
|
import zoneinfo
|
||||||
|
except ImportError:
|
||||||
|
from backports import zoneinfo
|
||||||
|
|
||||||
import ciso8601
|
import ciso8601
|
||||||
from dateutil import tz
|
|
||||||
|
|
||||||
from homeassistant.const import MATCH_ALL
|
from homeassistant.const import MATCH_ALL
|
||||||
|
|
||||||
|
@ -43,7 +47,10 @@ def get_time_zone(time_zone_str: str) -> dt.tzinfo | None:
|
||||||
|
|
||||||
Async friendly.
|
Async friendly.
|
||||||
"""
|
"""
|
||||||
return tz.gettz(time_zone_str)
|
try:
|
||||||
|
return zoneinfo.ZoneInfo(time_zone_str) # type: ignore
|
||||||
|
except zoneinfo.ZoneInfoNotFoundError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def utcnow() -> dt.datetime:
|
def utcnow() -> dt.datetime:
|
||||||
|
@ -311,7 +318,7 @@ def find_next_time_expression_time(
|
||||||
if result.tzinfo in (None, UTC):
|
if result.tzinfo in (None, UTC):
|
||||||
return result
|
return result
|
||||||
|
|
||||||
if tz.datetime_ambiguous(result):
|
if _datetime_ambiguous(result):
|
||||||
# This happens when we're leaving daylight saving time and local
|
# This happens when we're leaving daylight saving time and local
|
||||||
# clocks are rolled back. In this case, we want to trigger
|
# clocks are rolled back. In this case, we want to trigger
|
||||||
# on both the DST and non-DST time. So when "now" is in the DST
|
# on both the DST and non-DST time. So when "now" is in the DST
|
||||||
|
@ -320,7 +327,7 @@ def find_next_time_expression_time(
|
||||||
if result.fold != fold:
|
if result.fold != fold:
|
||||||
result = result.replace(fold=fold)
|
result = result.replace(fold=fold)
|
||||||
|
|
||||||
if not tz.datetime_exists(result):
|
if not _datetime_exists(result):
|
||||||
# This happens when we're entering daylight saving time and local
|
# This happens when we're entering daylight saving time and local
|
||||||
# clocks are rolled forward, thus there are local times that do
|
# clocks are rolled forward, thus there are local times that do
|
||||||
# not exist. In this case, we want to trigger on the next time
|
# not exist. In this case, we want to trigger on the next time
|
||||||
|
@ -337,11 +344,26 @@ def find_next_time_expression_time(
|
||||||
# For example: if triggering on 2:30 and now is 28.10.2018 2:30 (in DST)
|
# For example: if triggering on 2:30 and now is 28.10.2018 2:30 (in DST)
|
||||||
# we should trigger next on 28.10.2018 2:30 (out of DST), but our
|
# we should trigger next on 28.10.2018 2:30 (out of DST), but our
|
||||||
# algorithm above would produce 29.10.2018 2:30 (out of DST)
|
# algorithm above would produce 29.10.2018 2:30 (out of DST)
|
||||||
if tz.datetime_ambiguous(now):
|
if _datetime_ambiguous(now):
|
||||||
check_result = find_next_time_expression_time(
|
check_result = find_next_time_expression_time(
|
||||||
now + _dst_offset_diff(now), seconds, minutes, hours
|
now + _dst_offset_diff(now), seconds, minutes, hours
|
||||||
)
|
)
|
||||||
if tz.datetime_ambiguous(check_result):
|
if _datetime_ambiguous(check_result):
|
||||||
return check_result
|
return check_result
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def _datetime_exists(dattim: dt.datetime) -> bool:
|
||||||
|
"""Check if a datetime exists."""
|
||||||
|
assert dattim.tzinfo is not None
|
||||||
|
original_tzinfo = dattim.tzinfo
|
||||||
|
# Check if we can round trip to UTC
|
||||||
|
return dattim == dattim.astimezone(UTC).astimezone(original_tzinfo)
|
||||||
|
|
||||||
|
|
||||||
|
def _datetime_ambiguous(dattim: dt.datetime) -> bool:
|
||||||
|
"""Check whether a datetime is ambiguous."""
|
||||||
|
assert dattim.tzinfo is not None
|
||||||
|
opposite_fold = dattim.replace(fold=not dattim.fold)
|
||||||
|
return _datetime_exists(dattim) and dattim.utcoffset() != opposite_fold.utcoffset()
|
||||||
|
|
|
@ -6,6 +6,7 @@ astral==2.2
|
||||||
async_timeout==3.0.1
|
async_timeout==3.0.1
|
||||||
attrs==21.2.0
|
attrs==21.2.0
|
||||||
awesomeversion==21.2.3
|
awesomeversion==21.2.3
|
||||||
|
backports.zoneinfo;python_version<"3.9"
|
||||||
bcrypt==3.1.7
|
bcrypt==3.1.7
|
||||||
certifi>=2020.12.5
|
certifi>=2020.12.5
|
||||||
ciso8601==2.1.3
|
ciso8601==2.1.3
|
||||||
|
@ -15,7 +16,6 @@ PyJWT==1.7.1
|
||||||
cryptography==3.3.2
|
cryptography==3.3.2
|
||||||
pip>=8.0.3,<20.3
|
pip>=8.0.3,<20.3
|
||||||
python-slugify==4.0.1
|
python-slugify==4.0.1
|
||||||
python-dateutil==2.8.1
|
|
||||||
pyyaml==5.4.1
|
pyyaml==5.4.1
|
||||||
requests==2.25.1
|
requests==2.25.1
|
||||||
ruamel.yaml==0.15.100
|
ruamel.yaml==0.15.100
|
||||||
|
|
2
setup.py
2
setup.py
|
@ -37,6 +37,7 @@ REQUIRES = [
|
||||||
"async_timeout==3.0.1",
|
"async_timeout==3.0.1",
|
||||||
"attrs==21.2.0",
|
"attrs==21.2.0",
|
||||||
"awesomeversion==21.2.3",
|
"awesomeversion==21.2.3",
|
||||||
|
'backports.zoneinfo;python_version<"3.9"',
|
||||||
"bcrypt==3.1.7",
|
"bcrypt==3.1.7",
|
||||||
"certifi>=2020.12.5",
|
"certifi>=2020.12.5",
|
||||||
"ciso8601==2.1.3",
|
"ciso8601==2.1.3",
|
||||||
|
@ -47,7 +48,6 @@ REQUIRES = [
|
||||||
"cryptography==3.3.2",
|
"cryptography==3.3.2",
|
||||||
"pip>=8.0.3,<20.3",
|
"pip>=8.0.3,<20.3",
|
||||||
"python-slugify==4.0.1",
|
"python-slugify==4.0.1",
|
||||||
"python-dateutil==2.8.1",
|
|
||||||
"pyyaml==5.4.1",
|
"pyyaml==5.4.1",
|
||||||
"requests==2.25.1",
|
"requests==2.25.1",
|
||||||
"ruamel.yaml==0.15.100",
|
"ruamel.yaml==0.15.100",
|
||||||
|
|
Loading…
Add table
Reference in a new issue