In Python API, Timestamp.ToDatetime() does not support full range, fails with "ValueError: year is out of range"

2,554 views
Skip to first unread message

David

unread,
Feb 13, 2019, 9:05:40 PM2/13/19
to Protocol Buffers
In protobuf/internal/well_known_types.py, you define Timestamp.ToDatetime(), which is supposed to convert a protobuf Timestamp to a Python datetimeToDateTime() is implemented as:

return datetime.utcfromtimestamp(
   
self.seconds + self.nanos / float(_NANOS_PER_SECOND))

However, the float division loses precision, and the resulting rounding error can cause this function to fail, even if the Timestamp contains a value that is representable as a Python datetime.

For example, the Python datetime.max is 9999-12-31T23:59:59.999999, which is within the supported Timestamp range. But due to the float rounding, this fails with "ValueError: year is out of range":

import datetime
from google.protobuf import timestamp_pb2

timestamp
= timestamp_pb2.Timestamp()
timestamp
.FromDatetime(datetime.datetime.max) # this is fine
print(timestamp.ToDatetime()) # this crashes

(In addition, on some platforms, utcfromtimestamp() may only support timestamps up to year 2038: https://docs.python.org/3/library/datetime.html#datetime.date.fromtimestamp).

Could you change the implementation of ToDatetime() to this instead:

_EPOCH_DATETIME = datetime.utcfromtimestamp(0)
...


def ToDatetime(self):
   
return _EPOCH_DATETIME + timedelta(
        seconds
=self.seconds,
   
    microseconds=self.nanos / float(_NANOS_PER_MICROSECOND))

Thanks!
Reply all
Reply to author
Forward
0 new messages