From 0a6ba144446d0ceee25de26366b4f6eb67516675 Mon Sep 17 00:00:00 2001 From: Klaudiusz Staniek Date: Mon, 11 Mar 2019 21:27:41 +0100 Subject: [PATCH] Fixes issues #21821 and #21819 (#21911) * Fix #21821 * datetime fix * local time to utc conversion fix * Test cases update * date import removed * Update tod.py --- homeassistant/components/binary_sensor/tod.py | 20 ++++--- tests/components/binary_sensor/test_tod.py | 59 ++++++++++--------- 2 files changed, 43 insertions(+), 36 deletions(-) diff --git a/homeassistant/components/binary_sensor/tod.py b/homeassistant/components/binary_sensor/tod.py index 7dc6e5ebe81..8e29bbd4678 100644 --- a/homeassistant/components/binary_sensor/tod.py +++ b/homeassistant/components/binary_sensor/tod.py @@ -119,6 +119,17 @@ class TodSensor(BinarySensorDevice): self.hass.config.time_zone).isoformat(), } + def _naive_time_to_utc_datetime(self, naive_time): + """Convert naive time from config to utc_datetime with current day.""" + # get the current local date from utc time + current_local_date = self.current_datetime.astimezone( + self.hass.config.time_zone).date() + # calcuate utc datetime corecponding to local time + utc_datetime = self.hass.config.time_zone.localize( + datetime.combine( + current_local_date, naive_time)).astimezone(tz=pytz.UTC) + return utc_datetime + def _calculate_initial_boudary_time(self): """Calculate internal absolute time boudaries.""" nowutc = self.current_datetime @@ -134,9 +145,7 @@ class TodSensor(BinarySensorDevice): # datetime.combine(date, time, tzinfo) is not supported # in python 3.5. The self._after is provided # with hass configured TZ not system wide - after_event_date = datetime.combine( - nowutc, self._after.replace( - tzinfo=self.hass.config.time_zone)).astimezone(tz=pytz.UTC) + after_event_date = self._naive_time_to_utc_datetime(self._after) self._time_after = after_event_date @@ -154,9 +163,7 @@ class TodSensor(BinarySensorDevice): self.hass, self._before, after_event_date) else: # Convert local time provided to UTC today, see above - before_event_date = datetime.combine( - nowutc, self._before.replace( - tzinfo=self.hass.config.time_zone)).astimezone(tz=pytz.UTC) + before_event_date = self._naive_time_to_utc_datetime(self._before) # It is safe to add timedelta days=1 to UTC as there is no DST if before_event_date < after_event_date + self._after_offset: @@ -190,7 +197,6 @@ class TodSensor(BinarySensorDevice): async def async_added_to_hass(self): """Call when entity about to be added to Home Assistant.""" - await super().async_added_to_hass() self._calculate_initial_boudary_time() self._calculate_next_update() self._point_in_time_listener(dt_util.now()) diff --git a/tests/components/binary_sensor/test_tod.py b/tests/components/binary_sensor/test_tod.py index 3c083141962..7af6ef95bfa 100644 --- a/tests/components/binary_sensor/test_tod.py +++ b/tests/components/binary_sensor/test_tod.py @@ -110,8 +110,8 @@ class TestBinarySensorTod(unittest.TestCase): def test_midnight_turnover_after_midnight_inside_period(self): """Test midnight turnover setting before midnight inside period .""" - test_time = datetime( - 2019, 1, 10, 21, 00, 0, tzinfo=self.hass.config.time_zone) + test_time = self.hass.config.time_zone.localize( + datetime(2019, 1, 10, 21, 0, 0)).astimezone(pytz.UTC) config = { 'binary_sensor': [ { @@ -143,8 +143,8 @@ class TestBinarySensorTod(unittest.TestCase): def test_midnight_turnover_before_midnight_outside_period(self): """Test midnight turnover setting before midnight outside period.""" - test_time = datetime( - 2019, 1, 10, 20, 30, 0, tzinfo=self.hass.config.time_zone) + test_time = self.hass.config.time_zone.localize( + datetime(2019, 1, 10, 20, 30, 0)).astimezone(pytz.UTC) config = { 'binary_sensor': [ { @@ -165,8 +165,9 @@ class TestBinarySensorTod(unittest.TestCase): def test_midnight_turnover_after_midnight_outside_period(self): """Test midnight turnover setting before midnight inside period .""" - test_time = datetime( - 2019, 1, 10, 20, 0, 0, tzinfo=self.hass.config.time_zone) + test_time = self.hass.config.time_zone.localize( + datetime(2019, 1, 10, 20, 0, 0)).astimezone(pytz.UTC) + config = { 'binary_sensor': [ { @@ -185,8 +186,8 @@ class TestBinarySensorTod(unittest.TestCase): state = self.hass.states.get('binary_sensor.night') assert state.state == STATE_OFF - switchover_time = datetime( - 2019, 1, 11, 4, 59, 0, tzinfo=self.hass.config.time_zone) + switchover_time = self.hass.config.time_zone.localize( + datetime(2019, 1, 11, 4, 59, 0)).astimezone(pytz.UTC) with patch('homeassistant.components.binary_sensor.tod.dt_util.utcnow', return_value=switchover_time): @@ -210,8 +211,8 @@ class TestBinarySensorTod(unittest.TestCase): def test_from_sunrise_to_sunset(self): """Test period from sunrise to sunset.""" - test_time = datetime( - 2019, 1, 12, tzinfo=self.hass.config.time_zone) + test_time = self.hass.config.time_zone.localize( + datetime(2019, 1, 12)).astimezone(pytz.UTC) sunrise = dt_util.as_local(get_astral_event_date( self.hass, 'sunrise', dt_util.as_utc(test_time))) sunset = dt_util.as_local(get_astral_event_date( @@ -299,8 +300,8 @@ class TestBinarySensorTod(unittest.TestCase): def test_from_sunset_to_sunrise(self): """Test period from sunset to sunrise.""" - test_time = datetime( - 2019, 1, 12, tzinfo=self.hass.config.time_zone) + test_time = self.hass.config.time_zone.localize( + datetime(2019, 1, 12)).astimezone(pytz.UTC) sunset = dt_util.as_local(get_astral_event_date( self.hass, 'sunset', test_time)) sunrise = dt_util.as_local(get_astral_event_next( @@ -385,14 +386,14 @@ class TestBinarySensorTod(unittest.TestCase): def test_offset(self): """Test offset.""" - after = datetime( - 2019, 1, 10, 18, 0, 0, - tzinfo=self.hass.config.time_zone) + \ + after = self.hass.config.time_zone.localize( + datetime(2019, 1, 10, 18, 0, 0)).astimezone(pytz.UTC) + \ timedelta(hours=1, minutes=34) - before = datetime( - 2019, 1, 10, 22, 0, 0, - tzinfo=self.hass.config.time_zone) + \ + + before = self.hass.config.time_zone.localize( + datetime(2019, 1, 10, 22, 0, 0)).astimezone(pytz.UTC) + \ timedelta(hours=1, minutes=45) + entity_id = 'binary_sensor.evening' config = { 'binary_sensor': [ @@ -457,9 +458,8 @@ class TestBinarySensorTod(unittest.TestCase): def test_offset_overnight(self): """Test offset overnight.""" - after = datetime( - 2019, 1, 10, 18, 0, 0, - tzinfo=self.hass.config.time_zone) + \ + after = self.hass.config.time_zone.localize( + datetime(2019, 1, 10, 18, 0, 0)).astimezone(pytz.UTC) + \ timedelta(hours=1, minutes=34) entity_id = 'binary_sensor.evening' config = { @@ -498,7 +498,8 @@ class TestBinarySensorTod(unittest.TestCase): self.hass.config.latitude = 69.6 self.hass.config.longitude = 18.8 - test_time = datetime(2010, 1, 1, tzinfo=self.hass.config.time_zone) + test_time = self.hass.config.time_zone.localize( + datetime(2010, 1, 1)).astimezone(pytz.UTC) sunrise = dt_util.as_local(get_astral_event_next( self.hass, 'sunrise', dt_util.as_utc(test_time))) sunset = dt_util.as_local(get_astral_event_next( @@ -600,13 +601,13 @@ class TestBinarySensorTod(unittest.TestCase): self.hass.config.latitude = 69.6 self.hass.config.longitude = 18.8 - test_time = datetime(2010, 6, 1, tzinfo=self.hass.config.time_zone) + test_time = self.hass.config.time_zone.localize( + datetime(2010, 6, 1)).astimezone(pytz.UTC) + sunrise = dt_util.as_local(get_astral_event_next( self.hass, 'sunrise', dt_util.as_utc(test_time))) sunset = dt_util.as_local(get_astral_event_next( self.hass, 'sunset', dt_util.as_utc(test_time))) - print(sunrise) - print(sunset) config = { 'binary_sensor': [ { @@ -701,8 +702,8 @@ class TestBinarySensorTod(unittest.TestCase): def test_sun_offset(self): """Test sun event with offset.""" - test_time = datetime( - 2019, 1, 12, tzinfo=self.hass.config.time_zone) + test_time = self.hass.config.time_zone.localize( + datetime(2019, 1, 12)).astimezone(pytz.UTC) sunrise = dt_util.as_local(get_astral_event_date( self.hass, 'sunrise', dt_util.as_utc(test_time)) + timedelta(hours=-1, minutes=-30)) @@ -810,8 +811,8 @@ class TestBinarySensorTod(unittest.TestCase): def test_dst(self): """Test sun event with offset.""" self.hass.config.time_zone = pytz.timezone('CET') - test_time = datetime( - 2019, 3, 30, 3, 0, 0, tzinfo=self.hass.config.time_zone) + test_time = self.hass.config.time_zone.localize( + datetime(2019, 3, 30, 3, 0, 0)).astimezone(pytz.UTC) config = { 'binary_sensor': [ {