我正在尝试使用python将Firestore时间戳转换为毫秒或日期格式,以使用该日期执行计算。尝试将其解析为最新的结果。
TypeError: strptime() argument 1 must be str, not DatetimeWithNanoseconds.
如何在python中将Firestore时间戳转换为毫秒/日期格式?我需要用它来进行计算。
docs = db.collection(u'status').stream()
for doc in docs:
doc_data = doc.to_dict()
# TypeError: strptime() argument 1 must be str, not DatetimeWithNanoseconds
utc_time = datetime.strptime(doc_data['start_date'], "%Y-%m-%dT%H:%M:%S.%fZ")
答案 0 :(得分:3)
答案 1 :(得分:2)
尝试此解决方案
try:
utc_time = strptime(''.join(str(doc_data['start_date']).rsplit(':', 1)), "%Y-%m-%d %H:%M:%S.%f%z")
except Exception as e:
if type(e) is ValueError:
utc_time = strptime(''.join(str(doc_data['start_date']).rsplit(':', 1)), "%Y-%m-%d %H:%M:%S%z")
else :
print(e)
答案 2 :(得分:1)
DatetimeWithNanoseconds
是一个对象,因此您必须使用其属性。要查看其属性,请使用print(dir(doc_data['start_date']))
。最后,您可以将其格式化为字符串,下面的代码演示如何操作。
docs = db.collection(u'status').stream()
for doc in docs:
doc_data = doc_data.to_dict()
val1 = doc_data['start_date']
year,month,day,hour,minute,second,tzinfo = val1.year,val1.month,val1.day,val1.hour, val1.minute, val1.second, val1.tzinfo
utc_time = "%s-%s-%s %s:%s:%s.%s"%(year, month, day,hour,minute,second,tzinfo)
答案 3 :(得分:1)
正如卢克的答案所暗示的,您可以将datetime
的所有常用方法与值DatetimeWithNanoseconds
一起使用,因为它是一个子类。因此,例如,您可以执行doc_data['start_date'].timestamp()
以获取自1970-01-01以来的秒数(包括小数秒)。
但是,通过试验和查看implementation of DatetimeWithNanoseconds,我注意到了开发人员应该意识到的一些问题(可能还有Google应该解决的问题)。
DatetimeWithNanoseconds
向nanosecond
添加一个只读datetime
属性,但保留其microsecond
属性。目的似乎是可以在创建对象时设置一个或另一个,但不能同时设置两个,然后读取其中一个。使用DatetimeWithNanoseconds
构造函数时,可以设置microsecond
或nanosecond
,但不能同时设置两者(如果设置nanosecond
,则必须将其指定为关键字参数)。如果尝试同时设置两者,则将引发异常。如果仅设置nanosecond
,则可以将microsecond
正确设置为nanosecond / 1000
,向下取整。如果仅设置microsecond
,则会设置microsecond
,但是nanosecond
设置为零。
>>> from google.api_core.datetime_helpers import DatetimeWithNanoseconds
>>> d1 = DatetimeWithNanoseconds(2020, 6, 22, 17, 1, 30, 12345)
>>> d1.microsecond
12345
>>> d1.nanosecond
0
>>> d2 = DatetimeWithNanoseconds(2020, 6, 22, 17, 1, 30, nanosecond=1234567)
>>> d2.microsecond
1234
>>> d2.nanosecond
1234567
如果您以其他方式构造DatetimeWithNanoseconds
,例如DatetimeWithNanoseconds.now()
,则总是会得到nanosecond
设置为零的值。
>>> now = DatetimeWithNanoseconds.now()
>>> now.microsecond
51570
>>> now.nanosecond
0
从Firestore提取文档时获得的值似乎总是将nanosecond
设置为零!因此,如果我要获取带有时间戳的文档,然后将其写回到Firestore,它将失去精度。 (当然,我使用的是firebase-admin
的旧版本,因此它可能已在较新的版本中修复。)
我目前正在执行这样的操作以从时间戳中提取秒和纳秒(我在不确定该时间戳是datetime
还是DatetimeWithNanoseconds
的情况下使用此方法):
def get_seconds_and_nanoseconds(val):
if isinstance(val, datetime_helpers.DatetimeWithNanoseconds) and val.nanosecond:
return {
'nanoseconds': val.nanosecond,
'seconds': int(val.timestamp()),
}
if isinstance(val, datetime):
return {
'nanoseconds': 1000 * int(val.microsecond),
'seconds': int(val.timestamp()),
}
raise TypeError(f'Not a datetime or DatetimeWithNanoseconds')
要在几秒钟和几纳秒的时间内构造出正确的DatetimeWithNanoseconds
,我可以这样做:
def datetime_with_nanoseconds(seconds, nanoseconds):
dt = datetime.fromtimestamp(seconds, tz=timezone.utc)
dtnanos = datetime_helpers.DatetimeWithNanoseconds(
dt.year,
dt.month,
dt.day,
dt.hour,
dt.minute,
dt.second,
nanosecond=nanoseconds,
tzinfo=dt.tzinfo,
)
return dtnanos
这很丑陋,但是我还没有找到更简洁的方法。
答案 4 :(得分:-1)
import datetime
# here a is instance of 'google.api_core.datetime_helpers.DatetimeWithNanoseconds'
# we use datetime.combine method to convert DatetimeWithNanosecond into datetime object
answer = datetime.datetime.combine(date=a.date(), time=a.time(), tzinfo=a.tzinfo)
print(type(answer)
# it will be class datetime
访问https://docs.python.org/3/library/datetime.html#datetime.datetime.combine