[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[tor-commits] [stem/master] Add timezone to parsed datetimes
commit f8717b4bffd46c8c0ee7147f5b50927737b2b5e1
Author: Steven Engler <opara@xxxxxxxxxxxxxxxxx>
Date: Mon Oct 25 14:46:39 2021 -0400
Add timezone to parsed datetimes
---
stem/control.py | 3 ++-
stem/descriptor/__init__.py | 3 ++-
stem/descriptor/extrainfo_descriptor.py | 2 +-
stem/descriptor/networkstatus.py | 2 +-
stem/descriptor/router_status_entry.py | 3 ++-
stem/descriptor/tordnsel.py | 6 +++---
stem/response/events.py | 8 +++++---
stem/util/str_tools.py | 15 +++++++++++----
8 files changed, 27 insertions(+), 15 deletions(-)
diff --git a/stem/control.py b/stem/control.py
index e162704b..40ca6bed 100644
--- a/stem/control.py
+++ b/stem/control.py
@@ -247,6 +247,7 @@ If you're fine with allowing your script to raise exceptions then this can be mo
import asyncio
import calendar
import collections
+import datetime
import functools
import inspect
import io
@@ -1537,7 +1538,7 @@ class Controller(BaseController):
self.get_info('accounting/bytes-left'),
)
- interval_end = stem.util.str_tools._parse_timestamp(interval_end)
+ interval_end = stem.util.str_tools._parse_timestamp(interval_end, datetime.timezone.utc)
used_read, used_written = [int(val) for val in used.split(' ', 1)]
left_read, left_written = [int(val) for val in left.split(' ', 1)]
diff --git a/stem/descriptor/__init__.py b/stem/descriptor/__init__.py
index c015d246..d928ff21 100644
--- a/stem/descriptor/__init__.py
+++ b/stem/descriptor/__init__.py
@@ -108,6 +108,7 @@ import base64
import codecs
import collections
import copy
+import datetime
import hashlib
import io
import os
@@ -683,7 +684,7 @@ def _parse_timestamp_line(keyword: str, attribute: str) -> Callable[['stem.descr
value = _value(keyword, entries)
try:
- setattr(descriptor, attribute, stem.util.str_tools._parse_timestamp(value))
+ setattr(descriptor, attribute, stem.util.str_tools._parse_timestamp(value, datetime.timezone.utc))
except ValueError:
raise ValueError("Timestamp on %s line wasn't parsable: %s %s" % (keyword, keyword, value))
diff --git a/stem/descriptor/extrainfo_descriptor.py b/stem/descriptor/extrainfo_descriptor.py
index 8d9cbf30..ad08d361 100644
--- a/stem/descriptor/extrainfo_descriptor.py
+++ b/stem/descriptor/extrainfo_descriptor.py
@@ -239,7 +239,7 @@ def _parse_timestamp_and_interval(keyword: str, content: str) -> Tuple[datetime.
raise ValueError("%s line's interval wasn't a number: %s" % (keyword, line))
try:
- timestamp = stem.util.str_tools._parse_timestamp(timestamp_str)
+ timestamp = stem.util.str_tools._parse_timestamp(timestamp_str, datetime.timezone.utc)
return timestamp, int(interval), remainder
except ValueError:
raise ValueError("%s line's timestamp wasn't parsable: %s" % (keyword, line))
diff --git a/stem/descriptor/networkstatus.py b/stem/descriptor/networkstatus.py
index e8cf90eb..a69f501f 100644
--- a/stem/descriptor/networkstatus.py
+++ b/stem/descriptor/networkstatus.py
@@ -1962,7 +1962,7 @@ class BridgeNetworkStatusDocument(NetworkStatusDocument):
published_line = published_line.split(' ', 1)[1].strip()
try:
- self.published = stem.util.str_tools._parse_timestamp(published_line)
+ self.published = stem.util.str_tools._parse_timestamp(published_line, datetime.timezone.utc)
except ValueError:
if validate:
raise ValueError("Bridge network status document's 'published' time wasn't parsable: %s" % published_line)
diff --git a/stem/descriptor/router_status_entry.py b/stem/descriptor/router_status_entry.py
index aa94a703..eed34fac 100644
--- a/stem/descriptor/router_status_entry.py
+++ b/stem/descriptor/router_status_entry.py
@@ -22,6 +22,7 @@ sources...
"""
import binascii
+import datetime
import io
import stem.exit_policy
@@ -161,7 +162,7 @@ def _parse_r_line(descriptor: 'stem.descriptor.Descriptor', entries: ENTRY_TYPE)
try:
published = '%s %s' % (r_comp[3], r_comp[4])
- descriptor.published = stem.util.str_tools._parse_timestamp(published)
+ descriptor.published = stem.util.str_tools._parse_timestamp(published, datetime.timezone.utc)
except ValueError:
raise ValueError("Publication time time wasn't parsable: r %s" % value)
diff --git a/stem/descriptor/tordnsel.py b/stem/descriptor/tordnsel.py
index 32cf1863..ffb67578 100644
--- a/stem/descriptor/tordnsel.py
+++ b/stem/descriptor/tordnsel.py
@@ -98,13 +98,13 @@ class TorDNSEL(Descriptor):
self.fingerprint = value
elif keyword == 'Published':
try:
- self.published = stem.util.str_tools._parse_timestamp(value)
+ self.published = stem.util.str_tools._parse_timestamp(value, datetime.timezone.utc)
except ValueError:
if validate:
raise ValueError("Published time wasn't parsable: %s" % value)
elif keyword == 'LastStatus':
try:
- self.last_status = stem.util.str_tools._parse_timestamp(value)
+ self.last_status = stem.util.str_tools._parse_timestamp(value, datetime.timezone.utc)
except ValueError:
if validate:
raise ValueError("LastStatus time wasn't parsable: %s" % value)
@@ -119,7 +119,7 @@ class TorDNSEL(Descriptor):
raise ValueError('Unexpected block content: %s' % block_content)
try:
- date = stem.util.str_tools._parse_timestamp(date_str)
+ date = stem.util.str_tools._parse_timestamp(date_str, datetime.timezone.utc)
self.exit_addresses.append((address, date))
except ValueError:
if validate:
diff --git a/stem/response/events.py b/stem/response/events.py
index 2b9b6dfd..a55771cc 100644
--- a/stem/response/events.py
+++ b/stem/response/events.py
@@ -221,12 +221,14 @@ class AddrMapEvent(Event):
self.expiry = None
else:
try:
- self.expiry = stem.util.str_tools._parse_timestamp(self.expiry)
+ # control-spec: "Expiry is expressed as the local time (rather than
+ # UTC). This is a bug, left in for backward compatibility"
+ self.expiry = stem.util.str_tools._parse_timestamp(self.expiry, None)
except ValueError:
raise stem.ProtocolError('Unable to parse date in ADDRMAP event: %s' % self)
if self.utc_expiry is not None:
- self.utc_expiry = stem.util.str_tools._parse_timestamp(self.utc_expiry)
+ self.utc_expiry = stem.util.str_tools._parse_timestamp(self.utc_expiry, datetime.timezone.utc)
if self.cached is not None:
if self.cached == 'YES':
@@ -518,7 +520,7 @@ class ClientsSeenEvent(Event):
def _parse(self) -> None:
if self.start_time is not None:
- self.start_time = stem.util.str_tools._parse_timestamp(self.start_time)
+ self.start_time = stem.util.str_tools._parse_timestamp(self.start_time, datetime.timezone.utc)
if self.locales is not None:
locale_to_count = {}
diff --git a/stem/util/str_tools.py b/stem/util/str_tools.py
index a9a34364..0012e96a 100644
--- a/stem/util/str_tools.py
+++ b/stem/util/str_tools.py
@@ -26,7 +26,7 @@ import sys
import stem.util
import stem.util.enum
-from typing import List, Sequence, Tuple, Union, overload
+from typing import List, Optional, Sequence, Tuple, Union, overload
# label conversion tuples of the form...
# (bits / bytes / seconds, short label, long label)
@@ -481,7 +481,7 @@ def parse_short_time_label(label: str) -> int:
raise ValueError('Non-numeric value in time entry: %s' % label)
-def _parse_timestamp(entry: str) -> datetime.datetime:
+def _parse_timestamp(entry: str, tz: Optional[datetime.timezone]) -> datetime.datetime:
"""
Parses the date and time that in format like like...
@@ -490,6 +490,8 @@ def _parse_timestamp(entry: str) -> datetime.datetime:
2012-11-08 16:48:41
:param entry: timestamp to be parsed
+ :param tz: timezone of the entry (if **None**, the returned **datetime** will
+ be "naive")
:returns: **datetime** for the time represented by the timestamp
@@ -504,7 +506,12 @@ def _parse_timestamp(entry: str) -> datetime.datetime:
except AttributeError:
raise ValueError('Expected timestamp in format YYYY-MM-DD HH:MM:ss but got ' + entry)
- return datetime.datetime(time[0], time[1], time[2], time[3], time[4], time[5])
+ dt = datetime.datetime(time[0], time[1], time[2], time[3], time[4], time[5])
+
+ if tz != None:
+ dt.replace(tzinfo=tz)
+
+ return dt
def _parse_iso_timestamp(entry: str) -> 'datetime.datetime':
@@ -541,7 +548,7 @@ def _parse_iso_timestamp(entry: str) -> 'datetime.datetime':
else:
raise ValueError("timestamp didn't contain delimeter 'T' between date and time")
- timestamp = _parse_timestamp(timestamp_str)
+ timestamp = _parse_timestamp(timestamp_str, datetime.timezone.utc)
return timestamp + datetime.timedelta(microseconds = int(microseconds))
_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits