将DatetimeWithNanoseconds转换为python firestore中的日期格式

时间:2019-12-29 05:04:33

标签: python firebase google-cloud-firestore

我正在尝试使用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")

5 个答案:

答案 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应该解决的问题)。

DatetimeWithNanosecondsnanosecond添加一个只读datetime属性,但保留其microsecond属性。目的似乎是可以在创建对象时设置一个或另一个,但不能同时设置两个,然后读取其中一个。使用DatetimeWithNanoseconds构造函数时,可以设置microsecondnanosecond,但不能同时设置两者(如果设置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