Int*_*rer 4 python time datetime timestamp
我试图在 Windows 操作系统和 macOS 上使用 Python 3.10+ 获取精确到微秒的时间戳。
\n在 Windows 操作系统上,我注意到 Python 的内置time.time()
(与 配对datetime.fromtimestamp()
)并且datetime.datetime.now()
时钟似乎较慢。它们没有足够的分辨率来区分微秒级事件。好消息是和time
之类的函数似乎确实使用了足够快的时钟来测量微秒级事件。time.perf_counter()
time.time_ns()
可悲的是,我不知道如何将它们放入datetime
对象中。如何将 PEP 564 的纳秒分辨率时间函数的输出time.perf_counter()
转换为对象datetime
?
注意:我不需要纳秒级的东西,所以可以放弃低于 1-\xce\xbcs 的精度。
\n目前的解决方案
\n这是我当前的(hacky)解决方案,实际上工作正常,但我想知道是否有更干净的方法:
\nimport time\nfrom datetime import datetime, timedelta\nfrom typing import Final\n\nIMPORT_TIMESTAMP: Final[datetime] = datetime.now()\nINITIAL_PERF_COUNTER: Final[float] = time.perf_counter()\n\n\ndef get_timestamp() -> datetime:\n """Get a high resolution timestamp with \xce\xbcs-level precision."""\n dt_sec = time.perf_counter() - INITIAL_PERF_COUNTER\n return IMPORT_TIMESTAMP + timedelta(seconds=dt_sec)\n
Run Code Online (Sandbox Code Playgroud)\n
这几乎已经是最好的了,因为C 模块(如果可用)会使用datetime
快速 C 实现覆盖该模块的纯 Python 实现中定义的所有类,并且没有钩子。
\n参考:python/cpython@cf86e36
注意:
\ndatetime.now()
和获取性能计数器时间之间所需的时间。datetime
和 a会产生亚微秒的性能成本timedelta
。根据您的具体用例,如果多次调用,这可能会也可能无关紧要。
\n一个小小的改进是:
\nINITIAL_TIMESTAMP: Final[float] = time.time()\nINITIAL_TIMESTAMP_PERF_COUNTER: Final[float] = time.perf_counter()\n\ndef get_timestamp_float() -> float:\n dt_sec = time.perf_counter() - INITIAL_TIMESTAMP_PERF_COUNTER\n return INITIAL_TIMESTAMP + dt_sec\n\ndef get_timestamp_now() -> datetime:\n dt_sec = time.perf_counter() - INITIAL_TIMESTAMP_PERF_COUNTER\n return datetime.fromtimestamp(INITIAL_TIMESTAMP + dt_sec)\n
Run Code Online (Sandbox Code Playgroud)\n视窗:
\n# Intrinsic error\ntimeit.timeit(\'datetime.now()\', setup=\'from datetime import datetime\')/1000000 # 0.31 \xce\xbcs\ntimeit.timeit(\'time.time()\', setup=\'import time\')/1000000 # 0.07 \xce\xbcs\n\n# Performance cost\nsetup = \'from datetime import datetime, timedelta; import time\'\ntimeit.timeit(\'datetime.now() + timedelta(1.000001)\', setup=setup)/1000000 # 0.79 \xce\xbcs\ntimeit.timeit(\'datetime.fromtimestamp(time.time() + 1.000001)\', setup=setup)/1000000 # 0.44 \xce\xbcs\n
Run Code Online (Sandbox Code Playgroud)\n# Resolution\nmin get_timestamp_float() delta: 239 ns\n
Run Code Online (Sandbox Code Playgroud)\nWindows 和 macOS:
\n视窗 | 苹果系统 | |
---|---|---|
# 固有错误 | ||
timeit.timeit(\'datetime.now()\', setup=\'from datetime import datetime\')/1000000 | 0.31 \xce\xbcs | 0.61 \xce\xbcs |
timeit.timeit(\'time.time()\', setup=\'import time\')/1000000 | 0.07 \xce\xbcs | 0.08 \xce\xbcs |
# 性能成本 | ||
setup = \'from datetime import datetime, timedelta; import time\' | - | - |
timeit.timeit(\'datetime.now() + timedelta(1.000001)\', setup=setup)/1000000 | 0.79 \xce\xbcs | 1.26 \xce\xbcs |
timeit.timeit(\'datetime.fromtimestamp(time.time() + 1.000001)\', setup=setup)/1000000 | 0.44 \xce\xbcs | 0.69 \xce\xbcs |
# 解决 | ||
min time() delta (基准) | x毫秒 | 716纳秒 |
min get_timestamp_float() delta | 239纳秒 | 239纳秒 |
正如Kelly Bundy在评论中float
指出的那样,239 ns 是 Unix 时间量级允许的最小差异。
x = time.time()\nprint((math.nextafter(x, 2*x) - x) * 1e9) # 238.4185791015625\n
Run Code Online (Sandbox Code Playgroud)\n解析脚本,基于https://www.python.org/dev/peps/pep-0564/#script:
\nimport math\nimport time\nfrom typing import Final\n\nLOOPS = 10 ** 6\n\nINITIAL_TIMESTAMP: Final[float] = time.time()\nINITIAL_TIMESTAMP_PERF_COUNTER: Final[float] = time.perf_counter()\n\ndef get_timestamp_float() -> float:\n dt_sec = time.perf_counter() - INITIAL_TIMESTAMP_PERF_COUNTER\n return INITIAL_TIMESTAMP + dt_sec\n\nmin_dt = [abs(time.time() - time.time())\n for _ in range(LOOPS)]\nmin_dt = min(filter(bool, min_dt))\nprint("min time() delta: %s ns" % math.ceil(min_dt * 1e9))\n\nmin_dt = [abs(get_timestamp_float() - get_timestamp_float())\n for _ in range(LOOPS)]\nmin_dt = min(filter(bool, min_dt))\nprint("min get_timestamp_float() delta: %s ns" % math.ceil(min_dt * 1e9))\n
Run Code Online (Sandbox Code Playgroud)\n
归档时间: |
|
查看次数: |
1238 次 |
最近记录: |