Fix (de)serialization of negative timestamps (#1241)

This commit is contained in:
binares 2019-08-01 19:47:38 +03:00 committed by Lonami
parent 2ace4fde41
commit 2b277dd558
2 changed files with 27 additions and 12 deletions

View File

@ -2,14 +2,18 @@
This module contains the BinaryReader utility class.
"""
import os
from datetime import datetime, timezone
from datetime import datetime, timezone, timedelta
from io import BufferedReader, BytesIO
from struct import unpack
import time
from ..errors import TypeNotFoundError
from ..tl.alltlobjects import tlobjects
from ..tl.core import core_objects
_EPOCH_NAIVE = datetime(*time.gmtime(0)[:6])
_EPOCH = _EPOCH_NAIVE.replace(tzinfo=timezone.utc)
class BinaryReader:
"""
@ -120,10 +124,7 @@ class BinaryReader:
into a Python datetime object.
"""
value = self.read_int()
if value == 0:
return None
else:
return datetime.fromtimestamp(value, tz=timezone.utc)
return _EPOCH + timedelta(seconds=value)
def tgread_object(self):
"""Reads a Telegram object."""

View File

@ -1,7 +1,21 @@
import base64
import json
import struct
from datetime import datetime, date, timedelta
from datetime import datetime, date, timedelta, timezone
import time
_EPOCH_NAIVE = datetime(*time.gmtime(0)[:6])
_EPOCH_NAIVE_LOCAL = datetime(*time.localtime(0)[:6])
_EPOCH = _EPOCH_NAIVE.replace(tzinfo=timezone.utc)
def _datetime_to_timestamp(dt):
# If no timezone is specified, it is assumed to be in utc zone
if dt.tzinfo is None:
dt = dt.replace(tzinfo=timezone.utc)
# We use .total_seconds() method instead of simply dt.timestamp(),
# because on Windows the latter raises OSError on datetimes ~< datetime(1970,1,1)
return int((dt - _EPOCH).total_seconds())
def _json_default(value):
@ -121,21 +135,21 @@ class TLObject:
@staticmethod
def serialize_datetime(dt):
if not dt:
if not dt and not isinstance(dt, timedelta):
return b'\0\0\0\0'
if isinstance(dt, datetime):
dt = int(dt.timestamp())
dt = _datetime_to_timestamp(dt)
elif isinstance(dt, date):
dt = int(datetime(dt.year, dt.month, dt.day).timestamp())
dt = _datetime_to_timestamp(datetime(dt.year, dt.month, dt.day))
elif isinstance(dt, float):
dt = int(dt)
elif isinstance(dt, timedelta):
# Timezones are tricky. datetime.now() + ... timestamp() works
dt = int((datetime.now() + dt).timestamp())
# Timezones are tricky. datetime.utcnow() + ... timestamp() works
dt = _datetime_to_timestamp(datetime.utcnow() + dt)
if isinstance(dt, int):
return struct.pack('<I', dt)
return struct.pack('<i', dt)
raise TypeError('Cannot interpret "{}" as a date.'.format(dt))