forked from platypush/platypush
🐛 A proper cross-version solution for the utcnow()
issue.
No need to maintain two different pieces of logic - a `utcnow()` for Python < 3.11 and `now(datetime.UTC)` for Python >= 3.11. `datetime.timezone.utc` existed long before datetime.UTC and that's what the `utcnow` facade should use. This means that all the `utcnow()` will always have `tzinfo=UTC` regardless of the Python version. There's still a problem with the `utcnow()`-generated timestamps that have been generated by previous versions of Python and stored on the db. Therefore, when the code performs comparisons with timestamps fetched from the db, it should always explicitly do a `.replace(tzinfo=utc)` to ensure that we always compare offset-aware datetime representations. See blog post for technical details: https://manganiello.blog/wheres-my-time-again
This commit is contained in:
parent
1067ab04d9
commit
c9a5c29a4a
7 changed files with 19 additions and 21 deletions
|
@ -1,10 +1,8 @@
|
|||
from datetime import timedelta
|
||||
import logging
|
||||
from threading import Event
|
||||
from time import time
|
||||
from typing import Collection, Optional
|
||||
|
||||
from platypush.utils import utcnow
|
||||
|
||||
from ._base import (
|
||||
Entity,
|
||||
EntityKey,
|
||||
|
@ -47,8 +45,8 @@ def get_entities_engine(timeout: Optional[float] = None) -> EntitiesEngine:
|
|||
|
||||
:param timeout: Timeout in seconds (default: None).
|
||||
"""
|
||||
time_start = utcnow()
|
||||
while not timeout or (utcnow() - time_start < timedelta(seconds=timeout)):
|
||||
time_start = time()
|
||||
while not timeout or (time() - time_start < timeout):
|
||||
if _engine:
|
||||
break
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from datetime import timedelta
|
||||
from datetime import timedelta, timezone
|
||||
from logging import getLogger
|
||||
from queue import Queue
|
||||
from typing import Callable, Collection, Dict, Final, List, Optional, Type
|
||||
|
@ -99,7 +99,8 @@ event_matchers: Dict[
|
|||
)
|
||||
and (
|
||||
not (old and old.updated_at)
|
||||
or utcnow() - old.updated_at >= timedelta(seconds=_rssi_update_interval)
|
||||
or utcnow() - old.updated_at.replace(tzinfo=timezone.utc)
|
||||
>= timedelta(seconds=_rssi_update_interval)
|
||||
)
|
||||
),
|
||||
}
|
||||
|
|
|
@ -97,8 +97,7 @@ class CalendarIcalPlugin(Plugin, CalendarInterface):
|
|||
if (
|
||||
event['status'] != 'cancelled'
|
||||
and event['end'].get('dateTime')
|
||||
and event['end']['dateTime']
|
||||
>= utcnow().replace(tzinfo=datetime.timezone.utc).isoformat()
|
||||
and event['end']['dateTime'] >= utcnow().isoformat()
|
||||
and (
|
||||
(
|
||||
only_participating
|
||||
|
|
|
@ -71,7 +71,7 @@ class GoogleCalendarPlugin(GooglePlugin, CalendarInterface):
|
|||
:meth:`platypush.plugins.calendar.CalendarPlugin.get_upcoming_events`.
|
||||
"""
|
||||
|
||||
now = utcnow().isoformat() + 'Z'
|
||||
now = utcnow().replace(tzinfo=None).isoformat() + 'Z'
|
||||
service = self.get_service('calendar', 'v3')
|
||||
result = (
|
||||
service.events()
|
||||
|
|
|
@ -68,7 +68,7 @@ class SunPlugin(RunnablePlugin):
|
|||
dt = datetime.datetime.strptime(
|
||||
f'{now.year}-{now.month:02d}-{now.day:02d} {t}',
|
||||
'%Y-%m-%d %I:%M:%S %p',
|
||||
).replace(tzinfo=datetime.UTC)
|
||||
).replace(tzinfo=datetime.timezone.utc)
|
||||
|
||||
if dt < now:
|
||||
dt += datetime.timedelta(days=1)
|
||||
|
|
|
@ -115,9 +115,13 @@ class UserManager:
|
|||
.first()
|
||||
)
|
||||
|
||||
if not user_session or (
|
||||
user_session.expires_at and user_session.expires_at < utcnow()
|
||||
):
|
||||
expires_at = (
|
||||
user_session.expires_at.replace(tzinfo=datetime.timezone.utc)
|
||||
if user_session and user_session.expires_at
|
||||
else None
|
||||
)
|
||||
|
||||
if not user_session or (expires_at and expires_at < utcnow()):
|
||||
return None, None
|
||||
|
||||
user = session.query(User).filter_by(user_id=user_session.user_id).first()
|
||||
|
|
|
@ -816,14 +816,10 @@ def wait_for_either(*events, timeout: Optional[float] = None, cls: Type = Event)
|
|||
|
||||
def utcnow():
|
||||
"""
|
||||
A workaround util to maintain compatibility both with Python >= 3.12 (which
|
||||
deprecated datetime.utcnow) and Python < 3.12 (which doesn't have
|
||||
datetime.UTC).
|
||||
utcnow() without tears. It always returns a datetime object in UTC
|
||||
timezone.
|
||||
"""
|
||||
if hasattr(datetime, 'UTC'):
|
||||
return datetime.datetime.now(datetime.UTC)
|
||||
|
||||
return datetime.datetime.utcnow()
|
||||
return datetime.datetime.now(datetime.timezone.utc)
|
||||
|
||||
|
||||
# vim:sw=4:ts=4:et:
|
||||
|
|
Loading…
Reference in a new issue