Use zoneinfo instead of dateutil (#50387)

Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
Paulus Schoutsen
2021-05-10 08:32:29 -07:00
committed by GitHub
parent 3fab21ebc7
commit f8584c3ded
4 changed files with 31 additions and 9 deletions

View File

@@ -6,8 +6,12 @@ import datetime as dt
import re
from typing import Any
try:
import zoneinfo
except ImportError:
from backports import zoneinfo
import ciso8601
from dateutil import tz
from homeassistant.const import MATCH_ALL
@@ -43,7 +47,10 @@ def get_time_zone(time_zone_str: str) -> dt.tzinfo | None:
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:
@@ -311,7 +318,7 @@ def find_next_time_expression_time(
if result.tzinfo in (None, UTC):
return result
if tz.datetime_ambiguous(result):
if _datetime_ambiguous(result):
# This happens when we're leaving daylight saving time and local
# 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
@@ -320,7 +327,7 @@ def find_next_time_expression_time(
if result.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
# clocks are rolled forward, thus there are local times that do
# 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)
# 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)
if tz.datetime_ambiguous(now):
if _datetime_ambiguous(now):
check_result = find_next_time_expression_time(
now + _dst_offset_diff(now), seconds, minutes, hours
)
if tz.datetime_ambiguous(check_result):
if _datetime_ambiguous(check_result):
return check_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()