aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorWolfgang Müller2021-05-02 12:38:56 +0200
committerWolfgang Müller2021-05-02 12:38:56 +0200
commitf95a23e0e5c23b7ec13e63501b6ab6df540cb695 (patch)
tree107c181ce88abf258a4fa1cadacdb103d12f63be
parent0b6ce2c57d53d947b15f0d429d2216df61ce3783 (diff)
downloadquarg-f95a23e0e5c23b7ec13e63501b6ab6df540cb695.tar.gz
Handle timezones correctly
Quassel uses UTC message timestamps in its database, but does not save any timezone information along with them. Up until now, we were reading those timestamps from the database naively - resulting in datetime objects that could not be identified as UTC. The same happened with timestamps we got from dateutil.isoparse. If the user did not specify an offset explicitly, the timestamp would be parsed and passed to the program "as is", effectively being interpreted as UTC because they were compared to database timestamps. This commit will ensure that the correct timezone is saved for every datetime object we encounter. Timestamps from the database are marked as UTC. If the user does not explicitly specify an offset, the timestamp is assumed to be in local time. Furthermore, when printing out message timestamps, make sure to convert them to the user's local timezone first.
-rw-r--r--quarg/database/tables.py20
-rw-r--r--quarg/quassel/formatter.py4
-rw-r--r--quarg/utils.py4
3 files changed, 25 insertions, 3 deletions
diff --git a/quarg/database/tables.py b/quarg/database/tables.py
index 10e6057..743ffa2 100644
--- a/quarg/database/tables.py
+++ b/quarg/database/tables.py
@@ -1,10 +1,26 @@
+import datetime
+
from sqlalchemy.schema import Column, ForeignKey
-from sqlalchemy.types import BigInteger, Boolean, DateTime, Integer, Text
+from sqlalchemy.types import BigInteger, Boolean, DateTime, Integer, Text, TypeDecorator
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
# pylint: disable=too-few-public-methods
+# Timestamps are saved in the database in UTC without timezone info, so attach
+# a UTC timezone to the datetime object
+class DateTimeUTC(TypeDecorator):
+ # pylint complains that process_{bind,literal}_param and python_type are
+ # abstract but not overriden. This seems to not be necessary with
+ # SQLAlchemy, so squash those warnings
+ # pylint: disable=abstract-method
+ impl = DateTime
+
+ def process_result_value(self, value, dialect):
+ if value is not None:
+ value = value.replace(tzinfo=datetime.timezone.utc)
+ return value
+
Base = declarative_base()
# Note: We have commented out unused columns to keep SQLAlchemy from selecting
@@ -13,7 +29,7 @@ Base = declarative_base()
class Backlog(Base):
__tablename__ = 'backlog'
messageid = Column(BigInteger, primary_key=True)
- time = Column(DateTime)
+ time = Column(DateTimeUTC)
bufferid = Column(Integer, ForeignKey('buffer.bufferid'))
type = Column(Integer)
flags = Column(Integer)
diff --git a/quarg/quassel/formatter.py b/quarg/quassel/formatter.py
index b6235e8..51eec00 100644
--- a/quarg/quassel/formatter.py
+++ b/quarg/quassel/formatter.py
@@ -33,7 +33,9 @@ class Message(NamedTuple):
def format_from(backlog_row):
message = Message.from_backlog(backlog_row)
formatter = FORMATTERS[message.type]
- timestamp = message.time.isoformat(sep=' ', timespec='seconds')
+
+ # make sure to convert timestamps to local time before printing
+ timestamp = message.time.astimezone().isoformat(sep=' ', timespec='seconds')
return f'{timestamp}\t{message.buffer}\t{formatter(message)}'
diff --git a/quarg/utils.py b/quarg/utils.py
index 7fa270e..903c057 100644
--- a/quarg/utils.py
+++ b/quarg/utils.py
@@ -12,4 +12,8 @@ def parse_isodate(date):
except OverflowError as err:
errx(f'isoparse: date overflows: \'{date}\'')
+ # If no offset is given, assume local time
+ if parsed.tzinfo is None:
+ parsed = parsed.astimezone()
+
return parsed