shiva
shiva

Reputation: 2699

Can't parse microseconds correctly with strptime()

I have a string 19:04:01:94891.

When I pass this to datetime.datetime.strptime() as:

datetime.strptime('19:04:01:94891', "%H:%M:%S:%f")

I get the following result:

datetime.datetime(1900, 1, 1, 19, 4, 1, 948910)

However I expect the result to be:

datetime.datetime(1900, 1, 1, 19, 4, 1, 94891)

The difference is in microseconds.

How can I get the expected result without modifying the string as I am reading the string from a file?

Upvotes: 4

Views: 4265

Answers (2)

Eugene Yarmash
Eugene Yarmash

Reputation: 149736

From the documentation on strptime():

When used with the strptime() method, the %f directive accepts from one to six digits and zero pads on the right.

If your string always contains a 5-digit microseconds number, you could truncate the resulting number after parsing the string:

>>> from datetime import datetime
>>> dt = datetime.strptime('19:04:01:94891', '%H:%M:%S:%f')
>>> dt.replace(microsecond=dt.microsecond//10)
datetime.datetime(1900, 1, 1, 19, 4, 1, 94891)

A more robust solution would be to zero-pad the number of microseconds on the left in the input string. Since you already have an example for Python 2, here's one using Python 3's extended unpacking:

>>> *rest, ms = '19:04:01:94891'.split(':')
>>> date_string = ':'.join(rest + [ms.zfill(6)])
>>> date_string
'19:04:01:094891'
>>> datetime.strptime(date_string, '%H:%M:%S:%f')
datetime.datetime(1900, 1, 1, 19, 4, 1, 94891)

Upvotes: 2

Will
Will

Reputation: 24699

The problem is that your input isn't zero-padded, so the problem would be even worse if we were at, say, 11 microseconds. Let's fix the problem at it's source, and clean up the input first:

def fixMicroseconds(timestamp):
   parts = timestamp.split(':')

   return ':'.join(
       parts[:-1] + ['{:06d}'.format(int(parts[-1]))]
   )

Now it will be zero-padded to 6 digits as Python prefers.

Here's an example of this working:

In [1]: def fixMicroseconds(timestamp):
   ....:     parts = timestamp.split(':')
   ....:
   ....:     return ':'.join(
   ....:         parts[:-1] + ['{:06d}'.format(int(parts[-1]))]
   ....:     )
   ....:

In [2]: fixMicroseconds('19:04:01:94891')
Out[2]: '19:04:01:094891'

In [3]: fixMicroseconds('19:04:01:13')
Out[3]: '19:04:01:000013'

In [4]: datetime.datetime.strptime(fixMicroseconds('19:04:01:94891'), "%H:%M:%S:%f")
Out[4]: datetime.datetime(1900, 1, 1, 19, 4, 1, 94891)

You really need to clean up the input before the call to strptime(), because that's what strptime() expects (6 digits).

Upvotes: 3

Related Questions