Here's a (AFAICT) correct solution for rounding if someone is particular about that. The problem with string-based solutions is rounding ends up being a huge pain because what if your date is (2015, 02, 28, 23, 59, 59, 999900)?
def round_microseconds(date, digits_to_show):
fraction = date.microsecond / 1000000.0
rounded = round(fraction, digits_to_show)
if rounded < 1:
# format the number to have the required amount of decimal digits,
# this is important in case the rounded number is 0
hundredths = '{:.{prec}f}'.format(rounded, prec=digits_to_show)
hundredths = hundredths[2:] # trim off "0."
else:
# round up by adding a second to the datetime
date = date + datetime.timedelta(seconds=1)
hundredths = '0' * digits_to_show
return date.strftime("%Y%m%dT%H%M%S") + hundredths
Test results:
print round_microseconds(datetime.datetime(2015, 02, 28, 23, 59, 59, 999900), 3)
print round_microseconds(datetime.datetime(2015, 02, 28, 23, 59, 59, 999999), 6)
print round_microseconds(datetime.datetime(2015, 02, 28, 23, 59, 59, 5600), 2)
print round_microseconds(datetime.datetime(2015, 02, 28, 23, 59, 59, 5600), 3)
print round_microseconds(datetime.datetime(2015, 02, 28, 23, 59, 59, 5600), 4)
print round_microseconds(datetime.datetime(2015, 02, 28, 23, 59, 59, 5), 3)
print round_microseconds(datetime.datetime(2015, 02, 28, 23, 59, 59, 5), 5)
print round_microseconds(datetime.datetime(2015, 02, 28, 23, 59, 59, 5), 6)
20150301T000000000
20150228T235959999999
20150228T23595901
20150228T235959006
20150228T2359590056
20150228T235959000
20150228T23595900001
20150228T235959000005
Older, simpler solution but with a bug: it will fail when microseconds is 995000 or higher, so 0.5% of the time:
now = datetime.datetime.utcnow()
hundredths = str(round(now.microsecond, -4))[:2]
return now.strftime("%Y%m%dT%H%M%S") + hundredths
How it works:
- say
now
is datetime.datetime(2015, 2, 20, 19, 32, 48, 875912)
now.microsecond
is 875912
round(now.microsecond, -4)
is 880000.0. Use -4 because microsecond is in millionths so it has 6 digits, to get result to 2 digits you need to round off last 4 digits.
str(round(now.microsecond, -4))[:2]
to get only the first two digits of that number-as-a-string, so '88'. Note that 2 is 6-4, so the initial number of digits minus the digits you've rounded off.
- Then concatenate it with standard formatting of
now.strftime("%Y%m%dT%H%M%S")
This can be made a bit more general like so:
digits_to_show = 3
now = datetime.datetime.utcnow()
subsecond = str(round(now.microsecond, digits_to_show - 6))[:digits_to_show]
return now.strftime("%Y%m%dT%H%M%S") + subsecond