将日期时间格式化为带毫秒的字符串

359

如何将datetime对象格式化为带有毫秒的字符串?


1
https://dev59.com/JHVC5IYBdhLWcg3wYQEp - cetver
4
请写一个标题来描述您的问题,并尽量保持问题清晰明了。 - agf
2
值得在这里提到的是,额外的精度通常是可以接受的。例如,Java的Instant.parse可以解析使用strftime('%Y-%m-%dT%H:%M:%S.%fZ')创建的表示形式。 - Jarek Przygódzki
16个回答

639
要获取带有毫秒的日期字符串,使用[:-3]来截取%f(微秒)的最后三位数字。
>>> from datetime import datetime
>>> datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3]
'2022-09-24 10:18:32.926'

或者更短一点:
>>> from datetime import datetime
>>> datetime.utcnow().strftime('%F %T.%f')[:-3]
'2022-09-24 10:18:32.926'

查看Python文档以获取更多关于"%"格式代码的信息,以及strftime(3) man页面以获取完整列表。

9
请注意,如果您想使用import datetime代替from datetime import datetime,您需要使用以下代码:datetime.datetime.utcnow().strftime("%H:%M:%S.%f") - Luc
24
如果微秒为0,在Windows 2.7实现中将不会打印出微秒部分,因此会缩短秒数的输出 :( - cabbi
19
请注意,此处截断时间精度到毫秒,而非四舍五入。 - gens
3
正如gens所提到的,如果第一个数字大于等于5,这个方法难道不会出错吗?实际上,如果微秒部分大于999500,那么通过调整微秒部分是永远无法正确得到时间的。 - Chris
7
对于时间,截断比四舍五入更为合适。例如,07:59:59.999 应该被截断为 07:59:59 或 07:59,而不是四舍五入为 08:00:00 或 08:00,正如 07:59:59 应该被截断为 07:59 而不是四舍五入为 08:00。 - Technophile
显示剩余7条评论

159

使用Python 3.6+,你可以设置isoformattimespec

>>> from datetime import datetime
>>> datetime.utcnow().isoformat(sep=' ', timespec='milliseconds')
'2019-05-10 09:08:53.155'

2
适用于时区: date = datetime(2019,5,10) date_with_tz = pytz.timezone('Europe/Rome').localize(date) date_with_tz.isoformat(sep='T', timespec='milliseconds') 输出:'2019-05-10T00:00:00.000+02:00' - Ena
1
这看起来比接受的答案中的[:-3]更干净,但你应该知道它似乎做了相同的事情。>>> datetime.fromisoformat('2021-12-08 20:00:00.678900').isoformat(sep=' ', timespec='milliseconds')导致'2021-12-08 20:00:00.678'。截断是否在ISO标准中指定还是只是一个错误?实现使用整数除法:https://github.com/python/cpython/blob/99c72326d245fb604609a87a51ef1ad0845467b7/Lib/datetime.py#L174 - Wolf
根据维基百科(https://en.wikipedia.org/wiki/ISO_8601#cite_note-37),“在ISO 8601中不允许使用其他字符(如空格)分隔日期和时间部分,但在其配置文件RFC 3339中允许使用”,因此最好添加类似于“T”作为分隔符,并且“如果时间是UTC,则直接在时间后面添加Z而不带空格”(摘自维基百科)。 - Jimson James

35

@Cabbi raised the issue,在某些系统上(使用 Python 2.7 的 Windows 系统),毫秒格式代码 %f 可能会错误地显示为"0",所以仅仅简单地截取后三位是不可移植的。这些系统没有遵循文档中指定的行为规范:

指令 意义 例子
%f 微妙,小数点后六位。 000000、000001、……、999999

下面的代码可以仔细地将时间戳格式化为带有毫秒的字符串:

>>> from datetime import datetime
>>> (dt, micro) = datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S.%f').split('.')
>>> "%s.%03d" % (dt, int(micro) / 1000)
'2016-02-26 04:37:53.133'

为了得到OP想要的确切输出结果,我们需要去除标点符号:

>>> from datetime import datetime
>>> (dt, micro) = datetime.utcnow().strftime('%Y%m%d%H%M%S.%f').split('.')
>>> "%s%03d" % (dt, int(micro) / 1000)
'20160226043839901'

10
我实际上正在做的是这样:打印 '%s.%03d' % (dt.strftime("%Y-%m-%d %H:%M:%S"), int(dt.microsecond/1000))。其中,我会格式化日期时间并将微秒转换为毫秒。 - cabbi
3
赞同 @cabbi 的观点,没必要在字符串和整数之间来回转换。 - caoanan

31

使用strftime函数:

>>> from datetime import datetime
>>> datetime.utcnow().strftime('%Y%m%d%H%M%S%f')
'20220402055654344968'

21
此代码会将微秒打印为最后6位数字。在结尾处添加[:-3],以删除最后3个数字,从而仅显示毫秒。 - Mark Lakata
9
微秒可能少于6位数字,因此[:-3]会打印出错误的毫秒数。 - cabbi
15
如果我们有时区,会怎样? - ᐅdevrimbaris
1
@ᐅdevrimbaris 请查看Lorenzo的时区检查答案。 - Ena

11

使用[:-3]来删除最后的三个字符,因为%f用于微秒:

>>> from datetime import datetime
>>> datetime.now().strftime('%Y/%m/%d %H:%M:%S.%f')[:-3]
'2013/12/04 16:50:03.141'

2
如其他答案所述,如果微秒为0,则“.123455”部分可能被打印为“.0”,导致截断最后3个字符以吃掉低秒位和“.0”。 - Technophile

6
import datetime

# convert string into date time format.

str_date = '2016-10-06 15:14:54.322989'
d_date = datetime.datetime.strptime(str_date , '%Y-%m-%d %H:%M:%S.%f')
print(d_date)
print(type(d_date)) # check d_date type.


# convert date time to regular format.

reg_format_date = d_date.strftime("%d %B %Y %I:%M:%S %p")
print(reg_format_date)

# some other date formats.
reg_format_date = d_date.strftime("%Y-%m-%d %I:%M:%S %p")
print(reg_format_date)
reg_format_date = d_date.strftime("%Y-%m-%d %H:%M:%S")
print(reg_format_date)

<<<<<< OUTPUT >>>>>>>

2016-10-06 15:14:54.322989    
<class 'datetime.datetime'>    
06 October 2016 03:14:54 PM    
2016-10-06 03:14:54 PM    
2016-10-06 15:14:54

4

2

我猜你的意思是你想要比datetime.datetime.strftime()更快的东西,并且基本上是从utc时间戳中剥离非字母字符。

你的方法略微更快,我认为你可以通过切片字符串来进一步加速:

>>> import timeit
>>> t=timeit.Timer('datetime.utcnow().strftime("%Y%m%d%H%M%S%f")','''
... from datetime import datetime''')
>>> t.timeit(number=10000000)
116.15451288223267

>>> def replaceutc(s):
...     return s\
...         .replace('-','') \
...         .replace(':','') \
...         .replace('.','') \
...         .replace(' ','') \
...         .strip()
... 
>>> t=timeit.Timer('replaceutc(str(datetime.datetime.utcnow()))','''
... from __main__ import replaceutc
... import datetime''')
>>> t.timeit(number=10000000)
77.96774983406067

>>> def sliceutc(s):
...     return s[:4] + s[5:7] + s[8:10] + s[11:13] + s[14:16] + s[17:19] + s[20:]
... 
>>> t=timeit.Timer('sliceutc(str(datetime.utcnow()))','''
... from __main__ import sliceutc
... from datetime import datetime''')
>>> t.timeit(number=10000000)
62.378515005111694

@oxtopus 做得好。就个人而言,我不再使用 timeit 来简单测量时间了。很奇怪的是,你的代码中时间比率是不同的:1 - 0.67 - 0.53,而我的是:1 - 0.35 - 0.20,对于方法 strftime - replace - slicing - eyquem
也许与在测试的每次迭代中调用str(datetime.datetime.utcnow())有关,而不是仅设置一次有关? - Austin Marshall

1
from datetime import datetime
from time import clock

t = datetime.utcnow()
print 't == %s    %s\n\n' % (t,type(t))

n = 100000

te = clock()
for i in xrange(1):
    t_stripped = t.strftime('%Y%m%d%H%M%S%f')
print clock()-te
print t_stripped," t.strftime('%Y%m%d%H%M%S%f')"

print

te = clock()
for i in xrange(1):
    t_stripped = str(t).replace('-','').replace(':','').replace('.','').replace(' ','')
print clock()-te
print t_stripped," str(t).replace('-','').replace(':','').replace('.','').replace(' ','')"

print

te = clock()
for i in xrange(n):
    t_stripped = str(t).translate(None,' -:.')
print clock()-te
print t_stripped," str(t).translate(None,' -:.')"

print

te = clock()
for i in xrange(n):
    s = str(t)
    t_stripped = s[:4] + s[5:7] + s[8:10] + s[11:13] + s[14:16] + s[17:19] + s[20:] 
print clock()-te
print t_stripped," s[:4] + s[5:7] + s[8:10] + s[11:13] + s[14:16] + s[17:19] + s[20:] "

结果

t == 2011-09-28 21:31:45.562000    <type 'datetime.datetime'>


3.33410112179
20110928212155046000  t.strftime('%Y%m%d%H%M%S%f')

1.17067364707
20110928212130453000 str(t).replace('-','').replace(':','').replace('.','').replace(' ','')

0.658806915404
20110928212130453000 str(t).translate(None,' -:.')

0.645189262881
20110928212130453000 s[:4] + s[5:7] + s[8:10] + s[11:13] + s[14:16] + s[17:19] + s[20:]

同时使用translate()slicing方法
translate()的优点是可以在一行中使用

基于第一个时间进行比较:

1.000 * t.strftime('%Y%m%d%H%M%S%f')

0.351 * str(t).replace('-','').replace(':','').replace('.','').replace(' ','')

0.198 * str(t).translate(None,' -:.')

0.194 * s[:4] + s[5:7] + s[8:10] + s[11:13] + s[14:16] + s[17:19] + s[20:]


1
不错!确实更加简洁,而且没有牺牲性能。在我的测试中,str.translate() 的速度要更快一些。 - Austin Marshall

1

如果你准备将时间存储在一个变量中并进行一些字符串操作,那么实际上可以不使用datetime模块来完成这个任务。

>>> _now = time.time()
>>> print ("Time : %s.%s\n" % (time.strftime('%x %X',time.localtime(_now)),
... str('%.3f'%_now).split('.')[1])) # Rounds to nearest millisecond
Time : 05/02/21 01:16:58.676

>>> 

%.3f 会四舍五入到最近的毫秒,如果您想要更多或更少的精度,只需更改小数位数即可

>>> print ("Time : %s.%s\n" % (time.strftime('%x %X',time.localtime(_now)),
... str('%.1f'%_now).split('.')[1])) # Rounds to nearest tenth of a second
Time : 05/02/21 01:16:58.7

>>>

在Python 2.7和3.7中进行了测试(显然,在2.x版本中调用print时需要省略括号)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接