How can I format a datetime
object as a string with milliseconds?

- 24,552
- 19
- 101
- 135

- 8,595
- 19
- 64
- 88
-
1http://stackoverflow.com/questions/311627/how-to-print-date-in-a-regular-format-in-python – cetver Sep 28 '11 at 19:31
-
4Please write a title that describes your problem and try to keep your question clear and to the point. – agf Sep 28 '11 at 19:34
-
2It's worth mentioning here that extra precision is often just fine. For example, Java's `Instant.parse` can parse represenation created with `strftime('%Y-%m-%dT%H:%M:%S.%fZ')` – Jarek Przygódzki Mar 08 '17 at 09:03
15 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 slightly shorter:
>>> from datetime import datetime
>>> datetime.utcnow().strftime('%F %T.%f')[:-3]

- 13,864
- 7
- 39
- 43
-
9Note, if you want to use `import datetime` instead of `from datetime import datetime`, you'll have to use this: `datetime.datetime.utcnow().strftime("%H:%M:%S.%f")` – Luc Sep 16 '15 at 11:01
-
24In case microseconds are 0, in windows 2.7 implementation microseconds are not printed out so it trims seconds :( – cabbi Nov 09 '15 at 15:37
-
1@cabbi, you could use this instead: `(dt, micro) = datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S.%f').split('.') ; dt = "%s.%03d" % (dt, int(micro) / 1000) ; print dt`. I added this as an answer. – Sam Watkins Feb 26 '16 at 04:41
-
18
-
`(dt, micro) = datetime.datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S.%f').split('.') ; dt = "%s.%03d" % (dt, round(int(micro) / 1000.0)) ; print dt` – Jiří Polcar Nov 15 '17 at 12:39
-
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 – Chris Nov 21 '17 at 01:11
-
5@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. – Technophile Jul 01 '21 at 21:59
-
1I like this solution most, because it tries to use the same format string for parsing and representing the dates. Nevertheless, I am not able to use the %z format specifier at the end for the timezone. I think there should be another format specifier for the miliseconds... for example %F. – yucer Sep 29 '21 at 15:18
-
@gens the [datetime.isoformat(sep='T', timespec='auto')](https://docs.python.org/3/library/datetime.html#datetime.datetime.isoformat) which is suggested in [next answer](https://stackoverflow.com/a/56074397/2932052) does the same: truncation. Maybe this helps locating timestamps via text search? – Wolf Dec 08 '21 at 19:07
-
-
Where is the `%F %T` documented? I can't find it in the Python's page for `datetime`. Is it deprecated? It works even in Python 3.10, though. I do see it in pages on POSIX datetime format codes. – m01010011 Mar 10 '23 at 05:27
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'

- 24,552
- 19
- 101
- 135

- 1,571
- 1
- 7
- 3
-
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' – Ena May 10 '19 at 09: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: https://github.com/python/cpython/blob/99c72326d245fb604609a87a51ef1ad0845467b7/Lib/datetime.py#L174 – Wolf Dec 08 '21 at 19:00
-
As per Wikipedia (https://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). – Jimson James Dec 04 '22 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'

- 24,552
- 19
- 101
- 135

- 7,819
- 3
- 38
- 38
-
10What I'am actually doing is this: print '%s.%03d'%(dt.strftime("%Y-%m-%d %H:%M:%S"), int(dt.microsecond/1000)) – cabbi Mar 08 '16 at 08:35
-
3agree with @cabbi, there's no need to convert back and forth with string and int – caoanan May 21 '18 at 03:15
Using strftime
:
>>> from datetime import datetime
>>> datetime.utcnow().strftime('%Y%m%d%H%M%S%f')
'20220402055654344968'

- 24,552
- 19
- 101
- 135

- 6,817
- 31
- 42
-
21FYI, 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. – Mark Lakata Jan 02 '14 at 21:40
-
9microseconds can be less than 6 digits, so [:-3] is printing out wrong milliseconds – cabbi Nov 09 '15 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'

- 24,552
- 19
- 101
- 135

- 129
- 1
- 7
-
2As 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". – Technophile Jul 01 '21 at 22:06
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

- 1,441
- 2
- 20
- 25
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().

- 10,163
- 3
- 47
- 55

- 61
- 2
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

- 2,991
- 16
- 14
-
@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** – eyquem Sep 28 '11 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? – Austin Marshall Sep 28 '11 at 22:10
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]

- 11
- 1
python -c "from datetime import datetime; print str(datetime.now())[:-3]"
2017-02-09 10:06:37.006

- 1,557
- 14
- 12
datetime
t = datetime.datetime.now()
ms = '%s.%i' % (t.strftime('%H:%M:%S'), t.microsecond/1000)
print(ms)
14:44:37.134

- 589
- 10
- 11
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).

- 165
- 1
- 12
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:]

- 26,771
- 7
- 38
- 46
-
1Nice! That is indeed cleaner without sacrificing performance. str.translate() actually faster in my testing. – Austin Marshall Sep 28 '11 at 21:47
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.

- 593
- 4
- 11
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.

- 24,552
- 19
- 101
- 135