33

I am trying to add two times together. The ISO 8601 time stamp is '1984-06-02T19:05:00.000Z', and I would like to convert it to seconds. I tried using the Python module iso8601, but it is only a parser.

Any suggestions?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Zaynaib Giwa
  • 5,366
  • 7
  • 21
  • 26

3 Answers3

37

If you want to get the seconds since epoch, you can use python-dateutil to convert it to a datetime object and then convert it so seconds using the strftime method. Like so:

>>> import dateutil.parser as dp
>>> t = '1984-06-02T19:05:00.000Z'
>>> parsed_t = dp.parse(t)
>>> t_in_seconds = parsed_t.timestamp()
>>> t_in_seconds
'455051100'

So you were halfway there :)

Pavneet Singh
  • 342
  • 1
  • 2
  • 10
chunpoon
  • 950
  • 10
  • 17
  • Thanks feynman21. I'm looking at the dateutil.parser documentation. What if I want to convert it back to an ISO format. – Zaynaib Giwa Dec 02 '14 at 10:35
  • 1
    check [this](https://docs.python.org/2/library/datetime.html) out. `datetime.isoformat()` should have what you are looking for. So you should first convert the string back to a `datetime` object using `strptime` and then call `isoformat` on that object. – chunpoon Dec 02 '14 at 11:08
  • http://stackoverflow.com/questions/3401428/how-to-get-an-isoformat-datetime-string-including-the-default-timezone Thank you so much for your help. – Zaynaib Giwa Dec 02 '14 at 11:30
  • 2
    `parsed_t.strftime('%s')` is wrong. `parsed_t.tzinfo == tzutc()` but [`.strftime('%s')` always uses the local timezone even if it is available](http://bugs.python.org/issue12750) (it may and does differ in your case from utc). The correct answer is `455051100`, not `455047500` (check `datetime.utcfromtimestamp(455051100)`). – jfs Feb 09 '17 at 22:10
  • Such a simple, elegant solution! – Blairg23 Feb 28 '17 at 18:09
  • Adding to @jfs comment: watch out if you're not using UTC timezone in the ISO, since `strftime('%s')` might bite you painfully: ```>>> parser.parse('2018-01-10T16:23:47-08:00').strftime('%s') '1515630227' >>> parser.parse('2018-01-10T16:23:47-00:00').strftime('%s') '1515630227'``` – Kieleth Jan 11 '18 at 19:32
  • 3
    For Python 3.3 and onward, you can use `parsed_t.timestamp()` to get the correct time. – user1609012 Sep 06 '18 at 20:02
  • What if you'd like the seconds as an integer instead of a string (without an additional conversion.) Is there a way instead of strftime? – k-den Apr 29 '20 at 20:11
  • 1
    @user1609012: beware, if `parsed_t` is not time zone aware then `timestamp()` may produce incorrect result: it interprets naive datetime as local time that may differ from the desired time zone such as UTC. – jfs Nov 04 '20 at 05:18
  • The above solution does not actually check the Z value to convert to GMT. If you paste the above ```t_in_seconds``` returned in the results to an epoch converter it returns ```Saturday, 2 June 1984 18:05:00``` in GMT. so it's either not timezone aware or does not consider daylight savings. – Pavneet Singh Dec 20 '20 at 02:41
28

Your date is UTC time in RFC 3339 format, you could parse it using only stdlib:

from datetime import datetime

utc_dt = datetime.strptime('1984-06-02T19:05:00.000Z', '%Y-%m-%dT%H:%M:%S.%fZ')

# Convert UTC datetime to seconds since the Epoch
timestamp = (utc_dt - datetime(1970, 1, 1)).total_seconds()
# -> 455051100.0

See also Converting datetime.date to UTC timestamp in Python

How do I convert it back to ISO 8601 format?

To convert POSIX timestamp back, create a UTC datetime object from it, and format it using .strftime() method:

from datetime import datetime, timedelta

utc_dt = datetime(1970, 1, 1) + timedelta(seconds=timestamp)
print(utc_dt.strftime('%Y-%m-%dT%H:%M:%S.%fZ'))
# -> 1984-06-02T19:05:00.000000Z

Note: It prints six digits after the decimal point (microseconds). To get three digits, see Formatting microseconds to 2 decimal places (in fact converting microseconds into tens of microseconds).

Community
  • 1
  • 1
jfs
  • 399,953
  • 195
  • 994
  • 1,670
  • Do you by any chance know how to convert it back to ISO 8601 format? So far anotherTime = datetime.datetime.fromtimestamp(timestamp).isoformat() but it does format .000Z. Any suggestions? I tried multiple things but all I got were errors – Zaynaib Giwa Dec 02 '14 at 15:16
  • @user3426338: I've updated the answer to show how to convert the timestamp (number) back to ISO 8601 format string. – jfs Dec 03 '14 at 07:47
  • 1
    This only parses `Z` suffix, doesn't deal with `±hh:mm` timezones. `%f` annoyingly refuses to parse more than 6 fractional digits (rare but legal in both ISO 8601 and RFC 3339) e.g. as printed by `date --iso-8601=ns`. – Beni Cherniavsky-Paskin Sep 22 '16 at 16:44
  • @BeniCherniavsky-Paskin yes, it is correct (moreover [%z in Python 3 understands only `hhmm` utc offset—no colon `:`](http://stackoverflow.com/q/1101508/4279)). There is [no way to parse even rfc 3339 (a profile of rfc 8601) using only stdlib](http://bugs.python.org/issue15873) (see [the question I've linked above](http://stackoverflow.com/questions/27245488/converting-iso-8601-date-time-to-seconds-in-python#comment42977722_27245488)). Though sometimes, parsing Z is all you need as in the example in the question. – jfs Sep 22 '16 at 17:12
0

Here is a solution in Python 3:

$ date +%s
1428030452
$ TZ=US/Pacific date -d @1428030452 '+%Y%m%d %H:%M:%S %z'
20150402 20:07:32 -0700
$ TZ=US/Eastern date -d @1428030452 '+%Y%m%d %H:%M:%S %z'
20150402 23:07:32 -0400
$ python3
>>> from datetime import datetime,timezone
>>> def iso2epoch(ts):
...     return int(datetime.strptime(ts[:-6],"%Y%m%d %H:%M:%S").replace(tzinfo=timezone.utc).timestamp()) - (int(ts[-2:])*60 + 60 * 60 * int(ts[-4:-2]) * int(ts[-5:-4]+'1'))
...
>>> iso2epoch("20150402 20:07:32 -0700")
1428030452
>>> iso2epoch("20150402 23:07:32 -0400")
1428030452
>>>
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
toppk
  • 696
  • 4
  • 10
  • 1
    Impressively short pure stdlib TZ-aware parsing! Alas, it's not ISO 8601 format (see example in question or run `date --iso-8601=ns`). The ISO standard allows *tons* of formats so strptime is hopeless, but parsing just `±hh:mm`, `Z` timezone formats (the RFC3339 subset) would be good enough in many cases. – Beni Cherniavsky-Paskin Sep 22 '16 at 16:38
  • Seems overly complicated --> `(int(ts[-2:])*60 + 60 * 60 * int(ts[-4:-2]) * int(ts[-5:-4]+'1')` – Ian Smith Jan 19 '22 at 17:49