diff --git a/firestore/google/cloud/firestore_v1beta1/_helpers.py b/firestore/google/cloud/firestore_v1beta1/_helpers.py index be02fe1e8ad8..949ba322417c 100644 --- a/firestore/google/cloud/firestore_v1beta1/_helpers.py +++ b/firestore/google/cloud/firestore_v1beta1/_helpers.py @@ -23,7 +23,7 @@ from google.cloud import exceptions from google.cloud._helpers import _datetime_to_pb_timestamp -from google.cloud._helpers import _pb_timestamp_to_datetime +from google.api_core.datetime_helpers import DatetimeWithNanoseconds from google.cloud.firestore_v1beta1 import transforms from google.cloud.firestore_v1beta1 import types from google.cloud.firestore_v1beta1.field_path import FieldPath @@ -165,6 +165,9 @@ def encode_value(value): if isinstance(value, float): return document_pb2.Value(double_value=value) + if isinstance(value, DatetimeWithNanoseconds): + return document_pb2.Value(timestamp_value=value.timestamp_pb()) + if isinstance(value, datetime.datetime): return document_pb2.Value(timestamp_value=_datetime_to_pb_timestamp(value)) @@ -275,10 +278,7 @@ def decode_value(value, client): elif value_type == "double_value": return value.double_value elif value_type == "timestamp_value": - # NOTE: This conversion is "lossy", Python ``datetime.datetime`` - # has microsecond precision but ``timestamp_value`` has - # nanosecond precision. - return _pb_timestamp_to_datetime(value.timestamp_value) + return DatetimeWithNanoseconds.from_timestamp_pb(value.timestamp_value) elif value_type == "string_value": return value.string_value elif value_type == "bytes_value": diff --git a/firestore/tests/unit/test__helpers.py b/firestore/tests/unit/test__helpers.py index dd63d5affc6c..c53a23ceb8d6 100644 --- a/firestore/tests/unit/test__helpers.py +++ b/firestore/tests/unit/test__helpers.py @@ -163,7 +163,20 @@ def test_float(self): expected = _value_pb(double_value=value) self.assertEqual(result, expected) - def test_datetime(self): + def test_datetime_with_nanos(self): + from google.api_core.datetime_helpers import DatetimeWithNanoseconds + from google.protobuf import timestamp_pb2 + + dt_seconds = 1488768504 + dt_nanos = 458816991 + timestamp_pb = timestamp_pb2.Timestamp(seconds=dt_seconds, nanos=dt_nanos) + dt_val = DatetimeWithNanoseconds.from_timestamp_pb(timestamp_pb) + + result = self._call_fut(dt_val) + expected = _value_pb(timestamp_value=timestamp_pb) + self.assertEqual(result, expected) + + def test_datetime_wo_nanos(self): from google.protobuf import timestamp_pb2 dt_seconds = 1488768504 @@ -387,20 +400,16 @@ def test_float(self): (3,) <= sys.version_info < (3, 4, 4), "known datetime bug (bpo-23517) in Python" ) def test_datetime(self): + from google.api_core.datetime_helpers import DatetimeWithNanoseconds from google.protobuf import timestamp_pb2 - from google.cloud._helpers import UTC dt_seconds = 552855006 - dt_nanos = 766961000 - # Make sure precision is valid in microseconds too. - self.assertEqual(dt_nanos % 1000, 0) + dt_nanos = 766961828 timestamp_pb = timestamp_pb2.Timestamp(seconds=dt_seconds, nanos=dt_nanos) value = _value_pb(timestamp_value=timestamp_pb) - expected_dt_val = datetime.datetime.utcfromtimestamp( - dt_seconds + 1e-9 * dt_nanos - ).replace(tzinfo=UTC) + expected_dt_val = DatetimeWithNanoseconds.from_timestamp_pb(timestamp_pb) self.assertEqual(self._call_fut(value), expected_dt_val) def test_unicode(self):