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

bar*_*uda 2 python datetime 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")
Run Code Online (Sandbox Code Playgroud)

Voy*_*Voy 16

转换DatetimeWithNanosecondsdatetime.datetime

datetime.datetime.fromtimestamp(datetime_with_nanoseconds.timestamp())
Run Code Online (Sandbox Code Playgroud)

尽管没有直接解决转换为日期格式的问题,但仍将这个答案留在这里,因为这是有关此转换的唯一帖子,而且我还没有在任何地方看到这个简单的直接解决方案。


ald*_*del 7

正如卢克的回答所暗示的,您可以使用 的所有常用方法datetime和 的值DatetimeWithNanoseconds,因为它是一个子类。例如,您可以获取doc_data['start_date'].timestamp()自 1970-01-01 以来的以秒为单位的时间(包括小数秒)。

然而,通过试验和查看DatetimeWithNanoseconds 的实现,我注意到开发人员应该注意的一些问题(并且可能是 Google 应该修复的)。

DatetimeWithNanoseconds将只读nanosecond属性添加到datetime,但保留其microsecond属性。其目的似乎是您可以在创建对象时设置其中之一,但不能同时设置两者,然后读取其中之一。使用DatetimeWithNanoseconds构造函数时,可以设置microsecondnanosecond,但不能同时设置两者(如果设置nanosecond,则必须将其指定为关键字参数)。如果您尝试同时设置两者,则会引发异常。如果您仅设置nanosecond,它会正确设置microsecondnanosecond / 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
Run Code Online (Sandbox Code Playgroud)

如果您以其他方式构造 a DatetimeWithNanoseconds,例如,您总是会得到一个设置为零的DatetimeWithNanoseconds.now()值。nanosecond

>>> now = DatetimeWithNanoseconds.now()
>>> now.microsecond
51570
>>> now.nanosecond
0
Run Code Online (Sandbox Code Playgroud)

从 Firestore 获取文档时获得的值似乎总是设置nanosecond为零!因此,如果我要获取带有时间戳的文档,然后将其写回 Firestore,则会丢失精度。(尽管我承认我使用的是一个相当旧的版本firebase-admin,所以它可能已在更新的版本中修复。)

我目前正在做类似的事情来从时间戳中提取秒和纳秒(我在不确定时间戳是 adatetime还是 a 的情况下使用它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')
Run Code Online (Sandbox Code Playgroud)

为了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
Run Code Online (Sandbox Code Playgroud)

它很难看,但我还没有找到更简洁的方法。


sha*_*ain 0

尝试这个解决方案

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)
Run Code Online (Sandbox Code Playgroud)