ISO time (ISO 8601) in Python

PythonDatetimeIso8601

Python Problem Overview


I have a file. In Python, I would like to take its creation time, and convert it to an ISO time (ISO 8601) string while preserving the fact that it was created in the Eastern Time Zone (ET).

How do I take the file's ctime and convert it to an ISO time string that indicates the Eastern Time Zone (and takes into account daylight savings time, if necessary)?

Python Solutions


Solution 1 - Python

Local to ISO 8601:

import datetime
datetime.datetime.now().isoformat()
>>> 2020-03-20T14:28:23.382748

UTC to ISO 8601:

import datetime
datetime.datetime.utcnow().isoformat()
>>> 2020-03-20T01:30:08.180856

Local to ISO 8601 without microsecond:

import datetime
datetime.datetime.now().replace(microsecond=0).isoformat()
>>> 2020-03-20T14:30:43

UTC to ISO 8601 with TimeZone information (Python 3):

import datetime
datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat()
>>> 2020-03-20T01:31:12.467113+00:00

UTC to ISO 8601 with Local TimeZone information without microsecond (Python 3):

import datetime
datetime.datetime.now().astimezone().replace(microsecond=0).isoformat()
>>> 2020-03-20T14:31:43+13:00

Local to ISO 8601 with TimeZone information (Python 3):

import datetime
datetime.datetime.now().astimezone().isoformat()
>>> 2020-03-20T14:32:16.458361+13:00

Notice there is a bug when using astimezone() on utc time. This gives an incorrect result:

datetime.datetime.utcnow().astimezone().isoformat() #Incorrect result

For Python 2, see and use [pytz][1].

[1]: https://pypi.python.org/pypi/pytz/ "pytz"

Solution 2 - Python

Here is what I use to convert to the XSD datetime format:

from datetime import datetime
datetime.now().replace(microsecond=0).isoformat()
# You get your ISO string

I came across this question when looking for the XSD date time format (xs:dateTime). I needed to remove the microseconds from isoformat.

Solution 3 - Python

ISO 8601 allows a compact representation with no separators except for the T, so I like to use this one-liner to get a quick timestamp string:

>>> datetime.datetime.utcnow().strftime("%Y%m%dT%H%M%S.%fZ")
'20180905T140903.591680Z'

If you don't need the microseconds, just leave out the .%f part:

>>> datetime.datetime.utcnow().strftime("%Y%m%dT%H%M%SZ")
'20180905T140903Z'

For local time:

>>> datetime.datetime.now().strftime("%Y%m%dT%H%M%S")
'20180905T140903'

In general, I recommend you leave the punctuation in. RFC 3339 recommends that style because if everyone uses punctuation, there isn't a risk of things like multiple ISO 8601 strings being sorted in groups on their punctuation. So the one liner for a compliant string would be:

>>> datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%SZ")
'2018-09-05T14:09:03Z'

Solution 4 - Python

ISO 8601 Time Representation

The international standard ISO 8601 describes a string representation for dates and times. Two simple examples of this format are

2010-12-16 17:22:15
20101216T172215

(which both stand for the 16th of December 2010), but the format also allows for sub-second resolution times and to specify time zones. This format is of course not Python-specific, but it is good for storing dates and times in a portable format. Details about this format can be found in the Markus Kuhn entry.

I recommend use of this format to store times in files.

One way to get the current time in this representation is to use strftime from the time module in the Python standard library:

>>> from time import strftime
>>> strftime("%Y-%m-%d %H:%M:%S")
'2010-03-03 21:16:45'

You can use the strptime constructor of the datetime class:

>>> from datetime import datetime
>>> datetime.strptime("2010-06-04 21:08:12", "%Y-%m-%d %H:%M:%S")
datetime.datetime(2010, 6, 4, 21, 8, 12)

The most robust is the Egenix mxDateTime module:

>>> from mx.DateTime.ISO import ParseDateTimeUTC
>>> from datetime import datetime
>>> x = ParseDateTimeUTC("2010-06-04 21:08:12")
>>> datetime.fromtimestamp(x)
datetime.datetime(2010, 3, 6, 21, 8, 12)

References

Solution 5 - Python

I found the datetime.isoformat in the documentation. It seems to do what you want:

datetime.isoformat([sep])

Return a string representing the date and time in ISO 8601 format, YYYY-MM-DDTHH:MM:SS.mmmmmm or, if microsecond is 0, YYYY-MM-DDTHH:MM:SS

If utcoffset() does not return None, a 6-character string is appended, giving the UTC offset in (signed) hours and minutes: YYYY-MM-DDTHH:MM:SS.mmmmmm+HH:MM or, if microsecond is 0 YYYY-MM-DDTHH:MM:SS+HH:MM

The optional argument sep (default 'T') is a one-character separator, placed between the date and time portions of the result. For example,
>>>

>>> from datetime import tzinfo, timedelta, datetime
>>> class TZ(tzinfo):
...     def utcoffset(self, dt): return timedelta(minutes=-399)
...
>>> datetime(2002, 12, 25, tzinfo=TZ()).isoformat(' ')
'2002-12-25 00:00:00-06:39'

Solution 6 - Python

For those who are looking for a date-only solution, it is:

import datetime

datetime.date.today().isoformat()

Solution 7 - Python

The ISO 8601 time format does not store a time zone name, only the corresponding UTC offset is preserved.

To convert a file ctime to an ISO 8601 time string while preserving the UTC offset in Python 3:

>>> import os
>>> from datetime import datetime, timezone
>>> ts = os.path.getctime(some_file)
>>> dt = datetime.fromtimestamp(ts, timezone.utc)
>>> dt.astimezone().isoformat()
'2015-11-27T00:29:06.839600-05:00'

The code assumes that your local timezone is Eastern Time Zone (ET) and that your system provides a correct UTC offset for the given POSIX timestamp (ts), i.e., Python has access to a historical timezone database on your system or the time zone had the same rules at a given date.

If you need a portable solution; use the pytz module that provides access to the tz database:

>>> import os
>>> from datetime import datetime
>>> import pytz  # pip install pytz
>>> ts = os.path.getctime(some_file)
>>> dt = datetime.fromtimestamp(ts, pytz.timezone('America/New_York'))
>>> dt.isoformat()
'2015-11-27T00:29:06.839600-05:00'

The result is the same in this case.

If you need the time zone name/abbreviation/zone id, store it separately.

>>> dt.astimezone().strftime('%Y-%m-%d %H:%M:%S%z (%Z)')
'2015-11-27 00:29:06-0500 (EST)'

Note: no, : in the UTC offset and EST timezone abbreviation is not part of the ISO 8601 time format. It is not unique.

Different libraries/different versions of the same library may use different time zone rules for the same date/timezone. If it is a future date then the rules might be unknown yet. In other words, the same UTC time may correspond to a different local time depending on what rules you use -- saving a time in ISO 8601 format preserves UTC time and the local time that corresponds to the current time zone rules in use on your platform. You might need to recalculate the local time on a different platform if it has different rules.

Solution 8 - Python

You'll need to use os.stat to get the file creation time and a combination of time.strftime and time.timezone for formatting:

>>> import time
>>> import os
>>> t = os.stat('C:/Path/To/File.txt').st_ctime
>>> t = time.localtime(t)
>>> formatted = time.strftime('%Y-%m-%d %H:%M:%S', t)
>>> tz = str.format('{0:+06.2f}', float(time.timezone) / 3600)
>>> final = formatted + tz
>>> 
>>> final
'2008-11-24 14:46:08-02.00'

Solution 9 - Python

Correct me if I'm wrong (I'm not), but the offset from UTC changes with daylight saving time. So you should use

tz = str.format('{0:+06.2f}', float(time.altzone) / 3600)

I also believe that the sign should be different:

tz = str.format('{0:+06.2f}', -float(time.altzone) / 3600)

I could be wrong, but I don't think so.

Solution 10 - Python

Standard RFC-3339 in milliseconds

I needed the time in this format for a LoRa application so I came up with this, I hope it helps:

from datetime import datetime
from time import strftime


# Get the current time in the format: 2021-03-20T16:51:23.644+01:00
def rfc3339_time_ms():
        datetime_now = datetime.utcnow()
        # Remove the microseconds
        datetime_now_ms = datetime_now.strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3]
        # Add the timezone as "+/-HHMM", and the colon in "+/-HH:MM"
        datetime_now_ms_tz = datetime_now_ms + strftime("%z")
        rfc3339_ms_now = datetime_now_ms_tz[:-2] + ":" + datetime_now_ms_tz[-2:]
        # print(f"Current time in ms in RFC-3339 format: {rfc3339_ms_now}")
        return rfc3339_ms_now

Solution 11 - Python

Adding a small variation to estani's excellent answer

Local to ISO 8601 with TimeZone and no microsecond info (Python 3):

import datetime, time

utc_offset_sec = time.altzone if time.localtime().tm_isdst else time.timezone
utc_offset = datetime.timedelta(seconds=-utc_offset_sec)
datetime.datetime.now().replace(microsecond=0, tzinfo=datetime.timezone(offset=utc_offset)).isoformat()

Sample Output:

'2019-11-06T12:12:06-08:00'

Tested that this output can be parsed by both Javascript Date and C# DateTime/DateTimeOffset

Solution 12 - Python

Just make the life simple please:

  1. Use UTC time
  2. Microsecond
  3. one line code

f"{datetime.datetime.utcnow().isoformat()[:-3]}Z"

output:

2022-02-25T02:08:40.684Z

Solution 13 - Python

I agree with Jarek, and I furthermore note that the ISO offset separator character is a colon, so I think the final answer should be:

isodate.datetime_isoformat(datetime.datetime.now()) + str.format('{0:+06.2f}', -float(time.timezone) / 3600).replace('.', ':')

Solution 14 - Python

I've developed this function:

def iso_8601_format(dt):
    """YYYY-MM-DDThh:mm:ssTZD (1997-07-16T19:20:30-03:00)"""

    if dt is None:
        return ""

    fmt_datetime = dt.strftime('%Y-%m-%dT%H:%M:%S')
    tz = dt.utcoffset()
    if tz is None:
        fmt_timezone = "+00:00"
    else:
        fmt_timezone = str.format('{0:+06.2f}', float(tz.total_seconds() / 3600))

    return fmt_datetime + fmt_timezone

Solution 15 - Python

import datetime, time    
def convert_enddate_to_seconds(self, ts):
    """Takes ISO 8601 format(string) and converts into epoch time."""
     dt = datetime.datetime.strptime(ts[:-7],'%Y-%m-%dT%H:%M:%S.%f')+\
                datetime.timedelta(hours=int(ts[-5:-3]),
                minutes=int(ts[-2:]))*int(ts[-6:-5]+'1')
    seconds = time.mktime(dt.timetuple()) + dt.microsecond/1000000.0
    return seconds 

>>> import datetime, time
>>> ts = '2012-09-30T15:31:50.262-08:00'
>>> dt = datetime.datetime.strptime(ts[:-7],'%Y-%m-%dT%H:%M:%S.%f')+ datetime.timedelta(hours=int(ts[-5:-3]), minutes=int(ts[-2:]))*int(ts[-6:-5]+'1')
>>> seconds = time.mktime(dt.timetuple()) + dt.microsecond/1000000.0
>>> seconds
1348990310.26

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJoseph TurianView Question on Stackoverflow
Solution 1 - PythonestaniView Answer on Stackoverflow
Solution 2 - PythonradtekView Answer on Stackoverflow
Solution 3 - PythonJim HunzikerView Answer on Stackoverflow
Solution 4 - PythonVoislav SaucaView Answer on Stackoverflow
Solution 5 - Pythonuser2120810View Answer on Stackoverflow
Solution 6 - PythonAlexander ZinchukView Answer on Stackoverflow
Solution 7 - PythonjfsView Answer on Stackoverflow
Solution 8 - PythonMax ShawabkehView Answer on Stackoverflow
Solution 9 - PythonJarek PrzygódzkiView Answer on Stackoverflow
Solution 10 - PythonchronoclastView Answer on Stackoverflow
Solution 11 - PythonSharpiroView Answer on Stackoverflow
Solution 12 - PythonJohn_JView Answer on Stackoverflow
Solution 13 - PythonmattbornskiView Answer on Stackoverflow
Solution 14 - PythonAndre AvillaView Answer on Stackoverflow
Solution 15 - PythonronakView Answer on Stackoverflow