The isoformat() method of Python's datetime class converts a date or time object into a string formatted according to the ISO 8601 standard (YYYY-MM-DDTHH:MM:SS.ssssss). By default, it uses the character T as a separator between the date and time, but this can be customized using the sep argument, and the time precision can be controlled via the timespec argument.
Key Parameters and Behavior
sep: Specifies the separator character between the date and time fields. The default is'T', but any single character (e.g.,' ','#') is valid; providing a string with two or more characters raises aTypeError.timespec: Controls the precision of the time component in the output. The default value is'auto', which includes microseconds only if they are non-zero. Other options include:'hours': Returns time inHHformat.'minutes': Returns time inHH:MMformat.'seconds': Returns time inHH:MM:SSformat.'milliseconds': Returns time inHH:MM:SS.mmmformat (truncating microseconds to milliseconds).'microseconds': Returns time inHH:MM:SS.mmmmmmformat.
Timezone Handling
The method automatically includes the UTC offset in the output if the datetime object is timezone-aware (i.e., it has a tzinfo attribute). If the object is naive (no timezone information), the offset is omitted from the string.
Converting Strings Back to Objects
To parse an ISO 8601 formatted string back into a datetime object, use the fromisoformat() class method. This method was added in Python 3.7 and supports the basic ISO 8601 format starting from Python 3.11, which notably includes support for the "Z" suffix (indicating UTC).
Example Usage
from datetime import datetime, timezone
# Create a naive datetime object
dt_naive = datetime(2023, 4, 1, 5, 0, 30, 1000)
print(dt_naive.isoformat())
# Output: 2023-04-01T05:00:30.001000
# Create a timezone-aware datetime object
dt_aware = datetime(2023, 4, 1, 5, 0, 30, 1000, tzinfo=timezone.utc)
print(dt_aware.isoformat())
# Output: 2023-04-01T05:00:30.001000+00:00
# Custom separator and precision
print(dt_aware.isoformat(sep=' ', timespec='minutes'))
# Output: 2023-04-01 05:00+00:00
# Parse an ISO string back to datetime
parsed_dt = datetime.fromisoformat("2023-04-01T05:00:30.001000")
print(parsed_dt)
# Output: 2023-04-01 05:00:30.001000To get the current time in UTC in Python 3.2+:
>>> from datetime import datetime, timezone
>>> datetime.now(timezone.utc).isoformat()
'2015-01-27T05:57:31.399861+00:00'
To get local time in Python 3.3+:
>>> from datetime import datetime, timezone
>>> datetime.now(timezone.utc).astimezone().isoformat()
'2015-01-27T06:59:17.125448+01:00'
Explanation: datetime.now(timezone.utc) produces a timezone aware datetime object in UTC time. astimezone() then changes the timezone of the datetime object, to the system's locale timezone if called with no arguments. Timezone aware datetime objects then produce the correct ISO format automatically.
python - How to get current isoformat datetime string including the default timezone? - Stack Overflow
How to convert Python's .isoformat() string back into datetime object - Stack Overflow
datetime - ISO time (ISO 8601) in Python - Stack Overflow
Add ISO Basic format support to datetime.isoformat() and date.isoformat()
Videos
In Python 3.10 and earlier, datetime.fromisoformat only supported formats outputted by datetime.isoformat. This meant that many valid ISO 8601 strings could not be parsed, including the very common "Z" suffix (e.g. 2000-01-01T00:00:00Z).
I discovered today that 3.11 supports most ISO 8601 formats. I'm thrilled: I'll no longer have to use a third-party library to ingest ISO 8601 and RFC 3339 datetimes. This was one of my biggest gripes with Python's stdlib.
It's not 100% standards compliant, but I think the exceptions are pretty reasonable:
-
Time zone offsets may have fractional seconds.
-
The T separator may be replaced by any single unicode character.
-
Ordinal dates are not currently supported.
-
Fractional hours and minutes are not supported.
https://docs.python.org/3/library/datetime.html#datetime.datetime.fromisoformat
To get the current time in UTC in Python 3.2+:
>>> from datetime import datetime, timezone
>>> datetime.now(timezone.utc).isoformat()
'2015-01-27T05:57:31.399861+00:00'
To get local time in Python 3.3+:
>>> from datetime import datetime, timezone
>>> datetime.now(timezone.utc).astimezone().isoformat()
'2015-01-27T06:59:17.125448+01:00'
Explanation: datetime.now(timezone.utc) produces a timezone aware datetime object in UTC time. astimezone() then changes the timezone of the datetime object, to the system's locale timezone if called with no arguments. Timezone aware datetime objects then produce the correct ISO format automatically.
You need to make your datetime objects timezone aware. from the datetime docs:
There are two kinds of date and time objects: “naive” and “aware”. This distinction refers to whether the object has any notion of time zone, daylight saving time, or other kind of algorithmic or political time adjustment. Whether a naive datetime object represents Coordinated Universal Time (UTC), local time, or time in some other timezone is purely up to the program, just like it’s up to the program whether a particular number represents metres, miles, or mass. Naive datetime objects are easy to understand and to work with, at the cost of ignoring some aspects of reality.
When you have an aware datetime object, you can use isoformat() and get the output you need.
To make your datetime objects aware, you'll need to subclass tzinfo, like the second example in here, or simpler - use a package that does it for you, like pytz or python-dateutil
Using pytz, this would look like:
import datetime, pytz
datetime.datetime.now(timezone.utc).isoformat()
You can also control the output format, if you use strftime with the '%z' format directive like
datetime.datetime.now(timezone.utc).strftime('%Y-%m-%dT%H:%M:%S.%f%z')
Python 3.7+
As of Python 3.7 there is a method datetime.fromisoformat() which is exactly the reverse for isoformat().
Older Python
If you have older Python, then this is the current best "solution" to this question:
pip install python-dateutil
Then...
import datetime
import dateutil
def getDateTimeFromISO8601String(s):
d = dateutil.parser.parse(s)
return d
Try this:
>>> def gt(dt_str):
... dt, _, us = dt_str.partition(".")
... dt = datetime.datetime.strptime(dt, "%Y-%m-%dT%H:%M:%S")
... us = int(us.rstrip("Z"), 10)
... return dt + datetime.timedelta(microseconds=us)
Usage:
>>> gt("2008-08-12T12:20:30.656234Z")
datetime.datetime(2008, 8, 12, 12, 20, 30, 656234)
Local to ISO 8601:
import datetime
datetime.datetime.now().isoformat()
>>> '2024-08-01T14:38:32.499588'
UTC to ISO 8601:
import datetime
datetime.datetime.now(datetime.timezone.utc).isoformat()
>>> '2024-08-01T04:38:47.731215+00:00'
Local to ISO 8601 without microsecond:
import datetime
datetime.datetime.now().replace(microsecond=0).isoformat()
>>> '2024-08-01T14:38:57'
UTC to ISO 8601 with timezone information (Python 3):
import datetime
datetime.datetime.now(datetime.timezone.utc).isoformat()
>>> '2024-08-01T04:39:06.274874+00:00'
Local to ISO 8601 with timezone information (Python 3):
import datetime
datetime.datetime.now().astimezone().isoformat()
>>> '2024-08-01T14:39:16.698776+10:00'
Local to ISO 8601 with local timezone information without microsecond (Python 3):
import datetime
datetime.datetime.now().astimezone().replace(microsecond=0).isoformat()
>>> '2024-08-01T14:39:28+10:00'
Notice there is a bug when using astimezone() on utcnow(). This gives an incorrect result:
datetime.datetime.utcnow().astimezone().isoformat() #Incorrect result, do not use.
.utcnow() is deprecated, use .now(datetime.timezome.utc) instead.
For Python 2, see and use pytz.
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.now(datetime.UTC).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.now(datetime.UTC).strftime("%Y%m%dT%H%M%SZ")
'20180905T140903Z'
For local time:
>>> datetime.datetime.now(datetime.timezone(datetime.timedelta(hours=-5))).strftime("%Y-%m-%dT%H:%M:%S%:z")
'2018-09-05T14:09:03-05:00'
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(datetime.UTC).strftime("%Y-%m-%dT%H:%M:%SZ")
'2018-09-05T14:09:03Z'