ISO 8601 is the internationally accepted way to represent dates and times. This ISO standard helps remove doubts that can result from the various day-date conventions, cultures and time zones that impact a global operation.
Fortunately, Python offers several methods for working with the ISO 8601 format more efficiently. In this tutorial, we’ll explore how to format dates and times into ISO 8601 strings using Python. In addition, we will discuss how to convert ISO 8601 strings back into datetime
objects and go over some important things to keep in mind when dealing with time zones.
But first, let’s understand what the ISO 8601 format is.
Understanding ISO 8601 Format
Different cultures around the world have their own conventions for formatting dates. For example, the United States typically uses the month-day-year format (01-05-2024), while many European countries use the day-month-year format (05-01-2024). These variations can lead to miscommunication, especially in international contexts.
For example, 01-05-24 could mean January 5, 2024, or May 1, 2024. For an individual, this kind of uncertainty can be very frustrating, but for a business, it can be very expensive. Organizing meetings and deliveries, writing contracts and buying airplane tickets can be very difficult when the date is unclear.
To address this, the International Organization for Standardization (ISO) created the ISO 8601 standard. This standard establishes a clear and unambiguous date and time format, with components arranged from most significant to least:
YYYY-MM-DDTHH:MM:SS.mmmmmm[Z|+HH:MM|-HH:MM]
Where,
- YYYY: Year (4 digits)
- MM: Month (01-12)
- DD: Day (01-31)
- T: Separator between date and time
- HH: Hour (00-23)
- MM: Minute (00-59)
- SS: Second (00-59)
- mmmmmm: Microseconds (optional, up to 6 digits)
- […]: Indicates optional time zone components:
- Z: UTC time zone
- +HH:MM: Positive offset from UTC
- -HH:MM: Negative offset from UTC
For example, September 27, 2024, at 6 PM in New York is represented as 2024-09-27T18:00:00-05:00 in ISO 8601 format.
Formatting Dates and Times to ISO 8601
Python simplifies the process of formatting dates and times into ISO 8601 strings through the use of the isoformat() method available in the datetime module.
Getting the Current Time in ISO 8601 format
If you want the current date and time in ISO 8601 format, you first need to obtain the current datetime object using the now()
method. Then, call the isoformat()
method on this object to format it.
from datetime import datetime
# Get the current date and time
dt = datetime.now()
# Format the datetime object into an ISO 8601 string
iso_formatted_dt = dt.isoformat()
print(iso_formatted_dt)
# Output: 2024-03-07T13:32:52.335546
Converting Specific Date and Time to ISO 8601 Format
To get the ISO 8601 format representation of a specific date and time, you can instantiate a datetime
object by specifying the year, month, day, hour, minute, second, and microsecond. And then use the isoformat()
method.
from datetime import datetime
# Example datetime with microseconds
dt = datetime(2023, 4, 5, 12, 30, 45, 123456)
# Format the datetime object into an ISO 8601 string
iso_formatted_dt = dt.isoformat()
print(iso_formatted_dt)
# Output: 2023-04-05T12:30:45.123456
Specifying a separator
The isoformat()
method allows you to customize the output of an ISO 8601 string using two parameters: sep
and timespec
. Let’s focus on the sep
parameter first.
The sep
parameter lets you choose the character that separates the date and time components within the ISO 8601 formatted string. The default is the letter ‘T’, but you can change this to any other character that fits your needs.
from datetime import datetime
# Example datetime
dt = datetime(2023, 4, 5, 12, 30, 45)
print(dt.isoformat()) # Output: 2023-04-05T12:30:45 (Default )
print(dt.isoformat(sep=' ')) # Output: 2023-04-05 12:30:45
print(dt.isoformat(sep='_')) # Output: 2023-04-05_12:30:45
Specifying timespec for different precisions
The timespec
parameter specifies the number of additional components of the time to include. By adjusting this parameter, you can customize whether the output includes only hours, hours and minutes, seconds, or even milliseconds and microseconds.
The timespec
parameter accepts the following values:
auto
(default): Same as ‘seconds’ if microsecond is 0, same as ‘microseconds’ otherwise.hours
: Include the hour in the two-digit HH format.minutes
: Include hour and minute in HH:MM format.seconds
: Include hour, minute, and second in HH:MM:SS format.milliseconds
: Include full time, but truncate fractional second part to milliseconds. HH:MM:SS.sss format.microseconds
: Include full time in HH:MM:SS.ffffff format.
from datetime import datetime
# Example datetime with microseconds
dt = datetime(2023, 4, 5, 12, 30, 45, 123456)
# Default (auto) behavior includes microseconds if present
print(dt.isoformat()) # 2023-04-05T12:30:45.123456
# Specifying different levels of precision
print(dt.isoformat(timespec='hours')) # Output: 2023-04-05T12
print(dt.isoformat(timespec='minutes')) # Output: 2023-04-05T12:30
print(dt.isoformat(timespec='seconds')) # Output: 2023-04-05T12:30:45
print(dt.isoformat(timespec='milliseconds')) # Output: 2023-04-05T12:30:45.123
print(dt.isoformat(timespec='microseconds')) # Output: 2023-04-05T12:30:45.123456
Parsing ISO 8601 Strings
To parse an ISO 8601 formatted string back into a Python datetime object, use the fromisoformat() method. Here are some examples demonstrating how to use fromisoformat()
:
from datetime import datetime
# Parse a simple date
date_only = datetime.fromisoformat('2023-04-01')
print(date_only)
# Output: 2023-04-01 00:00:00
# Parse a datetime with microseconds
datetime_no_tz = datetime.fromisoformat('2023-04-01T12:34:56.789012')
print(datetime_no_tz)
# Output: 2023-04-01 12:34:56.789012
# Parse a datetime with timezone info
datetime_with_tz = datetime.fromisoformat('2023-04-01T12:34:56.789012-05:00')
print(datetime_with_tz)
# Output: 2023-04-01 12:34:56.789012-05:00
Prior to Python 3.11, the fromisoformat()
method had more limited capabilities in the types of ISO 8601 formats it could understand. It primarily supported only the formats that could be generated by the isoformat()
method.
However, this has been expanded. Now, the fromisoformat()
method support a variety of ISO 8601 formats. Let’s illustrate this with some examples:
from datetime import datetime
# Parse a simple date
dt = datetime.fromisoformat('2024-11-04')
print(dt)
# Output: 2024-11-04 00:00:00
# Parse a simple date without delimeters
dt = datetime.fromisoformat('20241104')
print(dt)
# Output: 2024-11-04 00:00:00
# Parse a datetime with hours, minutes, and seconds
dt = datetime.fromisoformat('2024-11-04T00:05:23')
print(dt)
# Output: 2024-11-04 00:05:23
# Parse a datetime with UTC timezone (Z)
dt = datetime.fromisoformat('2024-11-04T00:05:23Z')
print(dt)
# Output: 2024-11-04 00:05:23+00:00
# Parse a datetime without delimeters
dt = datetime.fromisoformat('20241104T000523')
print(dt)
# Output: 2024-11-04 00:05:23
# Parse a datetime with week number
dt = datetime.fromisoformat('2024-W01-2T00:05:23.283')
print(dt)
# Output: 2024-01-02 00:05:23.283000
# Parse a datetime with microseconds
dt = datetime.fromisoformat('2024-11-04 00:05:23.283')
print(dt)
# Output: 2024-11-04 00:05:23.283000
# Parse a datetime with microseconds and UTC timezone
dt = datetime.fromisoformat('2024-11-04 00:05:23.283+00:00')
print(dt)
# Output: 2024-11-04 00:05:23.283000+00:00
# Parse a datetime with timezone offset
dt = datetime.fromisoformat('2024-11-04T00:05:23+04:00')
print(dt)
# Output: 2024-11-04 00:05:23+04:00
Handling Time Zones
The ISO 8601 standard provides a clear way for representing time zone information by either using UTC (Coordinated Universal Time) or by specifying an offset from UTC.
A ‘Z’ appended to the end of an ISO 8601 string (e.g., 2024-03-07T12:35:00Z) directly indicates UTC, whereas appending +HH:MM or -HH:MM to the end of the string shows an offset from UTC. For example, 2024-03-06T14:25:15+01:00 represents a date and time that is one hour ahead of UTC.
About Timezone-Aware datetime Objects
Before proceeding with formatting and parsing ISO 8601 strings, it is essential to understand that Python’s datetime objects can be classified into two categories: naive and aware.
A naive datetime object doesn’t include any information about time zones. Whereas, a timezone-aware datetime object explicitly carries time zone information, meaning it knows its offset from UTC.
To work with time zones effectively, you should use timezone-aware datetime objects. Python 3.9 introduced the zoneinfo module, making it easier to handle time zones directly from the IANA time zone database.
To create a timezone-aware datetime object, simply specify the time zone using the ZoneInfo class from the zoneinfo module. Here’s an example that demonstrates creating a datetime object for the “America/New_York” time zone:
from datetime import datetime
from zoneinfo import ZoneInfo
# Creating a datetime object for a specific time zone
dt_with_tz = datetime(2024, 3, 6, 14, 25, 15, tzinfo=ZoneInfo("America/New_York"))
print(dt_with_tz)
# Output: 2024-03-06 14:25:15-05:00
You can also convert a timezone-aware datetime object from one time zone to another using the astimezone()
method:
from datetime import datetime
from zoneinfo import ZoneInfo
# Creating a datetime object for a specific time zone
dt_with_tz = datetime(2024, 3, 6, 14, 25, 15, tzinfo=ZoneInfo("America/New_York"))
# Convert a datetime object to UTC
utc_dt = dt_with_tz.astimezone(ZoneInfo("UTC"))
print(utc_dt)
# Output: 2024-03-06 19:25:15+00:00
Formatting datetime Object with Time Zone to ISO 8601
When you format a timezone-aware datetime object using the isoformat()
method, Python automatically includes the time zone information in the resulting string:
from datetime import datetime
from zoneinfo import ZoneInfo
dt_with_tz = datetime(2024, 3, 6, 14, 25, 15, tzinfo=ZoneInfo("America/New_York"))
iso_format_string_utc = dt_with_tz.isoformat()
print(iso_format_string_utc)
# Output: 2024-03-06T14:25:15-05:00
Parsing ISO 8601 String with Time Zone
Python also supports parsing ISO 8601 strings that include time zone information. This is achieved using the fromisoformat()
method. Here’s an example of how to parse such a string:
from datetime import datetime
iso_string_tz = '2024-03-06T14:25:15-05:00' # 1 hour ahead of UTC
datetime_obj_tz = datetime.fromisoformat(iso_string_tz)
print(datetime_obj_tz)
# Output: 2024-03-06 14:25:15-05:00