8

Hey I am working in python with datetime and I am wondering what the best way to parse this timestamp is.

The timestamps are ISO standard, here is an example "2010-06-19T08:17:14.078685237Z"

Now so far I have used

time = datetime.datetime.strptime(timestamp.split(".")[0], "%Y-%m-%dT%H:%M:%S") precisetime = time + datetime.timedelta(0,float("." + timestamp[:-1].split(".")[0])) 

This kind of works, but I feel like there should be a more streamlined way (I am very new to python, and I am sure I am doing this like an ass). Also, I have nanoseconds in my timestamp, but only microseconds in my datetime object, is there a better module to work with? I need to be able to do operations on the time such as subtracting times and putting them in the scheduler.

Any better way to go about this?

2
  • 1
    Sorry for the improductive comment, but "I am very new to python, and I am sure I am doing this like an ass" -> you, sir, made me laugh out loud. We've all been there. Commented Jun 1, 2011 at 20:43
  • I still write 'ass code' Commented Jun 1, 2011 at 20:47

5 Answers 5

8

You can use Numpy's datetime64: http://docs.scipy.org/doc/numpy-dev/reference/arrays.datetime.html

It supports nanoseconds and higher precisions.

>>> import numpy as np >>> np.version.version '1.7.1' >>> np.datetime64("2010-06-19T08:17:14.078685237Z", dtype="datetime64[ns]") numpy.datetime64('2010-06-19T08:17:14.078685237+0000') 
Sign up to request clarification or add additional context in comments.

2 Comments

Seems to be raising DeprecationWarning now.
From the documentation "Deprecated since version 1.11.0: NumPy does not store timezone information." And from the source code "It will be quite a while before we can remove this, because, at the very least, a lot of existing code uses the 'Z' modifier ..." But you should just drop the Z and use np.datetime64("2010-06-19T08:17:14.078685237")
6

datetime is only precise to microseconds. I.e. 10e-6.

So

14.078685237 

will get truncated to

14.078685 

if you do what you did above.

It's better to just hold the sub-seconds separately in a float, and do some floating point modulus operations to keep track of this.

I find it ridiculous that datetime doesn't do this.

And for the people that say clocks aren’t accurate enough. That isn't the only use case. When your converting back and forth from distance to time. (Multiplying by the speed of light.) 1 micro second is 300m. 300 meters is the length of 3 football fields. Which is total crap for accuracy.

Comments

2

There's nothing inherently ass-like with your approach, but you may like to try pyiso8601 or dateutil

1 Comment

both pyiso8601 and dateutil return datetime objects that have only microsecond precision. OP needs nanosecond precision such as provided by numpy.datetime64
1

Your code looks fine. I don't know a better way, but I'm not a datetime expert. Personally, I would wrap it in a function and do a little less work per line, but that's just my style:

def parse_iso_timestamp(timestamp) ts, partial_seconds = timestamp[:-1].split('.') partial_seconds = float("." + partial_seconds) time = datetime.datetime.strptime(ts, "%Y-%m-%dT%H:%M:%S") precisedatetime = time + datetime.timedelta(seconds=partial_seconds) return precisedatetime 

edit: I agree with Rob Cowie's answer. No need to reinvent the wheel.

1 Comment

An aside: It's become the fashion in Python to do as much work as possible in one line. I'm not sure I like it. I prefer smaller chunks documented with variable names.
0

Here is an alternative approach using a regular expression that you may (or may not) find cleaner:

import re timestamp = "2010-06-19T08:17:14.078685237Z" ts_regex = re.compile(r"(\d{4})-(\d{1,2})-(\d{1,2})T(\d{2}):(\d{2}):(\d{2})\.(\d{6})") precisetime = datetime.datetime(*map(int, ts_regex.match(timestamp).groups())) 

Here it is broken into a few more steps to provide some clarity:

>>> ts_regex.match(timestamp).groups() ('2010', '06', '19', '08', '17', '14', '078685') >>> map(int, ts_regex.match(timestamp).groups()) [2010, 6, 19, 8, 17, 14, 78685] 

We can pass this list directly into the initialization of a datetime object using argument expansion with *, since the arguments are in the correct order.

2 Comments

No need to be that fancy with your regex. This will give you what you need: re.findall('\d+', timestamp). And with that you could get it down to the one liner: precisetime = datetime.datetime(*map(int, re.findall('\d+', timestamp)), which is shorter than the line it replaced. ;)
The one liner will actually not work in this case since it will match 9 characters after the decimal point and try to put that into microseconds. You could definitely save some code by using a variation on Steven's method if you are sure you are dealing with a valid timestamp.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.