目前我正在记录东西,我正在使用我自己的格式化程序和自定义formatTime()
:
def formatTime(self, _record, _datefmt):
t = datetime.datetime.now()
return t.strftime('%Y-%m-%d %H:%M:%S.%f')
我的问题是微秒%f
是六位数。反正有没有吐出更少的数字,比如微秒的前三位?
最简单的方法是使用切片来切掉微秒的最后三位数字:
def format_time():
t = datetime.datetime.now()
s = t.strftime('%Y-%m-%d %H:%M:%S.%f')
return s[:-3]
我强烈建议只切碎。我曾经写过一些记录代码,它对时间戳进行舍入而不是截断,当舍入更改最后一位时,我发现它实际上有点令人困惑。有定时代码在某个时间戳停止运行,但由于四舍五入,存在具有该时间戳的日志事件。切碎更简单,更可预测。
如果你想实际地对数字进行四舍五入而不是仅仅切碎,那就需要做更多的工作,但并不可怕:
def format_time():
t = datetime.datetime.now()
s = t.strftime('%Y-%m-%d %H:%M:%S.%f')
head = s[:-7] # everything up to the '.'
tail = s[-7:] # the '.' and the 6 digits after it
f = float(tail)
temp = "{:.03f}".format(f) # for Python 2.x: temp = "%.3f" % f
new_tail = temp[1:] # temp[0] is always '0'; get rid of it
return head + new_tail
显然,您可以用更少的变量来简化上述内容;我只是想让它很容易理解。
从 Python 3.6 开始,该语言内置了以下功能:
def format_time():
t = datetime.datetime.now()
s = t.isoformat(timespec='milliseconds')
return s
此方法应始终返回与此完全相同的时间戳(有或没有时区,取决于输入dt
对象是否包含时区):
2016-08-05T18:18:54.776+0000
它需要一个datetime
对象作为输入(您可以使用 生成datetime.datetime.now()
)。要获得像我的示例输出中那样的时区,您需要import pytz
并通过datetime.datetime.now(pytz.utc)
.
import pytz, datetime
time_format(datetime.datetime.now(pytz.utc))
def time_format(dt):
return "%s:%.3f%s" % (
dt.strftime('%Y-%m-%dT%H:%M'),
float("%.3f" % (dt.second + dt.microsecond / 1e6)),
dt.strftime('%z')
)
我注意到,如果有一个(例如0.870
become 0.87
),上面的一些其他方法会省略尾随零,这导致我将这些时间戳输入的解析器出现问题。这种方法没有这个问题。
一个适用于所有情况的简单解决方案:
def format_time():
t = datetime.datetime.now()
if t.microsecond % 1000 >= 500: # check if there will be rounding up
t = t + datetime.timedelta(milliseconds=1) # manually round up
return t.strftime('%Y-%m-%d %H:%M:%S.%f')[:-3]
基本上,您首先对日期对象本身进行手动舍入,然后您可以安全地修剪微秒。
编辑:正如一些人在下面的评论中指出的那样,当微秒值达到 999500 时,此解决方案(以及上述解决方案)的四舍五入会带来问题,因为 999.5 会四舍五入为 1000(溢出)。
如果没有重新实现 strftime 以支持我们想要的格式(由舍入引起的潜在溢出需要传播到几秒,然后是几分钟等),只截断到前 3 位数字要简单得多,如接受的答案,或使用类似的东西:
'{:03}'.format(int(999999/1000))
-- 原始答案保留在下面 --
就我而言,我试图用毫秒格式化为“ddd”的日期戳。我最终用来获得毫秒的解决方案是使用对象的microsecond
属性datetime
,将其除以 1000.0,必要时用零填充,然后用格式对其进行舍入。它看起来像这样:
'{:03.0f}'.format(datetime.now().microsecond / 1000.0)
# Produces: '033', '499', etc.
您可以从微秒中减去当前日期时间。
d = datetime.datetime.now()
current_time = d - datetime.timedelta(microseconds=d.microsecond)
这将2021-05-14 16:11:21.916229
变成2021-05-14 16:11:21
此方法允许灵活的精度,如果您指定的精度过高,则会消耗整个微秒值。
def formatTime(self, _record, _datefmt, precision=3):
dt = datetime.datetime.now()
us = str(dt.microsecond)
f = us[:precision] if len(us) > precision else us
return "%d-%d-%d %d:%d:%d.%d" % (dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, int(f))
此方法实现舍入到小数点后 3 位:
import datetime
from decimal import *
def formatTime(self, _record, _datefmt, precision='0.001'):
dt = datetime.datetime.now()
seconds = float("%d.%d" % (dt.second, dt.microsecond))
return "%d-%d-%d %d:%d:%s" % (dt.year, dt.month, dt.day, dt.hour, dt.minute,
float(Decimal(seconds).quantize(Decimal(precision), rounding=ROUND_HALF_UP)))
strftime
我故意避免使用该方法,因为我不希望在不重新验证的情况下修改完全序列化的日期时间对象。这种方式还可以显示日期内部,以防您想进一步修改它。
在舍入示例中,请注意Decimal
模块的精度是基于字符串的。
这是我使用正则表达式的解决方案:
import re
# Capture 6 digits after dot in a group.
regexp = re.compile(r'\.(\d{6})')
def to_splunk_iso(dt):
"""Converts the datetime object to Splunk isoformat string."""
# 6-digits string.
microseconds = regexp.search(dt.isoformat()).group(1)
return regexp.sub('.%d' % round(float(microseconds) / 1000), dt.isoformat())
根据Pablojim修复建议的解决方案评论:
from datetime import datetime
dt = datetime.now()
dt_round_microsec = round(dt.microsecond/1000) #number of zeroes to round
dt = dt.replace(microsecond=dt_round_microsec)
如果曾经想获得星期几(即'星期日)'以及结果,那么切片'[:-3]'将不起作用。到时候你可以一起去,
dt = datetime.datetime.now()
print("{}.{:03d} {}".format(dt.strftime('%Y-%m-%d %I:%M:%S'), dt.microsecond//1000, dt.strftime("%A")))
#Output: '2019-05-05 03:11:22.211 Sunday'
%H - 24 小时制
%I - 12 小时制
谢谢,
在这里添加我的两美分,因为这种方法将允许您编写微秒格式,就像您使用 c 样式的浮点数一样。他们都使用%f
.
import datetime
import re
def format_datetime(date, format):
"""Format a ``datetime`` object with microsecond precision.
Pass your microsecond as you would format a c-string float.
e.g "%.3f"
Args:
date (datetime.datetime): You input ``datetime`` obj.
format (str): Your strftime format string.
Returns:
str: Your formatted datetime string.
"""
# We need to check if formatted_str contains "%.xf" (x = a number)
float_format = r"(%\.\d+f)"
has_float_format = re.search(float_format, format)
if has_float_format:
# make microseconds be decimal place. Might be a better way to do this
microseconds = date.microsecond
while int(microseconds): # quit once it's 0
microseconds /= 10
ms_str = has_float_format.group(1) % microseconds
format = re.sub(float_format, ms_str[2:], format)
return date.strftime(format)
print(datetime.datetime.now(), "%H:%M:%S.%.3f")
# '17:58:54.424'