diff --git a/google/cloud/storage/blob.py b/google/cloud/storage/blob.py index 4129675c8..ce24d719f 100644 --- a/google/cloud/storage/blob.py +++ b/google/cloud/storage/blob.py @@ -55,7 +55,7 @@ from google.cloud import exceptions from google.cloud._helpers import _bytes_to_unicode from google.cloud._helpers import _datetime_to_rfc3339 -from google.cloud._helpers import _rfc3339_to_datetime +from google.cloud._helpers import _rfc3339_nanos_to_datetime from google.cloud._helpers import _to_bytes from google.cloud.exceptions import NotFound from google.cloud.storage._helpers import _add_generation_match_parameters @@ -3645,7 +3645,7 @@ def retention_expiration_time(self): """ value = self._properties.get("retentionExpirationTime") if value is not None: - return _rfc3339_to_datetime(value) + return _rfc3339_nanos_to_datetime(value) @property def self_link(self): @@ -3731,7 +3731,7 @@ def time_deleted(self): """ value = self._properties.get("timeDeleted") if value is not None: - return _rfc3339_to_datetime(value) + return _rfc3339_nanos_to_datetime(value) @property def time_created(self): @@ -3746,7 +3746,7 @@ def time_created(self): """ value = self._properties.get("timeCreated") if value is not None: - return _rfc3339_to_datetime(value) + return _rfc3339_nanos_to_datetime(value) @property def updated(self): @@ -3761,7 +3761,7 @@ def updated(self): """ value = self._properties.get("updated") if value is not None: - return _rfc3339_to_datetime(value) + return _rfc3339_nanos_to_datetime(value) @property def custom_time(self): @@ -3776,7 +3776,7 @@ def custom_time(self): """ value = self._properties.get("customTime") if value is not None: - return _rfc3339_to_datetime(value) + return _rfc3339_nanos_to_datetime(value) @custom_time.setter def custom_time(self, value): diff --git a/google/cloud/storage/bucket.py b/google/cloud/storage/bucket.py index 31a188134..76715d835 100644 --- a/google/cloud/storage/bucket.py +++ b/google/cloud/storage/bucket.py @@ -28,7 +28,7 @@ from google.api_core import datetime_helpers from google.cloud._helpers import _datetime_to_rfc3339 from google.cloud._helpers import _NOW -from google.cloud._helpers import _rfc3339_to_datetime +from google.cloud._helpers import _rfc3339_nanos_to_datetime from google.cloud.exceptions import NotFound from google.api_core.iam import Policy from google.cloud.storage import _signing @@ -499,7 +499,7 @@ def uniform_bucket_level_access_locked_time(self): ubla = self.get("uniformBucketLevelAccess", {}) stamp = ubla.get("lockedTime") if stamp is not None: - stamp = _rfc3339_to_datetime(stamp) + stamp = _rfc3339_nanos_to_datetime(stamp) return stamp @property @@ -2556,7 +2556,7 @@ def retention_policy_effective_time(self): if policy is not None: timestamp = policy.get("effectiveTime") if timestamp is not None: - return _rfc3339_to_datetime(timestamp) + return _rfc3339_nanos_to_datetime(timestamp) @property def retention_policy_locked(self): @@ -2675,7 +2675,7 @@ def time_created(self): """ value = self._properties.get("timeCreated") if value is not None: - return _rfc3339_to_datetime(value) + return _rfc3339_nanos_to_datetime(value) @property def versioning_enabled(self): diff --git a/google/cloud/storage/hmac_key.py b/google/cloud/storage/hmac_key.py index 47ca33cfc..3fd49079e 100644 --- a/google/cloud/storage/hmac_key.py +++ b/google/cloud/storage/hmac_key.py @@ -13,7 +13,7 @@ # limitations under the License. from google.cloud.exceptions import NotFound -from google.cloud._helpers import _rfc3339_to_datetime +from google.cloud._helpers import _rfc3339_nanos_to_datetime from google.cloud.storage.constants import _DEFAULT_TIMEOUT from google.cloud.storage.retry import DEFAULT_RETRY @@ -151,7 +151,7 @@ def time_created(self): """ value = self._properties.get("timeCreated") if value is not None: - return _rfc3339_to_datetime(value) + return _rfc3339_nanos_to_datetime(value) @property def updated(self): @@ -164,7 +164,7 @@ def updated(self): """ value = self._properties.get("updated") if value is not None: - return _rfc3339_to_datetime(value) + return _rfc3339_nanos_to_datetime(value) @property def path(self): diff --git a/tests/system/test_system.py b/tests/system/test_system.py index bb6ff5b54..5973e6c73 100644 --- a/tests/system/test_system.py +++ b/tests/system/test_system.py @@ -1063,6 +1063,21 @@ def test_upload_blob_custom_time(self): custom_time = same_blob.custom_time.replace(tzinfo=None) self.assertEqual(custom_time, current_time) + def test_blob_custom_time_no_micros(self): + # Test that timestamps without microseconds are treated correctly by + # custom_time encoding/decoding. + blob = self.bucket.blob("CustomTimeNoMicrosBlob") + file_contents = b"Hello World" + time_without_micros = datetime.datetime(2021, 2, 10, 12, 30) + blob.custom_time = time_without_micros + blob.upload_from_string(file_contents) + self.case_blobs_to_delete.append(blob) + + same_blob = self.bucket.blob(("CustomTimeNoMicrosBlob")) + same_blob.reload(projection="full") + custom_time = same_blob.custom_time.replace(tzinfo=None) + self.assertEqual(custom_time, time_without_micros) + def test_blob_crc32_md5_hash(self): blob = self.bucket.blob("MyBuffer") file_contents = b"Hello World"