Skip to content

Commit

Permalink
Fix blocking I/O in the event loop when loading timezones (#117721)
Browse files Browse the repository at this point in the history
  • Loading branch information
bdraco authored May 20, 2024
1 parent 0293315 commit 5a609c3
Show file tree
Hide file tree
Showing 98 changed files with 294 additions and 217 deletions.
4 changes: 3 additions & 1 deletion homeassistant/components/ambient_network/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,9 @@ def _update_attrs(self) -> None:

# Treatments for special units.
if value is not None and self.device_class == SensorDeviceClass.TIMESTAMP:
value = datetime.fromtimestamp(value / 1000, tz=dt_util.DEFAULT_TIME_ZONE)
value = datetime.fromtimestamp(
value / 1000, tz=dt_util.get_default_time_zone()
)

self._attr_available = value is not None
self._attr_native_value = value
4 changes: 3 additions & 1 deletion homeassistant/components/caldav/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,9 @@ def to_datetime(obj):
"""Return a datetime."""
if isinstance(obj, datetime):
return CalDavUpdateCoordinator.to_local(obj)
return datetime.combine(obj, time.min).replace(tzinfo=dt_util.DEFAULT_TIME_ZONE)
return datetime.combine(obj, time.min).replace(
tzinfo=dt_util.get_default_time_zone()
)

@staticmethod
def to_local(obj: datetime | date) -> datetime | date:
Expand Down
4 changes: 1 addition & 3 deletions homeassistant/components/datetime/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,7 @@ async def _async_set_value(entity: DateTimeEntity, service_call: ServiceCall) ->
"""Service call wrapper to set a new date/time."""
value: datetime = service_call.data[ATTR_DATETIME]
if value.tzinfo is None:
value = value.replace(
tzinfo=dt_util.get_time_zone(entity.hass.config.time_zone)
)
value = value.replace(tzinfo=dt_util.get_default_time_zone())
return await entity.async_set_value(value)


Expand Down
19 changes: 12 additions & 7 deletions homeassistant/components/ecobee/switch.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from __future__ import annotations

from datetime import tzinfo
import logging
from typing import Any

Expand Down Expand Up @@ -29,12 +30,17 @@ async def async_setup_entry(
data: EcobeeData = hass.data[DOMAIN]

async_add_entities(
(
EcobeeVentilator20MinSwitch(data, index)
[
EcobeeVentilator20MinSwitch(
data,
index,
(await dt_util.async_get_time_zone(thermostat["location"]["timeZone"]))
or dt_util.get_default_time_zone(),
)
for index, thermostat in enumerate(data.ecobee.thermostats)
if thermostat["settings"]["ventilatorType"] != "none"
),
True,
],
update_before_add=True,
)


Expand All @@ -48,15 +54,14 @@ def __init__(
self,
data: EcobeeData,
thermostat_index: int,
operating_timezone: tzinfo,
) -> None:
"""Initialize ecobee ventilator platform."""
super().__init__(data, thermostat_index)
self._attr_unique_id = f"{self.base_unique_id}_ventilator_20m_timer"
self._attr_is_on = False
self.update_without_throttle = False
self._operating_timezone = dt_util.get_time_zone(
self.thermostat["location"]["timeZone"]
)
self._operating_timezone = operating_timezone

async def async_update(self) -> None:
"""Get the latest state from the thermostat."""
Expand Down
4 changes: 2 additions & 2 deletions homeassistant/components/electric_kiwi/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,13 +91,13 @@ def _check_and_move_time(hop: Hop, time: str) -> datetime:
date_time = datetime.combine(
dt_util.start_of_local_day(),
datetime.strptime(time, "%I:%M %p").time(),
dt_util.DEFAULT_TIME_ZONE,
dt_util.get_default_time_zone(),
)

end_time = datetime.combine(
dt_util.start_of_local_day(),
datetime.strptime(hop.end.end_time, "%I:%M %p").time(),
dt_util.DEFAULT_TIME_ZONE,
dt_util.get_default_time_zone(),
)

if end_time < dt_util.now():
Expand Down
4 changes: 1 addition & 3 deletions homeassistant/components/gardena_bluetooth/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,7 @@ class GardenaBluetoothSensor(GardenaBluetoothDescriptorEntity, SensorEntity):
def _handle_coordinator_update(self) -> None:
value = self.coordinator.get_cached(self.entity_description.char)
if isinstance(value, datetime):
value = value.replace(
tzinfo=dt_util.get_time_zone(self.hass.config.time_zone)
)
value = value.replace(tzinfo=dt_util.get_default_time_zone())
self._attr_native_value = value

if char := self.entity_description.connected_state:
Expand Down
4 changes: 2 additions & 2 deletions homeassistant/components/google/calendar.py
Original file line number Diff line number Diff line change
Expand Up @@ -341,11 +341,11 @@ async def async_create_event(self, **kwargs: Any) -> None:
if isinstance(dtstart, datetime):
start = DateOrDatetime(
date_time=dt_util.as_local(dtstart),
timezone=str(dt_util.DEFAULT_TIME_ZONE),
timezone=str(dt_util.get_default_time_zone()),
)
end = DateOrDatetime(
date_time=dt_util.as_local(dtend),
timezone=str(dt_util.DEFAULT_TIME_ZONE),
timezone=str(dt_util.get_default_time_zone()),
)
else:
start = DateOrDatetime(date=dtstart)
Expand Down
4 changes: 2 additions & 2 deletions homeassistant/components/google/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def _truncate_timeline(timeline: Timeline, max_events: int) -> Timeline:
truncated = list(itertools.islice(upcoming, max_events))
return Timeline(
[
SortableItemValue(event.timespan_of(dt_util.DEFAULT_TIME_ZONE), event)
SortableItemValue(event.timespan_of(dt_util.get_default_time_zone()), event)
for event in truncated
]
)
Expand Down Expand Up @@ -73,7 +73,7 @@ async def _async_update_data(self) -> Timeline:
raise UpdateFailed(f"Error communicating with API: {err}") from err

timeline = await self.sync.store_service.async_get_timeline(
dt_util.DEFAULT_TIME_ZONE
dt_util.get_default_time_zone()
)
self._upcoming_timeline = _truncate_timeline(timeline, MAX_UPCOMING_EVENTS)
return timeline
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/google/diagnostics.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ async def async_get_config_entry_diagnostics(
"""Return diagnostics for a config entry."""
payload: dict[str, Any] = {
"now": dt_util.now().isoformat(),
"timezone": str(dt_util.DEFAULT_TIME_ZONE),
"timezone": str(dt_util.get_default_time_zone()),
"system_timezone": str(datetime.datetime.now().astimezone().tzinfo),
}

Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/growatt_server/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ def update(self):
date_now = dt_util.now().date()
last_updated_time = dt_util.parse_time(str(sorted_keys[-1]))
mix_detail["lastdataupdate"] = datetime.datetime.combine(
date_now, last_updated_time, dt_util.DEFAULT_TIME_ZONE
date_now, last_updated_time, dt_util.get_default_time_zone()
)

# Dashboard data is largely inaccurate for mix system but it is the only
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/homeassistant/triggers/time.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ def update_entity_trigger(entity_id: str, new_state: State | None = None) -> Non
hour,
minute,
second,
tzinfo=dt_util.DEFAULT_TIME_ZONE,
tzinfo=dt_util.get_default_time_zone(),
)
# Only set up listener if time is now or in the future.
if trigger_dt >= dt_util.now():
Expand Down
8 changes: 4 additions & 4 deletions homeassistant/components/input_datetime/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -237,11 +237,11 @@ def __init__(self, config: ConfigType) -> None:
# If the user passed in an initial value with a timezone, convert it to right tz
if current_datetime.tzinfo is not None:
self._current_datetime = current_datetime.astimezone(
dt_util.DEFAULT_TIME_ZONE
dt_util.get_default_time_zone()
)
else:
self._current_datetime = current_datetime.replace(
tzinfo=dt_util.DEFAULT_TIME_ZONE
tzinfo=dt_util.get_default_time_zone()
)

@classmethod
Expand Down Expand Up @@ -295,7 +295,7 @@ async def async_added_to_hass(self):
)

self._current_datetime = current_datetime.replace(
tzinfo=dt_util.DEFAULT_TIME_ZONE
tzinfo=dt_util.get_default_time_zone()
)

@property
Expand Down Expand Up @@ -409,7 +409,7 @@ def async_set_datetime(self, date=None, time=None, datetime=None, timestamp=None
time = self._current_datetime.time()

self._current_datetime = py_datetime.datetime.combine(
date, time, dt_util.DEFAULT_TIME_ZONE
date, time, dt_util.get_default_time_zone()
)
self.async_write_ha_state()

Expand Down
8 changes: 5 additions & 3 deletions homeassistant/components/knx/datetime.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ async def async_added_to_hass(self) -> None:
):
self._device.remote_value.value = (
datetime.fromisoformat(last_state.state)
.astimezone(dt_util.DEFAULT_TIME_ZONE)
.astimezone(dt_util.get_default_time_zone())
.timetuple()
)

Expand All @@ -96,9 +96,11 @@ def native_value(self) -> datetime | None:
hour=time_struct.tm_hour,
minute=time_struct.tm_min,
second=min(time_struct.tm_sec, 59), # account for leap seconds
tzinfo=dt_util.DEFAULT_TIME_ZONE,
tzinfo=dt_util.get_default_time_zone(),
)

async def async_set_value(self, value: datetime) -> None:
"""Change the value."""
await self._device.set(value.astimezone(dt_util.DEFAULT_TIME_ZONE).timetuple())
await self._device.set(
value.astimezone(dt_util.get_default_time_zone()).timetuple()
)
2 changes: 1 addition & 1 deletion homeassistant/components/litterrobot/time.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def _as_local_time(start: datetime | None) -> time | None:
entity_category=EntityCategory.CONFIG,
value_fn=lambda robot: _as_local_time(robot.sleep_mode_start_time),
set_fn=lambda robot, value: robot.set_sleep_mode(
robot.sleep_mode_enabled, value.replace(tzinfo=dt_util.DEFAULT_TIME_ZONE)
robot.sleep_mode_enabled, value.replace(tzinfo=dt_util.get_default_time_zone())
),
)

Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/local_calendar/diagnostics.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ async def async_get_config_entry_diagnostics(
"""Return diagnostics for a config entry."""
payload: dict[str, Any] = {
"now": dt_util.now().isoformat(),
"timezone": str(dt_util.DEFAULT_TIME_ZONE),
"timezone": str(dt_util.get_default_time_zone()),
"system_timezone": str(datetime.datetime.now().astimezone().tzinfo),
}
store = hass.data[DOMAIN][config_entry.entry_id]
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/local_todo/todo.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ def __init__(
self._attr_unique_id = unique_id

def _new_todo_store(self) -> TodoStore:
return TodoStore(self._calendar, tzinfo=dt_util.DEFAULT_TIME_ZONE)
return TodoStore(self._calendar, tzinfo=dt_util.get_default_time_zone())

async def async_update(self) -> None:
"""Update entity state based on the local To-do items."""
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/met/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ async def fetch_data(self) -> Self:
if not resp:
raise CannotConnect
self.current_weather_data = self._weather_data.get_current_weather()
time_zone = dt_util.DEFAULT_TIME_ZONE
time_zone = dt_util.get_default_time_zone()
self.daily_forecast = self._weather_data.get_forecast(time_zone, False, 0)
self.hourly_forecast = self._weather_data.get_forecast(time_zone, True)
return self
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/met_eireann/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ async def fetch_data(self) -> Self:
"""Fetch data from API - (current weather and forecast)."""
await self._weather_data.fetching_data()
self.current_weather_data = self._weather_data.get_current_weather()
time_zone = dt_util.DEFAULT_TIME_ZONE
time_zone = dt_util.get_default_time_zone()
self.daily_forecast = self._weather_data.get_forecast(time_zone, False)
self.hourly_forecast = self._weather_data.get_forecast(time_zone, True)
return self
2 changes: 1 addition & 1 deletion homeassistant/components/nobo_hub/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
ip=ip_address,
discover=discover,
synchronous=False,
timezone=dt_util.DEFAULT_TIME_ZONE,
timezone=dt_util.get_default_time_zone(),
)
await hub.connect()

Expand Down
4 changes: 2 additions & 2 deletions homeassistant/components/onvif/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -251,13 +251,13 @@ async def async_check_date_and_time(self) -> None:

LOGGER.debug("%s: Device time: %s", self.name, device_time)

tzone = dt_util.DEFAULT_TIME_ZONE
tzone = dt_util.get_default_time_zone()
cdate = device_time.LocalDateTime
if device_time.UTCDateTime:
tzone = dt_util.UTC
cdate = device_time.UTCDateTime
elif device_time.TimeZone:
tzone = dt_util.get_time_zone(device_time.TimeZone.TZ) or tzone
tzone = await dt_util.async_get_time_zone(device_time.TimeZone.TZ) or tzone

if cdate is None:
LOGGER.warning("%s: Could not retrieve date/time on this camera", self.name)
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/rainbird/calendar.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ def event(self) -> CalendarEvent | None:
schedule = self.coordinator.data
if not schedule:
return None
cursor = schedule.timeline_tz(dt_util.DEFAULT_TIME_ZONE).active_after(
cursor = schedule.timeline_tz(dt_util.get_default_time_zone()).active_after(
dt_util.now()
)
program_event = next(cursor, None)
Expand Down
6 changes: 3 additions & 3 deletions homeassistant/components/recorder/statistics.py
Original file line number Diff line number Diff line change
Expand Up @@ -952,7 +952,7 @@ def reduce_day_ts_factory() -> (

# We have to recreate _local_from_timestamp in the closure in case the timezone changes
_local_from_timestamp = partial(
datetime.fromtimestamp, tz=dt_util.DEFAULT_TIME_ZONE
datetime.fromtimestamp, tz=dt_util.get_default_time_zone()
)

def _same_day_ts(time1: float, time2: float) -> bool:
Expand Down Expand Up @@ -1000,7 +1000,7 @@ def reduce_week_ts_factory() -> (

# We have to recreate _local_from_timestamp in the closure in case the timezone changes
_local_from_timestamp = partial(
datetime.fromtimestamp, tz=dt_util.DEFAULT_TIME_ZONE
datetime.fromtimestamp, tz=dt_util.get_default_time_zone()
)

def _same_week_ts(time1: float, time2: float) -> bool:
Expand Down Expand Up @@ -1058,7 +1058,7 @@ def reduce_month_ts_factory() -> (

# We have to recreate _local_from_timestamp in the closure in case the timezone changes
_local_from_timestamp = partial(
datetime.fromtimestamp, tz=dt_util.DEFAULT_TIME_ZONE
datetime.fromtimestamp, tz=dt_util.get_default_time_zone()
)

def _same_month_ts(time1: float, time2: float) -> bool:
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/risco/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ def native_value(self) -> datetime | None:
return None

if res := dt_util.parse_datetime(self._event.time):
return res.replace(tzinfo=dt_util.DEFAULT_TIME_ZONE)
return res.replace(tzinfo=dt_util.get_default_time_zone())
return None

@property
Expand Down
4 changes: 3 additions & 1 deletion homeassistant/components/rova/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

from .const import DOMAIN, LOGGER

EUROPE_AMSTERDAM_ZONE_INFO = get_time_zone("Europe/Amsterdam")


class RovaCoordinator(DataUpdateCoordinator[dict[str, datetime]]):
"""Class to manage fetching Rova data."""
Expand All @@ -33,7 +35,7 @@ async def _async_update_data(self) -> dict[str, datetime]:

for item in items:
date = datetime.strptime(item["Date"], "%Y-%m-%dT%H:%M:%S").replace(
tzinfo=get_time_zone("Europe/Amsterdam")
tzinfo=EUROPE_AMSTERDAM_ZONE_INFO
)
code = item["GarbageTypeCode"].lower()
if code not in data:
Expand Down
4 changes: 2 additions & 2 deletions homeassistant/components/srp_energy/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from .const import DOMAIN, LOGGER, MIN_TIME_BETWEEN_UPDATES, PHOENIX_TIME_ZONE

TIMEOUT = 10
PHOENIX_ZONE_INFO = dt_util.get_time_zone(PHOENIX_TIME_ZONE)


class SRPEnergyDataUpdateCoordinator(DataUpdateCoordinator[float]):
Expand Down Expand Up @@ -43,8 +44,7 @@ async def _async_update_data(self) -> float:
"""
LOGGER.debug("async_update_data enter")
# Fetch srp_energy data
phx_time_zone = dt_util.get_time_zone(PHOENIX_TIME_ZONE)
end_date = dt_util.now(phx_time_zone)
end_date = dt_util.now(PHOENIX_ZONE_INFO)
start_date = end_date - timedelta(days=1)
try:
async with asyncio.timeout(TIMEOUT):
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/tibber/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
tibber_connection = tibber.Tibber(
access_token=entry.data[CONF_ACCESS_TOKEN],
websession=async_get_clientsession(hass),
time_zone=dt_util.DEFAULT_TIME_ZONE,
time_zone=dt_util.get_default_time_zone(),
)
hass.data[DOMAIN] = tibber_connection

Expand Down
Loading

0 comments on commit 5a609c3

Please sign in to comment.