Skip to content

Commit

Permalink
fix: correctly decode times without microseconds (#375)
Browse files Browse the repository at this point in the history
Currently custom_time is not being decoded correctly if the value
has a zero in the microseconds field. This fixes the issue for
custom_time as well as elsewhere by replacing _datetime_to_rfc3339
with _rfc3339_nanos_to_datetime.

Fixes #363
  • Loading branch information
tritone committed Feb 10, 2021
1 parent 921553c commit 37a1eb5
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 13 deletions.
12 changes: 6 additions & 6 deletions google/cloud/storage/blob.py
Expand Up @@ -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
Expand Down Expand Up @@ -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):
Expand Down Expand Up @@ -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):
Expand All @@ -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):
Expand All @@ -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):
Expand All @@ -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):
Expand Down
8 changes: 4 additions & 4 deletions google/cloud/storage/bucket.py
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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):
Expand Down Expand Up @@ -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):
Expand Down
6 changes: 3 additions & 3 deletions google/cloud/storage/hmac_key.py
Expand Up @@ -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
Expand Down Expand Up @@ -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):
Expand All @@ -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):
Expand Down
15 changes: 15 additions & 0 deletions tests/system/test_system.py
Expand Up @@ -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"
Expand Down

0 comments on commit 37a1eb5

Please sign in to comment.