From e52f5e06f407b1c3bfe5204d13dd273ec9a6de04 Mon Sep 17 00:00:00 2001 From: Fabio Manganiello Date: Thu, 6 Jun 2024 02:22:23 +0200 Subject: [PATCH] [calendar.ical] Fixed timezone/datetime parsing issues. Closes: #405 --- CHANGELOG.md | 4 +++ platypush/plugins/calendar/ical/__init__.py | 28 ++++++++++++--------- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 941814af1..19e0b2793 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## [Unreleased] + +- [#405] Fixed timezone/timestamp rendering issues for `calendar.ical` events. + ## [1.0.7] - 2024-06-02 - [#384] Added `assistant.openai` and `tts.openai` plugins. diff --git a/platypush/plugins/calendar/ical/__init__.py b/platypush/plugins/calendar/ical/__init__.py index e71325a4e..51f501fb6 100644 --- a/platypush/plugins/calendar/ical/__init__.py +++ b/platypush/plugins/calendar/ical/__init__.py @@ -1,7 +1,9 @@ import datetime -import requests from typing import Optional +import requests +from dateutil.tz import gettz + from platypush.plugins import Plugin, action from platypush.plugins.calendar import CalendarInterface from platypush.utils import utcnow @@ -21,19 +23,20 @@ class CalendarIcalPlugin(Plugin, CalendarInterface): self.url = url @staticmethod - def _convert_timestamp(event, attribute: str) -> Optional[str]: + def _convert_timestamp(event: dict, attribute: str) -> Optional[str]: t = event.get(attribute) if not t: - return + return None - if isinstance(t.dt, datetime.date): + if isinstance(t.dt, datetime.date) and not isinstance(t.dt, datetime.datetime): return datetime.datetime( - t.dt.year, t.dt.month, t.dt.day, tzinfo=datetime.timezone.utc + t.dt.year, t.dt.month, t.dt.day, tzinfo=gettz() ).isoformat() return ( - datetime.datetime.utcfromtimestamp(t.dt.timestamp()) - .replace(tzinfo=datetime.timezone.utc) + datetime.datetime.fromtimestamp(t.dt.timestamp()) + .replace(tzinfo=t.dt.tzinfo or gettz()) + .astimezone(datetime.timezone.utc) .isoformat() ) @@ -82,10 +85,10 @@ class CalendarIcalPlugin(Plugin, CalendarInterface): from icalendar import Calendar events = [] - response = requests.get(self.url) - assert response.ok, "HTTP error while getting events from {}: {}".format( - self.url, response.text - ) + response = requests.get(self.url, timeout=20) + assert ( + response.ok + ), f"HTTP error while getting events from {self.url}: {response.text}" calendar = Calendar.from_ical(response.text) for event in calendar.walk(): @@ -97,7 +100,8 @@ class CalendarIcalPlugin(Plugin, CalendarInterface): if ( event['status'] != 'cancelled' and event['end'].get('dateTime') - and event['end']['dateTime'] >= utcnow().isoformat() + and datetime.datetime.fromisoformat(event['end']['dateTime']) + >= utcnow() and ( ( only_participating