How can I format a datetime object as a string with milliseconds?
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' 9With 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' 2Using 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' 2Use [:-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' 1import 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 0I 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 2In 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:
11.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:]
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.