我有一些时间格式为 HH:MM::SS.nano_seconds 的日志文件(例如 01:02:03.123456789)。我想在 python 中创建一个日期时间,这样我就可以巧妙地对时间进行数学运算(例如,计算时差)。strptime使用 %f在微秒内效果很好。Python datetime 和 time 模块真的不支持纳秒吗?
5 回答
您可以从源代码中看到datetime
对象不支持比微秒更精细的任何东西。正如 Mike Pennington 在评论中指出的那样,这可能是因为计算机硬件时钟几乎没有那么精确。维基百科说HPET的频率“至少 10 MHz”,这意味着每 100 纳秒有一个滴答声。
如果您可以忍受扔掉最后三位数字(无论如何这可能不太有意义),您可以通过将输入字符串切成小数点后只有六位数字并使用解析来解析它%f
。否则,看起来您必须自己实现减法。
很久以后的更新:numpy 和 pandas 现在都(有些不同)支持时间戳,包括跟踪纳秒的可能性,这通常是很好的解决方案。如何查看其他答案。
Python 3.7+ 在( PEP 564 ) 中也有time.time_ns
相关函数,但在.time
datetime
这是一个旧线程,但仍然......
您可以使用 Pandas 功能来实现这一点。我有像“2019-03-22T14:00:01.700311864Z”这样的时间戳,我通过以下方式转换为时间戳:
firstStamp = pd.to_datetime(firstStampString, format='%Y-%m-%dT%H:%M:%S.%fZ')
lastStamp = pd.to_datetime(lastStampString, format='%Y-%m-%dT%H:%M:%S.%fZ')
deltaTime = lastStamp - firstStamp
这工作正常。
您可以很自然地使用纳秒甚至更精确的时间单位(ps、fs、as)和numpy
. Numpy 有自己的Datetimes 和 Timedeltas实现,所以你可以尝试np.datetime64
:
import numpy as np
def str_to_ns(time_str):
"""
input: time in a format `hh:mm:ss.up_to_9_digits`
"""
h, m, s = time_str.split(":")
int_s, ns = s.split(".")
ns = map(lambda t, unit: np.timedelta64(t, unit),
[h,m,int_s,ns.ljust(9, '0')],['h','m','s','ns'])
return sum(ns)
然后您可以通过以下方式使用此功能:
>>> src = "1:2:34.123456789"
>>> out = str_to_ns(src)
>>> print(out)
3754123456789 nanoseconds
>>> out / np.timedelta64(1,'h')
1.0428120713302778
>>> out / np.timedelta64(1,'m')
62.568724279816664
>>> out / np.timedelta64(1,'s')
3754.123456789
算术也是可能的:
>>> t1, t2 = str_to_ns("1:0:12.12345678"), str_to_ns("1:0:12.12")
>>> t1 - t2
numpy.timedelta64(3456780,'ns')
我同意这不是那么自然,但是通过这种方式,您可以使用numpy
.
如果您实际上并不关心纳秒,但您仍然希望能够解析秒内具有 >6 位小数的日期时间,则可以使用python-dateutils库。
例如,尝试使用标准 lib datetime 包:
>>> from datetime import datetime
>>> datetime.strptime('2021-02-14T02:27:57.96119078Z', '%Y-%m-%dT%H:%M:%S.%fZ')
ValueError: time data '2021-02-14T02:27:57.96119078Z' does not match format '%Y-%m-%dT%H:%M:%S.%fZ'
但是使用 python-dateutils,它实际上会解析它而不会引发错误:
>>> from dateutil.parser import isoparse
>>> isoparse('2021-02-14T02:27:57.96119078Z')
datetime.datetime(2021, 2, 14, 2, 27, 57, 961190, tzinfo=tzutc())
请注意,它不会保留纳秒(也不会正确舍入 - 它只是在 6 个小数位后截断),但它至少不会破坏解析 >6 个小数位。
def parse_nanodate(s):
"""
parse date, ignore nanoseconds
sample input: 2020-12-31T16:20:00.000000123Z
--> 123ns will be ignored
"""
if s[-1] == 'Z':
# add explicit UTC timezone, to make strptime happy
s += '+0000'
return datetime.datetime.strptime(
s[0:26]+s[29:], '%Y-%m-%dT%H:%M:%S.%fZ%z')