AttributeError: _nanosecond when updating a datetime in transaction
AttributeError: _nanosecond when updating a datetime in transaction
所以我正在尝试通过云功能更新云 firestore 中的日期时间字段,如下所示:
transaction.update(doc_ref, {'dateTimeField1': dateTimeValue})
Google 以 %Y-%m-%dT%H:%M:%SZ
或 %Y-%m-%dT%H:%M:%S.%fZ
.
格式在云函数的事件参数中将日期时间对象作为字符串发送
例如:2019-01-25T15:25:03.881Z
我正在将它转换为 datetime 对象,如下所示:
try:
datetime_obj = datetime.datetime.strptime(datetime_obj, '%Y-%m-%dT%H:%M:%S.%fZ')
except:
datetime_obj = datetime.datetime.strptime(datetime_obj, '%Y-%m-%dT%H:%M:%SZ')
datetime_obj = datetime_obj.replace(tzinfo=timezone('UTC'))
但是当我尝试执行该操作时,我遇到了以下错误:
AttributeError: _nanosecond
回溯:
File "/env/local/lib/python3.7/site-packages/google/cloud/firestore_v1beta1/batch.py", line 112, in update
reference._document_path, field_updates, option
File "/env/local/lib/python3.7/site-packages/google/cloud/firestore_v1beta1/_helpers.py", line 822, in pbs_for_update
update_pb = extractor.get_update_pb(document_path)
File "/env/local/lib/python3.7/site-packages/google/cloud/firestore_v1beta1/_helpers.py", line 459, in get_update_pb
name=document_path, fields=encode_dict(self.set_fields)
File "/env/local/lib/python3.7/site-packages/google/cloud/firestore_v1beta1/_helpers.py", line 215, in encode_dict
return {key: encode_value(value) for key, value in six.iteritems(values_dict)}
File "/env/local/lib/python3.7/site-packages/google/cloud/firestore_v1beta1/_helpers.py", line 215, in <dictcomp>
return {key: encode_value(value) for key, value in six.iteritems(values_dict)}
File "/env/local/lib/python3.7/site-packages/google/cloud/firestore_v1beta1/_helpers.py", line 169, in encode_value
return document_pb2.Value(timestamp_value=value.timestamp_pb())
File "/env/local/lib/python3.7/site-packages/google/api_core/datetime_helpers.py", line 278, in timestamp_pb
nanos = self._nanosecond or self.microsecond * 1000
AttributeError: _nanosecond
是否允许通过交易设置日期时间,或者我在这里遗漏了什么?
编辑:
代码片段:
@firestore.transactional
def update_datetime_field(transaction, doc_ref, datetime_value):
try:
datetime_obj = datetime.datetime.strptime(datetime_value, '%Y-%m-%dT%H:%M:%S.%fZ')
except:
datetime_obj = datetime.datetime.strptime(datetime_value, '%Y-%m-%dT%H:%M:%SZ')
datetime_obj = datetime_obj.replace(tzinfo=timezone('UTC'))
# Example of datetime_obj -> datetime.datetime(2019, 1, 25, 15, 25, 3, 881000, tzinfo=<UTC>)
transaction.update(doc_ref, {'datetimeField1': datetime_obj})
return True
更多信息:
- 上面的代码在文档更新时被触发
collection1/document1/collection2/document2
- datetime 对象是 python 来自标准库的 datetime
- 我正在尝试通过使用 pytz
更改时区来将日期转换为 UTC
编辑 2:
更好的全图:
from firebase_admin import credentials, firestore
# initialize firebase admin sdk
creds = credentials.ApplicationDefault()
firebase_admin.initialize_app(creds,{'projectId': 'myProjectId'})
@firestore.transactional
def update_datetime_field(transaction, doc_ref, datetime_value):
try:
datetime_obj = datetime.datetime.strptime(datetime_value, '%Y-%m-%dT%H:%M:%S.%fZ')
except:
datetime_obj = datetime.datetime.strptime(datetime_value, '%Y-%m-%dT%H:%M:%SZ')
datetime_obj = datetime_obj.replace(tzinfo=timezone('UTC'))
# Example of datetime_obj -> datetime.datetime(2019, 1, 25, 15, 25, 3, 881000, tzinfo=<UTC>)
transaction.update(doc_ref, {'datetimeField1': datetime_obj})
return True
def update_datetime_in_transaction(event, context):
datetime_value = event['value']['fields']['datetimeField1']['timestampValue']
# this looks something like 2019-01-25T15:25:03.881Z
# prepare document reference to document
doc_ref = prepare_doc_ref(event, context)
# update_datetime_field
client = firestore.client()
transaction = client.transaction()
update_datetime_field(transaction, doc_ref, datetime_value)
return True
编辑 3:
事件参数截图:
控制台截图:
因此 firestore python sdk 需要 _nanosecond
属性,该属性目前在 python 标准库的日期时间中不可用(将来会添加。更多详细信息 here)
所以在检查了他们的代码库之后,我发现了一个名为 DatetimeWithNanoseconds
的 class,它 将纳秒支持添加到传统的日期时间对象 。
class(google/api_core中的datetime_helpers.py文件)的代码如下(为简洁起见故意删除了部分):
class DatetimeWithNanoseconds(datetime.datetime):
"""Track nanosecond in addition to normal datetime attrs.
Nanosecond can be passed only as a keyword argument.
"""
__slots__ = ('_nanosecond',)
@classmethod
def from_rfc3339(cls, stamp):
with_nanos = _RFC3339_NANOS.match(stamp)
if with_nanos is None:
raise ValueError(
'Timestamp: {}, does not match pattern: {}'.format(
stamp, _RFC3339_NANOS.pattern))
bare = datetime.datetime.strptime(
with_nanos.group('no_fraction'), _RFC3339_NO_FRACTION)
fraction = with_nanos.group('nanos')
if fraction is None:
nanos = 0
else:
scale = 9 - len(fraction)
nanos = int(fraction) * (10 ** scale)
return cls(bare.year, bare.month, bare.day,
bare.hour, bare.minute, bare.second,
nanosecond=nanos, tzinfo=pytz.UTC)
所以现在,我可以使用 class 而不是 datetime.datetime
来解析使用 DatetimeWithNanoseconds.from_rfc3339(timestamp)
方法在云函数的事件参数中作为字符串发送的日期时间。
示例:
from google.api_core.datetime_helpers import DatetimeWithNanoseconds
d1 = DatetimeWithNanoseconds.from_rfc3339('2019-01-25T15:25:03.881Z')
print(d1)
# DatetimeWithNanoseconds(2019, 1, 25, 15, 25, 3, 881000, tzinfo=<UTC>)
class 也有 rfc3339()
方法来给你字符串表示。
示例:
d1.rfc3339()
# 2019-01-25T15:25:03.881Z
Alternative solution:
您也可以使用 pandas.Timestamp()
而不是 DatetimeWithNanoseconds.from_rfc3339()
。
示例:
import pandas as pd
d1 = pd.Timestamp('2019-01-25T15:25:03.881Z')
print(d1)
# Timestamp('2019-01-25 15:25:03.881000+0000', tz='UTC')
我建议使用 DatetimeWithNanoseconds
,因为它随 sdk 一起提供,您不需要在 requirements.txt
中添加额外的 pandas 依赖项,这会增加调用延迟冷启动。更多详情 here.
希望这对您有所帮助。
所以我正在尝试通过云功能更新云 firestore 中的日期时间字段,如下所示:
transaction.update(doc_ref, {'dateTimeField1': dateTimeValue})
Google 以 %Y-%m-%dT%H:%M:%SZ
或 %Y-%m-%dT%H:%M:%S.%fZ
.
格式在云函数的事件参数中将日期时间对象作为字符串发送
例如:2019-01-25T15:25:03.881Z
我正在将它转换为 datetime 对象,如下所示:
try:
datetime_obj = datetime.datetime.strptime(datetime_obj, '%Y-%m-%dT%H:%M:%S.%fZ')
except:
datetime_obj = datetime.datetime.strptime(datetime_obj, '%Y-%m-%dT%H:%M:%SZ')
datetime_obj = datetime_obj.replace(tzinfo=timezone('UTC'))
但是当我尝试执行该操作时,我遇到了以下错误:
AttributeError: _nanosecond
回溯:
File "/env/local/lib/python3.7/site-packages/google/cloud/firestore_v1beta1/batch.py", line 112, in update
reference._document_path, field_updates, option
File "/env/local/lib/python3.7/site-packages/google/cloud/firestore_v1beta1/_helpers.py", line 822, in pbs_for_update
update_pb = extractor.get_update_pb(document_path)
File "/env/local/lib/python3.7/site-packages/google/cloud/firestore_v1beta1/_helpers.py", line 459, in get_update_pb
name=document_path, fields=encode_dict(self.set_fields)
File "/env/local/lib/python3.7/site-packages/google/cloud/firestore_v1beta1/_helpers.py", line 215, in encode_dict
return {key: encode_value(value) for key, value in six.iteritems(values_dict)}
File "/env/local/lib/python3.7/site-packages/google/cloud/firestore_v1beta1/_helpers.py", line 215, in <dictcomp>
return {key: encode_value(value) for key, value in six.iteritems(values_dict)}
File "/env/local/lib/python3.7/site-packages/google/cloud/firestore_v1beta1/_helpers.py", line 169, in encode_value
return document_pb2.Value(timestamp_value=value.timestamp_pb())
File "/env/local/lib/python3.7/site-packages/google/api_core/datetime_helpers.py", line 278, in timestamp_pb
nanos = self._nanosecond or self.microsecond * 1000
AttributeError: _nanosecond
是否允许通过交易设置日期时间,或者我在这里遗漏了什么?
编辑:
代码片段:
@firestore.transactional
def update_datetime_field(transaction, doc_ref, datetime_value):
try:
datetime_obj = datetime.datetime.strptime(datetime_value, '%Y-%m-%dT%H:%M:%S.%fZ')
except:
datetime_obj = datetime.datetime.strptime(datetime_value, '%Y-%m-%dT%H:%M:%SZ')
datetime_obj = datetime_obj.replace(tzinfo=timezone('UTC'))
# Example of datetime_obj -> datetime.datetime(2019, 1, 25, 15, 25, 3, 881000, tzinfo=<UTC>)
transaction.update(doc_ref, {'datetimeField1': datetime_obj})
return True
更多信息:
- 上面的代码在文档更新时被触发
collection1/document1/collection2/document2
- datetime 对象是 python 来自标准库的 datetime
- 我正在尝试通过使用 pytz 更改时区来将日期转换为 UTC
编辑 2:
更好的全图:
from firebase_admin import credentials, firestore
# initialize firebase admin sdk
creds = credentials.ApplicationDefault()
firebase_admin.initialize_app(creds,{'projectId': 'myProjectId'})
@firestore.transactional
def update_datetime_field(transaction, doc_ref, datetime_value):
try:
datetime_obj = datetime.datetime.strptime(datetime_value, '%Y-%m-%dT%H:%M:%S.%fZ')
except:
datetime_obj = datetime.datetime.strptime(datetime_value, '%Y-%m-%dT%H:%M:%SZ')
datetime_obj = datetime_obj.replace(tzinfo=timezone('UTC'))
# Example of datetime_obj -> datetime.datetime(2019, 1, 25, 15, 25, 3, 881000, tzinfo=<UTC>)
transaction.update(doc_ref, {'datetimeField1': datetime_obj})
return True
def update_datetime_in_transaction(event, context):
datetime_value = event['value']['fields']['datetimeField1']['timestampValue']
# this looks something like 2019-01-25T15:25:03.881Z
# prepare document reference to document
doc_ref = prepare_doc_ref(event, context)
# update_datetime_field
client = firestore.client()
transaction = client.transaction()
update_datetime_field(transaction, doc_ref, datetime_value)
return True
编辑 3:
事件参数截图:
控制台截图:
因此 firestore python sdk 需要 _nanosecond
属性,该属性目前在 python 标准库的日期时间中不可用(将来会添加。更多详细信息 here)
所以在检查了他们的代码库之后,我发现了一个名为 DatetimeWithNanoseconds
的 class,它 将纳秒支持添加到传统的日期时间对象 。
class(google/api_core中的datetime_helpers.py文件)的代码如下(为简洁起见故意删除了部分):
class DatetimeWithNanoseconds(datetime.datetime):
"""Track nanosecond in addition to normal datetime attrs.
Nanosecond can be passed only as a keyword argument.
"""
__slots__ = ('_nanosecond',)
@classmethod
def from_rfc3339(cls, stamp):
with_nanos = _RFC3339_NANOS.match(stamp)
if with_nanos is None:
raise ValueError(
'Timestamp: {}, does not match pattern: {}'.format(
stamp, _RFC3339_NANOS.pattern))
bare = datetime.datetime.strptime(
with_nanos.group('no_fraction'), _RFC3339_NO_FRACTION)
fraction = with_nanos.group('nanos')
if fraction is None:
nanos = 0
else:
scale = 9 - len(fraction)
nanos = int(fraction) * (10 ** scale)
return cls(bare.year, bare.month, bare.day,
bare.hour, bare.minute, bare.second,
nanosecond=nanos, tzinfo=pytz.UTC)
所以现在,我可以使用 class 而不是 datetime.datetime
来解析使用 DatetimeWithNanoseconds.from_rfc3339(timestamp)
方法在云函数的事件参数中作为字符串发送的日期时间。
示例:
from google.api_core.datetime_helpers import DatetimeWithNanoseconds
d1 = DatetimeWithNanoseconds.from_rfc3339('2019-01-25T15:25:03.881Z')
print(d1)
# DatetimeWithNanoseconds(2019, 1, 25, 15, 25, 3, 881000, tzinfo=<UTC>)
class 也有 rfc3339()
方法来给你字符串表示。
示例:
d1.rfc3339()
# 2019-01-25T15:25:03.881Z
Alternative solution:
您也可以使用 pandas.Timestamp()
而不是 DatetimeWithNanoseconds.from_rfc3339()
。
示例:
import pandas as pd
d1 = pd.Timestamp('2019-01-25T15:25:03.881Z')
print(d1)
# Timestamp('2019-01-25 15:25:03.881000+0000', tz='UTC')
我建议使用 DatetimeWithNanoseconds
,因为它随 sdk 一起提供,您不需要在 requirements.txt
中添加额外的 pandas 依赖项,这会增加调用延迟冷启动。更多详情 here.
希望这对您有所帮助。