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

3

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] '2020-05-04 10:18:32.926' 
9

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

Using strftime:

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

@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' 
2

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' 
1
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 
0

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

In python 3.6 and above using python f-strings:

from datetime import datetime i = datetime.utcnow() print(f"""{i:%Y-%m-%d %H:%M:%S}.{"{:03d}".format(i.microsecond // 1000)}""") 

The code specific to format milliseconds is:

{"{:03d}".format(i.microsecond // 1000)} 

The format string {:03d} and microsecond to millisecond conversion // 1000 is from def _format_time in that is used for datetime.datetime.isoformat().

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:]

1

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'), ) print(ms) 14:44:37.134 

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.

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).

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.

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy