How can I format a datetime
object as a string with milliseconds?
17 Answers
To get a date string with milliseconds, use [:-3]
to trim the last three digits of %f
(microseconds):
>>> from datetime import datetime
>>> datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3]
'2022-09-24 10:18:32.926'
Or shorter:
>>> from datetime import datetime
>>> datetime.utcnow().strftime('%F %T.%f')[:-3]
'2022-09-24 10:18:32.926'
See the Python docs for more "%
" format codes and the strftime(3)
man page for the full list.
-
9Note, if you want to use
import datetime
instead offrom datetime import datetime
, you'll have to use this:datetime.datetime.utcnow().strftime("%H:%M:%S.%f")
– LucCommented Sep 16, 2015 at 11:01 -
25In case microseconds are 0, in windows 2.7 implementation microseconds are not printed out so it trims seconds :(– cabbiCommented Nov 9, 2015 at 15:37
-
20
-
3As gens mentions, won't this get it wrong it the first drops number is >=5?. In fact if the usec part is > 999500, then you will never get the time right by fiddling with microseconds part– ChrisCommented Nov 21, 2017 at 1:11
-
8@gens for time, truncation is preferred to rounding. E.g. 07:59:59.999 should be truncated to 07:59:59 or 07:59 instead of rounding to 08:00:00 or 08:00, just as 07:59:59 should be truncated to 07:59 instead of rounding to 08:00. Commented Jul 1, 2021 at 21:59
With Python 3.6+, you can set isoformat
's timespec
:
>>> from datetime import datetime
>>> datetime.utcnow().isoformat(sep=' ', timespec='milliseconds')
'2019-05-10 09:08:53.155'
-
2Useful with timezone too: date = datetime(2019,5,10) date_with_tz = pytz.timezone('Europe/Rome').localize(date) date_with_tz.isoformat(sep='T', timespec='milliseconds') output: '2019-05-10T00:00:00.000+02:00'– EnaCommented May 10, 2019 at 9:17
-
1This looks cleaner than the
[:-3]
in the accepted answer, but you should know that it seemingly does the same>>> datetime.fromisoformat('2021-12-08 20:00:00.678900').isoformat(sep=' ', timespec='milliseconds')
leads to'2021-12-08 20:00:00.678'
. Is the truncation specified in ISO standard or is it just a bug? The implementation uses integer division: github.com/python/cpython/blob/…– WolfCommented Dec 8, 2021 at 19:00 -
As per Wikipedia (en.wikipedia.org/wiki/ISO_8601#cite_note-37), "Separating date and time parts with other characters such as space is not allowed in ISO 8601, but allowed in its profile RFC 3339", so its a good idea to add something like 'T' as separator, and "If the time is in UTC, add a Z directly after the time without a space" (excerpt from Wikipedia). Commented Dec 4, 2022 at 15:46
@Cabbi raised the issue that on some systems (Windows with Python 2.7), the microseconds format %f
may incorrectly give "0"
, so it's not portable to simply trim the last three characters. Such systems do not follow the behavior specified by the documentation:
Directive | Meaning | Example |
---|---|---|
%f | Microsecond as a decimal number, zero-padded to 6 digits. | 000000, 000001, …, 999999 |
The following code carefully formats a timestamp with milliseconds:
>>> 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'
To get the exact output that the OP wanted, we have to strip punctuation characters:
>>> from datetime import datetime
>>> (dt, micro) = datetime.utcnow().strftime('%Y%m%d%H%M%S.%f').split('.')
>>> "%s%03d" % (dt, int(micro) / 1000)
'20160226043839901'
Using strftime
:
>>> from datetime import datetime
>>> datetime.utcnow().strftime('%Y%m%d%H%M%S%f')
'20220402055654344968'
-
23FYI, this prints microseconds as the last 6 digits. Add
[:-3]
to the end to drop the last 3 digits so that it is only displaying milliseconds. Commented Jan 2, 2014 at 21:40 -
9microseconds can be less than 6 digits, so [:-3] is printing out wrong milliseconds– cabbiCommented Nov 9, 2015 at 15:26
-
15
-
1
Use [:-3]
to remove the 3 last characters since %f
is for microseconds:
>>> from datetime import datetime
>>> datetime.now().strftime('%Y/%m/%d %H:%M:%S.%f')[:-3]
'2013/12/04 16:50:03.141'
-
3As mentioned in other answers, if microseconds are 0 then the ".123455" portion may be printed as ".0", causing truncation of the last 3 chars to eat the low seconds digit and ".0". Commented Jul 1, 2021 at 22:06
In python 3.6 and above using python f-strings:
from datetime import datetime, timezone
dt = datetime.now(timezone.utc)
print(f"{dt:%Y-%m-%d %H:%M:%S}.{dt.microsecond // 1000:03d}")
The code specific to format milliseconds is:
{dt.microsecond // 1000:03d}
The format string {:03d}
and microsecond to millisecond conversion // 1000
is from def _format_time
in https://github.com/python/cpython/blob/master/Lib/datetime.py that is used for datetime.datetime.isoformat().
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
I assume you mean you're looking for something that is faster than datetime.datetime.strftime(), and are essentially stripping the non-alpha characters from a utc timestamp.
You're approach is marginally faster, and I think you can speed things up even more by slicing the string:
>>> 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 Good work. Personally, I don't use timeit anymore for simple measuring of time. It's strange that the ratios of times are different with your code: 1 - 0.67 - 0.53 and with mine: 1 - 0.35 - 0.20 , for the methods strftime - replace - slicing– eyquemCommented Sep 28, 2011 at 21:47
-
Maybe something to do with the str(datetime.datetime.utcnow()) being called in each iteration of the test vs setting it once? Commented Sep 28, 2011 at 22:10
In Python 3.11 (maybe older version support it too) it can be done with isoformat(timespec='milliseconds')
From datetime.py
:
The optional argument timespec specifies the number of additional terms of the time to include. Valid options are 'auto', 'hours', 'minutes', 'seconds', 'milliseconds' and 'microseconds'.
>>> datetime.now().isoformat(timespec='milliseconds')
'2023-12-01T10:34:18.657'
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:] "
result
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:]
Use of translate() and slicing method run in same time
translate() presents the advantage to be usable in one line
Comparing the times on the basis of the first one:
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:]
-
1Nice! That is indeed cleaner without sacrificing performance. str.translate() actually faster in my testing. Commented Sep 28, 2011 at 21:47
I dealt with the same problem but in my case it was important that the millisecond was rounded and not truncated
from datetime import datetime, timedelta
def strftime_ms(datetime_obj):
y,m,d,H,M,S = datetime_obj.timetuple()[:6]
ms = timedelta(microseconds = round(datetime_obj.microsecond/1000.0)*1000)
ms_date = datetime(y,m,d,H,M,S) + ms
return ms_date.strftime('%Y-%m-%d %H:%M:%S.%f')[:-3]
python -c "from datetime import datetime; print str(datetime.now())[:-3]"
2017-02-09 10:06:37.006
datetime
t = datetime.datetime.now()
ms = '%s.%i' % (t.strftime('%H:%M:%S'), t.microsecond/1000)
print(ms)
14:44:37.134
If you are prepared to store the time in a variable and do a little string manipulation, then you can actually do this without using the datetime module.
>>> _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 will round to out put the nearest millisecond, if you want more or less precision just change the number of decimal places
>>> 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
>>>
Tested in Python 2.7 and 3.7 (obviously you need to leave out the brackets when calling print in version 2.x).
The problem with datetime.utcnow()
and other such solutions is that they are slow.
More efficient solution may look like this one:
def _timestamp(prec=0):
t = time.time()
s = time.strftime("%H:%M:%S", time.localtime(t))
if prec > 0:
s += ("%.9f" % (t % 1,))[1:2+prec]
return s
Where prec
would be 3
in your case (milliseconds).
The function works up to 9 decimal places (please note number 9
in the 2nd formatting string).
If you'd like to round the fractional part, I'd suggest building "%.9f"
dynamically with desired number of decimal places.
Field-width format specification
The UNIX date
command allows specifying %3
to reduce the precision to 3 digits:
$ date '+%Y-%m-%d %H:%M:%S.%3N'
2022-01-01 00:01:23.456
Here's a custom function that can do that in Python:
from datetime import datetime
def strftime_(fmt: str, dt: datetime) -> str:
tokens = fmt.split("%")
tokens[1:] = [_format_token(dt, x) for x in tokens[1:]]
return "".join(tokens)
def _format_token(dt: datetime, token: str) -> str:
if len(token) == 0:
return ""
if token[0].isnumeric():
width = int(token[0])
s = dt.strftime(f"%{token[1]}")[:width]
return f"{s}{token[2:]}"
return dt.strftime(f"%{token}")
Example usage:
>>> strftime_("%Y-%m-%d %H:%M:%S.%3f", datetime.now())
'2022-01-01 00:01:23.456'
NOTE: %%
is not supported.
It depends on how whether you want to truncate or round microseconds:
example time:
tm = time(10,11,12,microsecond=95900)
truncating - as others have mentioned above:
print(f'{tm:%H:%M:%S.%f}'[:-3])
10:11:12.095
rounding - AFAIK there is no format specifier in Python to do this so you have to round the microseconds then format:
print(f'{tm:%H:%M:%S}.{tm.microsecond/1000:03.0f}')
10:11:12.096
Instant.parse
can parse represenation created withstrftime('%Y-%m-%dT%H:%M:%S.%fZ')