Fix process_datetime_to_timestamp and add test coverage (#71755)

pull/71772/head
J. Nick Koston 2022-05-12 20:12:50 -04:00 committed by GitHub
parent 8ab27f26b9
commit 1d9fb4bca8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 92 additions and 4 deletions

View File

@ -55,6 +55,10 @@ SCHEMA_VERSION = 28
_LOGGER = logging.getLogger(__name__)
# EPOCHORDINAL is not exposed as a constant
# https://github.com/python/cpython/blob/3.10/Lib/zoneinfo/_zoneinfo.py#L12
EPOCHORDINAL = datetime(1970, 1, 1).toordinal()
DB_TIMEZONE = "+00:00"
TABLE_EVENTS = "events"
@ -630,10 +634,22 @@ def process_timestamp_to_utc_isoformat(ts: datetime | None) -> str | None:
def process_datetime_to_timestamp(ts: datetime) -> float:
"""Process a timestamp into a unix timestamp."""
if ts.tzinfo == dt_util.UTC:
return ts.timestamp()
return ts.replace(tzinfo=dt_util.UTC).timestamp()
"""Process a datebase datetime to epoch.
Mirrors the behavior of process_timestamp_to_utc_isoformat
except it returns the epoch time.
"""
if ts.tzinfo is None:
# Taken from
# https://github.com/python/cpython/blob/3.10/Lib/zoneinfo/_zoneinfo.py#L185
return (
(ts.toordinal() - EPOCHORDINAL) * 86400
+ ts.hour * 3600
+ ts.minute * 60
+ ts.second
+ (ts.microsecond / 1000000)
)
return ts.timestamp()
class LazyState(State):

View File

@ -2,6 +2,7 @@
from datetime import datetime, timedelta
from unittest.mock import PropertyMock
from freezegun import freeze_time
import pytest
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker
@ -14,6 +15,7 @@ from homeassistant.components.recorder.models import (
RecorderRuns,
StateAttributes,
States,
process_datetime_to_timestamp,
process_timestamp,
process_timestamp_to_utc_isoformat,
)
@ -333,3 +335,73 @@ async def test_lazy_state_handles_same_last_updated_and_last_changed(caplog):
"last_updated": "2020-06-12T03:04:01.000323+00:00",
"state": "off",
}
@pytest.mark.parametrize(
"time_zone", ["Europe/Berlin", "America/Chicago", "US/Hawaii", "UTC"]
)
def test_process_datetime_to_timestamp(time_zone, hass):
"""Test we can handle processing database datatimes to timestamps."""
hass.config.set_time_zone(time_zone)
utc_now = dt_util.utcnow()
assert process_datetime_to_timestamp(utc_now) == utc_now.timestamp()
now = dt_util.now()
assert process_datetime_to_timestamp(now) == now.timestamp()
@pytest.mark.parametrize(
"time_zone", ["Europe/Berlin", "America/Chicago", "US/Hawaii", "UTC"]
)
def test_process_datetime_to_timestamp_freeze_time(time_zone, hass):
"""Test we can handle processing database datatimes to timestamps.
This test freezes time to make sure everything matches.
"""
hass.config.set_time_zone(time_zone)
utc_now = dt_util.utcnow()
with freeze_time(utc_now):
epoch = utc_now.timestamp()
assert process_datetime_to_timestamp(dt_util.utcnow()) == epoch
now = dt_util.now()
assert process_datetime_to_timestamp(now) == epoch
@pytest.mark.parametrize(
"time_zone", ["Europe/Berlin", "America/Chicago", "US/Hawaii", "UTC"]
)
async def test_process_datetime_to_timestamp_mirrors_utc_isoformat_behavior(
time_zone, hass
):
"""Test process_datetime_to_timestamp mirrors process_timestamp_to_utc_isoformat."""
hass.config.set_time_zone(time_zone)
datetime_with_tzinfo = datetime(2016, 7, 9, 11, 0, 0, tzinfo=dt.UTC)
datetime_without_tzinfo = datetime(2016, 7, 9, 11, 0, 0)
est = dt_util.get_time_zone("US/Eastern")
datetime_est_timezone = datetime(2016, 7, 9, 11, 0, 0, tzinfo=est)
est = dt_util.get_time_zone("US/Eastern")
datetime_est_timezone = datetime(2016, 7, 9, 11, 0, 0, tzinfo=est)
nst = dt_util.get_time_zone("Canada/Newfoundland")
datetime_nst_timezone = datetime(2016, 7, 9, 11, 0, 0, tzinfo=nst)
hst = dt_util.get_time_zone("US/Hawaii")
datetime_hst_timezone = datetime(2016, 7, 9, 11, 0, 0, tzinfo=hst)
assert (
process_datetime_to_timestamp(datetime_with_tzinfo)
== dt_util.parse_datetime("2016-07-09T11:00:00+00:00").timestamp()
)
assert (
process_datetime_to_timestamp(datetime_without_tzinfo)
== dt_util.parse_datetime("2016-07-09T11:00:00+00:00").timestamp()
)
assert (
process_datetime_to_timestamp(datetime_est_timezone)
== dt_util.parse_datetime("2016-07-09T15:00:00+00:00").timestamp()
)
assert (
process_datetime_to_timestamp(datetime_nst_timezone)
== dt_util.parse_datetime("2016-07-09T13:30:00+00:00").timestamp()
)
assert (
process_datetime_to_timestamp(datetime_hst_timezone)
== dt_util.parse_datetime("2016-07-09T21:00:00+00:00").timestamp()
)