Python Datetime: A Simple Guide with 39 Code Examples (2023)
You may already be familiar with various data types in Python like integers, floats, strings, etc. However, sometimes when you're developing a script or a machine learning algorithm, you should use dates and times. In everyday life, we can represent dates and times in many different formats, for example, July 4
, March 8, 2022
, 22:00
, or 31 December 2022, 23:59:59
. They use a combination of integers and strings, or you can also use floats to represent a fraction of a day, minute, etc.
But this isn't the only complication! Add to this listing different timezones, daylight saving time, different time format conventions (in the USA, it's 07/23/2022 and in Europe, it's 23/07/2023), etc.
Computers require unambiguous precision when we tell them what to do, but dates and times represent a challenge. Thankfully, Python has the datetime
module that allows us to easily manipulate objects that represent dates and times.
In this Python datetime
tutorial, we'll learn the following:
- Uses of the
datetime
module in Python - Transforming a string to a
datetime
object and vice versa using Pythondatetime
functions - Extracting date and time from a
datetime
object - Working with timestamps
- Performing arithmetic operations on dates and times
- Working with timezones
- Finally, creating a countdown timer to determine how long remains until New Year 2023 (in New York City!)
Let's begin working with dates and times in Python.
Note: If a piece of code doesn't have the import
statement, assume that the class/function used in the code has already been imported.
How do I use datetime in Python?
As we said earlier, representing dates and times in programming is a challenge. First of all, we have to represent them in a standard, universally accepted format. Fortunately, the International Organization for Standardization (ISO) developed a worldwide standard ISO 8601, which represents date- and time-related objects as YYYY-MM-DD HH:MM:SS
with information ranging from the most important (years,YYYY
) to the least important (seconds, SS
). Each piece of this format is represented as a four- or two-digit number.
The datetime
module in Python has 5 main classes (parts of the module):
date
to manipulate date objectstime
to manipulate time objectsdatetime
is a combination ofdate
andtime
timedelta
allows us to work with time durationtzinfo
allows us to work with timezones
Additionally, we'll use the zoneinfo
module, which provides us a modern way of working with time zones, and the dateutil
package, which contains plenty of useful functions to work with dates and times.
Let's import the datetime
module and create our first date and time objects:
# From the datetime module import date
from datetime import date
# Create a date object of 2000-02-03
date(2000, 2, 3)
datetime.date(2000, 2, 3)
In the code above, we imported the date
class from the module and then created a datetime.date
object of February 3, 2000. We can note that the order of numbers that we use to create this object is exactly the same as in ISO 8061 (but we omit 0s and write only one-digit numbers for the month and the day).
Coding is all about experimentation, so let's say we want to create an object of 2000-26-03:
# Create a date object of 2000-26-03
date(2000, 26, 3)
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Input In [2], in
1 # Create a date object of 2000-26-03
----> 2 date(2000, 26, 3)
ValueError: month must be in 1..12
We get ValueError: month must be in 1..12
, which makes sense because there is no month 26 in the calendar. This function strictly follows the ISO 8601 format. For practice, add more arguments to the date
function and note what happens.
Let's see how we can create a datetime.time
object:
# From the datetime module import time
from datetime import time
# Create a time object of 05:35:02
time(5, 35, 2)
datetime.time(5, 35, 2)
We've succeeded, and you can guess that this function also follows the ISO 8061 format. Can you break it as we did before with the date
function?
Now, what if we want both a date and a time in one object? We should use the datetime
class:
# From the datetime module import datetime
from datetime import datetime
# Create a datetime object of 2000-02-03 05:35:02
datetime(2000, 2, 3, 5, 35, 2)
datetime.datetime(2000, 2, 3, 5, 35, 2)
Great, we have our datetime
object. We can also be more explicit and pass keyword arguments to the datetime
constructor:
datetime(year=2000, month=2, day=3, hour=5, minute=35, second=2)
datetime.datetime(2000, 2, 3, 5, 35, 2)
What if we pass in only three arguments (year, month, and day)? Would it cause an error?
# Create a datetime object of 2000-02-03
datetime(2000, 2, 3)
datetime.datetime(2000, 2, 3, 0, 0)
We can see that now there are two zeros in the object that represent (respectively) the hour and the minute. Seconds, in this case, are omitted.
In many situations, we want to know the exact time at the moment. We can use the now()
method of the datetime
class:
# Time at the moment
now = datetime.now()
now
datetime.datetime(2022, 2, 14, 11, 33, 25, 516707)
We get a datetime
object. Here the last number is microseconds.
If we only need today's date, we can use the today()
method from the date
class:
today = date.today()
today
datetime.date(2022, 2, 14)
If we only need the time, we may write time.now()
, but it won't work. Instead, we have to access the hour
, minute
, and second
attributes of the datetime.now()
object and pass them to the time
constructor:
time(now.hour, now.minute, now.second)
datetime.time(11, 33, 25)
For practice, get the date from the datetime
object in Python (assigned to the now
variable).
We can also extract the week number and the number of the day from a datetime
object using the isocalendar()
function. It will return a three-item tuple containing an ISO year, week number, and weekday number:
# isocalendar() returns a 3-item tuple with ISO year, week number, and weekday number
now.isocalendar()
datetime.IsoCalendarDate(year=2022, week=7, weekday=1)
In the ISO format, a week starts on Monday and ends on Sunday. The days of the week are encoded by the numbers from 1 (Monday) to 7 (Sunday). If we want to access one of these tuple elements, we use bracket notation:
# Access week number
week_number = now.isocalendar()[1]
week_number
7
Extracting dates from strings
In data science, and in programming generally, we mostly work with dates and times that are stored as strings in dozens of different formats, depending on the region, company, or the granularity of the information we need. Sometimes, we need the date and the exact time, but in other cases, we only need the year and the month. How can we extract the data we need from a string to easily manipulate it as a datetime
(date
, time
) object?
fromisoformat() and isoformat()
The first function we'll learn to convert a date string into a date
object is fromisoformat
. We call it this way because it uses the ISO 8601 format (i.e., YYYY-MM-DD
). Let's look at an example:
# Convert a date string into a date object
date.fromisoformat("2022-12-31")
datetime.date(2022, 12, 31)
The ISO format also contains the time, but if we pass it to the function, it won't work:
date.fromisoformat("2022-12-31 00:00:00")
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Input In [13], in
----> 1 date.fromisoformat("2022-12-31 00:00:00")
ValueError: Invalid isoformat string: '2022-12-31 00:00:00'
Of course, we can also perform an inverse operation and convert a datetime
object into a date string in the ISO format. For this purpose, we should use the isoformat()
:
# Convert a datetime object into a string in the ISO format
date(2022, 12, 31).isoformat()
'2022-12-31'
strptime()
To solve the above ValueError
problem, we can use the strptime()
function that can convert an arbitrary date/time string into a datetime
object. Our string doesn't necessarily need to follow the ISO format, but we should specify which part of the string represents which date or time unit (year, hour, etc.). Let's look at an example to clarify. First of all, we'll use the strict ISO format to convert a string into a datetime
object:
# Date as a string
iso_date = "2022-12-31 23:59:58"
# ISO format
iso_format = "
# Convert the string into a datetime object
datetime.strptime(iso_date, iso_format)
datetime.datetime(2022, 12, 31, 23, 59, 58)
In the first line, we create a date/time string. In the second line, we specify the format of the string using a special code that contains a percent sign followed by a character that encodes a date or time unit. Finally, in the third line, we use the strptime()
function to convert the string into a datetime
object. This function takes two arguments: the string and the format of the string.
The code we used above can also encode other date and time units like a weekday, month name, week number, etc.
Code | Example | Description |
---|---|---|
Monday | Full weekday name | |
December | Full month name | |
2 | Week number (Monday as the first day of the week) |
You can refer to this website for other codes used in Python.
Let's look at a few more examples using other formats:
# European date as a string
european_date = "31-12-2022"
# European format
european_format = "
# Convert the string into a datetime object
datetime.strptime(european_date, european_format)
datetime.datetime(2022, 12, 31, 0, 0)
As we can see above, the string was successfully converted, but we have additional zeros that represent the time. Let's look at an example using other codes:
# Full month name date
full_month_date = "12 September 2022"
# Full month format
full_month_format = "
# Convert the string into a datetime object
datetime.strptime(full_month_date, full_month_format)
datetime.datetime(2022, 9, 12, 0, 0)
Again success! Note that the format we define should match the format of the date string. Thus, if we have spaces, colons, hyphens, or other characters to separate time units, they should be in the code string. Otherwise, Python will throw a ValueError
:
# Full month name date
full_month_date = "12 September 2022"
# Wrong format (missing space)
full_month_format = "
# Convert the string into a datetime object
datetime.strptime(full_month_date, full_month_format)
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Input In [18], in
5 full_month_format =
7 # Convert the string into a datetime object
----> 8 datetime.strptime(full_month_date, full_month_format)
File ~/coding/dataquest/articles/using-the-datetime-package/env/lib/python3.10/_strptime.py:568, in _strptime_datetime(cls, data_string, format)
565 def _strptime_datetime(cls, data_string, format=
566 """Return a class cls instance based on the input string and the
567 format string."""
--> 568 tt, fraction, gmtoff_fraction = _strptime(data_string, format)
569 tzname, gmtoff = tt[-2:]
570 args = tt[:6] + (fraction,)
File ~/coding/dataquest/articles/using-the-datetime-package/env/lib/python3.10/_strptime.py:349, in _strptime(data_string, format)
347 found = format_regex.match(data_string)
348 if not found:
--> 349 raise ValueError("time data
350 (data_string, format))
351 if len(data_string) != found.end():
352 raise ValueError("unconverted data remains:
353 data_string[found.end():])
ValueError: time data '12 September 2022' does not match format
Even one missing space can cause the error!
Converting datetime objects into strings
strftime()
In Python, we can also convert a datetime
object into a string using the strftime()
function. It takes two arguments: a datetime
object and the format of the output string.
# Create a datetime object
datetime_obj = datetime(2022, 12, 31)
# American date format
american_format = "
# European format
european_format = "
# American date string
print(f"American date string: {datetime.strftime(datetime_obj, american_format)}.")
# European date string
print(f"European date string: {datetime.strftime(datetime_obj, european_format)}.")
American date string: 12-31-2022.
European date string: 31-12-2022.
We took the same datetime
object and converted it into two different formats. We can also specify other formats, like the full month name followed by the day and the year.
full_month = "
datetime.strftime(datetime_obj, full_month)
'December 31, 2022'
Another way to use strftime
is to place it after a datetime
object:
datetime_obj = datetime(2022, 12, 31, 23, 59, 59)
full_datetime = "
datetime_obj.strftime(full_datetime)
'December 31, 2022 23:59:59'
In practice, strftime()
may be useful if we want to extract the weekday name that falls on December 31 in different years:
# Extract the weekday name of December 31
weekday_format = "
for year in range(2022, 2026):
print(f"Weekday of December 31, {year} is {date(year, 12, 31).strftime(weekday_format)}.")
Weekday of December 31, 2022 is Saturday.
Weekday of December 31, 2023 is Sunday.
Weekday of December 31, 2024 is Tuesday.
Weekday of December 31, 2025 is Wednesday.
Timestamps
In programming, it's common to see dates and times stored in the Unix timestamp format. This format represents whatever date as digits. Basically, a timestamp is a number of seconds that passed from the Unix epoch that started at 00:00:00 UTC (Coordinated Universal Time) on 1 January 1970. We can compute this number using the timestamp()
function:
new_year_2023 = datetime(2022, 12, 31)
datetime.timestamp(new_year_2023)
1672441200.0
1672441200 is the number of seconds between the start of the Unix epoch and December 31, 2022.
We can perform the inverse operation by using the fromtimestamp()
function:
datetime.fromtimestamp(1672441200)
datetime.datetime(2022, 12, 31, 0, 0)
Arithmetic operations with dates
Sometimes, we may want to compute the difference between two dates or perform other arithmetic operations on dates and times. Fortunately, Python has many instruments in its toolkit to perform such calculations.
Basic arithmetic operations
The first operation we can perform is to calculate the difference between two dates. To do this, we use the minus sign:
# Instatiate two dates
first_date = date(2022, 1, 1)
second_date = date(2022, 12, 31)
# Difference between two dates
date_diff = second_date - first_date
# Function to convert datetime to string
def dt_string(date, date_format="
return date.strftime(date_format)
print(f"The number of days and hours between {dt_string(first_date)} and {dt_string(second_date)} is {date_diff}.")
The number of days and hours between January 01, 2022 and December 31, 2022 is 364 days, 0:00:00.
Let's look at what type of object first_date - second_date
returns:
type(date_diff)
datetime.timedelta
The type of this object is datetime.timedelta
. It has delta in its name, which refers to a Green letter delta, $\Delta$, which in science and engineering, describes a change. Indeed, here it represents a change (difference) in time.
What if we're interested only in the number of days between two dates? We can access different attributes of the timedelta
objects, and one of them is called .days
.
print(f"The number of days between {dt_string(first_date)} and {dt_string(second_date)} is {(date_diff).days}.")
The number of days between January 01, 2022 and December 31, 2022 is 364.
timedelta()
Now that we know about the timedelta
object, it's time to introduce the timedelta()
function. It allows us to perform many arithmetic operations on time objects by adding and subtracting time units like days, years, weeks, seconds, etc. For example, we may be interested in knowing what day of the week is 30 days from now. To do so, we have to create an object that represents the current time and a timedelta
object that defines the amount of time we add to it:
# Import timedelta
from datetime import timedelta
# Current time
now = datetime.now()
# timedelta of 30 days
one_month = timedelta(days=30)
# Day in one month/using dt_string function defined above
print(f"The day in 30 days is {dt_string(now + one_month)}.")
The day in 30 days is March 16, 2022.
If we check the help page of the timedelta
function (help(timedelta)
), we'll see that it has the following arguments: days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours=0, weeks=0
. So, you can practice adding or subtracting other time units to a date. For example, we can compute the time 12 hours before New Year 2030:
# New year 2030
new_year_2030 = datetime(2030, 1, 1, 0, 0)
# timedelta of 12 hours
twelve_hours = timedelta(hours=12)
# Time string of 12 hours before New Year 2023
twelve_hours_before = (new_year_2030 - twelve_hours).strftime("
# Print the time 12 hours before New Year 2023
print(f"The time twelve hours before New Year 2030 will be {twelve_hours_before}.")
The time twelve hours before New Year 2030 will be December 31, 2029, 12:00:00.
We can also combine multiple arguments of the timedelta()
function to figure out a more specific time. For example, what will the time be in 27 days, 3 hours, and 45 minutes from now?
# Current time
now = datetime.now()
# Timedelta of 27 days, 3 hours, and 45 minutes
specific_timedelta = timedelta(days=27, hours=3, minutes=45)
# Time in 27 days, 3 hours, and 45 minutes
twenty_seven_days = (now + specific_timedelta).strftime("
print(f"The time in 27 days, 3 hours, and 45 minutes will be {twenty_seven_days}.")
The time in 27 days, 3 hours, and 45 minutes will be March 13, 2022, 15:18:39.
relativedelta()
Unfortunately, we can see from the help page that the function doesn't allow us to use months or years. To overcome this limitation, we can use the relativedelta
function from the dateutil
package. This function is very similar to timedelta()
, but it extends its functionality.
For example, we want to subtract 2 years, 3 months, 4 days, and 5 hours from the current time:
# Import relativedelta
from dateutil.relativedelta import relativedelta
# Current time
now = datetime.now()
# relativedelta object
relative_delta = relativedelta(years=2, months=3, days=4, hours=5)
two_years = (now - relative_delta).strftime("
print(f"The time 2 years, 3 months, 4 days, and 5 hours ago was {two_years}.")
The time 2 years, 3 months, 4 days, and 5 hours ago was November 10, 2019, 06:33:40.
We can also use relativedelta()
to compute the difference between two datetime
objects:
relativedelta(datetime(2030, 12, 31), now)
relativedelta(years=+8, months=+10, days=+16, hours=+12, minutes=+26, seconds=+19, microseconds=+728345)
These arithmetic operations may seem very abstract and impractical, but actually, they're useful in many applications. One such scenario might look like the following.
Say, a certain operation in our script should be performed only 30 days before a specific date. We can define a variable that holds the current time and adds a timedelta
object of 30 days to it. If today is the day, the operation will be evoked!
Otherwise, imagine we're working with datasets using pandas, and one of the columns contains some dates. Imagine that we have a dataset that holds our company profits on each day of the year. We want to create another dataset that will hold the dates exactly one year from the current date and predicted profits on each of those days. We're bound to use arithmetic calculations on dates!
Sooner or later, you'll encounter dates and times in one of your data science projects. When you do, head back to this tutorial.
Working with Time Zones
As we mentioned in the introduction, one of the issues of working with time in programming is handling time zones. They can have different shapes. We should also be aware that some regions implement daylight saving time (DST) while others don't.
Python distinguishes two types of date and time objects: naive and aware. A naive object doesn't hold any information about time zones, and an aware object does hold it.
First of all, let's look at a naive time object:
# Import tzinfo
from datetime import tzinfo
# Naive datetime
naive_datetime = datetime.now()
# Naive datetime doesn't hold any timezone information
type(naive_datetime.tzinfo)
NoneType
From Python 3.9, we have a concrete implementation of time zones using the Internet Assigned Numbers Authority database. The module that implements this functionality is called zoneinfo
. Note that if you're using previous versions of Python, you may use the pytz
or dateutil
packages.
Let's create an aware datetime
object using zoneinfo
and, in particular, the ZoneInfo
class, which is an implementation of the datetime.tzinfo
abstract class:
# Import ZoneInfo
from zoneinfo import ZoneInfo
utc_tz = ZoneInfo("UTC")
# Aware datetime object with UTC timezone
dt_utc = datetime.now(tz=utc_tz)
# The type of an aware object implemented with ZoneInfo is zoneinfo.ZoneInfo
type(dt_utc.tzinfo)
zoneinfo.ZoneInfo
We can see that an aware datetime
object has the information about time zones (implemented as a zoneinfo.ZoneInfo
object).
Let's look at a few examples. We want to determine the current time in Central Europe and California.
First of all, we can list all the available time zones in zoneinfo
:
import zoneinfo
# Will return a long list of timezones (opens many files!)
zoneinfo.available_timezones()
{'Africa/Abidjan',
'Africa/Accra',
'Africa/Addis_Ababa',
'Africa/Algiers',
'Africa/Asmara',
'Africa/Asmera',
'Africa/Bamako',
'Africa/Bangui',
'Africa/Banjul',
'Africa/Bissau',
'Africa/Blantyre',
'Africa/Brazzaville',
'Africa/Bujumbura',
'Africa/Cairo',
'Africa/Casablanca',
'Africa/Ceuta',
'Africa/Conakry',
'Africa/Dakar',
'Africa/Dar_es_Salaam',
'Africa/Djibouti',
'Africa/Douala',
'Africa/El_Aaiun',
'Africa/Freetown',
'Africa/Gaborone',
'Africa/Harare',
'Africa/Johannesburg',
'Africa/Juba',
'Africa/Kampala',
'Africa/Khartoum',
'Africa/Kigali',
'Africa/Kinshasa',
'Africa/Lagos',
'Africa/Libreville',
'Africa/Lome',
'Africa/Luanda',
'Africa/Lubumbashi',
'Africa/Lusaka',
'Africa/Malabo',
'Africa/Maputo',
'Africa/Maseru',
'Africa/Mbabane',
'Africa/Mogadishu',
'Africa/Monrovia',
'Africa/Nairobi',
'Africa/Ndjamena',
'Africa/Niamey',
'Africa/Nouakchott',
'Africa/Ouagadougou',
'Africa/Porto-Novo',
'Africa/Sao_Tome',
'Africa/Timbuktu',
'Africa/Tripoli',
'Africa/Tunis',
'Africa/Windhoek',
'America/Adak',
'America/Anchorage',
'America/Anguilla',
'America/Antigua',
'America/Araguaina',
'America/Argentina/Buenos_Aires',
'America/Argentina/Catamarca',
'America/Argentina/ComodRivadavia',
'America/Argentina/Cordoba',
'America/Argentina/Jujuy',
'America/Argentina/La_Rioja',
'America/Argentina/Mendoza',
'America/Argentina/Rio_Gallegos',
'America/Argentina/Salta',
'America/Argentina/San_Juan',
'America/Argentina/San_Luis',
'America/Argentina/Tucuman',
'America/Argentina/Ushuaia',
'America/Aruba',
'America/Asuncion',
'America/Atikokan',
'America/Atka',
'America/Bahia',
'America/Bahia_Banderas',
'America/Barbados',
'America/Belem',
'America/Belize',
'America/Blanc-Sablon',
'America/Boa_Vista',
'America/Bogota',
'America/Boise',
'America/Buenos_Aires',
'America/Cambridge_Bay',
'America/Campo_Grande',
'America/Cancun',
'America/Caracas',
'America/Catamarca',
'America/Cayenne',
'America/Cayman',
'America/Chicago',
'America/Chihuahua',
'America/Coral_Harbour',
'America/Cordoba',
'America/Costa_Rica',
'America/Creston',
'America/Cuiaba',
'America/Curacao',
'America/Danmarkshavn',
'America/Dawson',
'America/Dawson_Creek',
'America/Denver',
'America/Detroit',
'America/Dominica',
'America/Edmonton',
'America/Eirunepe',
'America/El_Salvador',
'America/Ensenada',
'America/Fort_Nelson',
'America/Fort_Wayne',
'America/Fortaleza',
'America/Glace_Bay',
'America/Godthab',
'America/Goose_Bay',
'America/Grand_Turk',
'America/Grenada',
'America/Guadeloupe',
'America/Guatemala',
'America/Guayaquil',
'America/Guyana',
'America/Halifax',
'America/Havana',
'America/Hermosillo',
'America/Indiana/Indianapolis',
'America/Indiana/Knox',
'America/Indiana/Marengo',
'America/Indiana/Petersburg',
'America/Indiana/Tell_City',
'America/Indiana/Vevay',
'America/Indiana/Vincennes',
'America/Indiana/Winamac',
'America/Indianapolis',
'America/Inuvik',
'America/Iqaluit',
'America/Jamaica',
'America/Jujuy',
'America/Juneau',
'America/Kentucky/Louisville',
'America/Kentucky/Monticello',
'America/Knox_IN',
'America/Kralendijk',
'America/La_Paz',
'America/Lima',
'America/Los_Angeles',
'America/Louisville',
'America/Lower_Princes',
'America/Maceio',
'America/Managua',
'America/Manaus',
'America/Marigot',
'America/Martinique',
'America/Matamoros',
'America/Mazatlan',
'America/Mendoza',
'America/Menominee',
'America/Merida',
'America/Metlakatla',
'America/Mexico_City',
'America/Miquelon',
'America/Moncton',
'America/Monterrey',
'America/Montevideo',
'America/Montreal',
'America/Montserrat',
'America/Nassau',
'America/New_York',
'America/Nipigon',
'America/Nome',
'America/Noronha',
'America/North_Dakota/Beulah',
'America/North_Dakota/Center',
'America/North_Dakota/New_Salem',
'America/Nuuk',
'America/Ojinaga',
'America/Panama',
'America/Pangnirtung',
'America/Paramaribo',
'America/Phoenix',
'America/Port-au-Prince',
'America/Port_of_Spain',
'America/Porto_Acre',
'America/Porto_Velho',
'America/Puerto_Rico',
'America/Punta_Arenas',
'America/Rainy_River',
'America/Rankin_Inlet',
'America/Recife',
'America/Regina',
'America/Resolute',
'America/Rio_Branco',
'America/Rosario',
'America/Santa_Isabel',
'America/Santarem',
'America/Santiago',
'America/Santo_Domingo',
'America/Sao_Paulo',
'America/Scoresbysund',
'America/Shiprock',
'America/Sitka',
'America/St_Barthelemy',
'America/St_Johns',
'America/St_Kitts',
'America/St_Lucia',
'America/St_Thomas',
'America/St_Vincent',
'America/Swift_Current',
'America/Tegucigalpa',
'America/Thule',
'America/Thunder_Bay',
'America/Tijuana',
'America/Toronto',
'America/Tortola',
'America/Vancouver',
'America/Virgin',
'America/Whitehorse',
'America/Winnipeg',
'America/Yakutat',
'America/Yellowknife',
'Antarctica/Casey',
'Antarctica/Davis',
'Antarctica/DumontDUrville',
'Antarctica/Macquarie',
'Antarctica/Mawson',
'Antarctica/McMurdo',
'Antarctica/Palmer',
'Antarctica/Rothera',
'Antarctica/South_Pole',
'Antarctica/Syowa',
'Antarctica/Troll',
'Antarctica/Vostok',
'Arctic/Longyearbyen',
'Asia/Aden',
'Asia/Almaty',
'Asia/Amman',
'Asia/Anadyr',
'Asia/Aqtau',
'Asia/Aqtobe',
'Asia/Ashgabat',
'Asia/Ashkhabad',
'Asia/Atyrau',
'Asia/Baghdad',
'Asia/Bahrain',
'Asia/Baku',
'Asia/Bangkok',
'Asia/Barnaul',
'Asia/Beirut',
'Asia/Bishkek',
'Asia/Brunei',
'Asia/Calcutta',
'Asia/Chita',
'Asia/Choibalsan',
'Asia/Chongqing',
'Asia/Chungking',
'Asia/Colombo',
'Asia/Dacca',
'Asia/Damascus',
'Asia/Dhaka',
'Asia/Dili',
'Asia/Dubai',
'Asia/Dushanbe',
'Asia/Famagusta',
'Asia/Gaza',
'Asia/Harbin',
'Asia/Hebron',
'Asia/Ho_Chi_Minh',
'Asia/Hong_Kong',
'Asia/Hovd',
'Asia/Irkutsk',
'Asia/Istanbul',
'Asia/Jakarta',
'Asia/Jayapura',
'Asia/Jerusalem',
'Asia/Kabul',
'Asia/Kamchatka',
'Asia/Karachi',
'Asia/Kashgar',
'Asia/Kathmandu',
'Asia/Katmandu',
'Asia/Khandyga',
'Asia/Kolkata',
'Asia/Krasnoyarsk',
'Asia/Kuala_Lumpur',
'Asia/Kuching',
'Asia/Kuwait',
'Asia/Macao',
'Asia/Macau',
'Asia/Magadan',
'Asia/Makassar',
'Asia/Manila',
'Asia/Muscat',
'Asia/Nicosia',
'Asia/Novokuznetsk',
'Asia/Novosibirsk',
'Asia/Omsk',
'Asia/Oral',
'Asia/Phnom_Penh',
'Asia/Pontianak',
'Asia/Pyongyang',
'Asia/Qatar',
'Asia/Qostanay',
'Asia/Qyzylorda',
'Asia/Rangoon',
'Asia/Riyadh',
'Asia/Saigon',
'Asia/Sakhalin',
'Asia/Samarkand',
'Asia/Seoul',
'Asia/Shanghai',
'Asia/Singapore',
'Asia/Srednekolymsk',
'Asia/Taipei',
'Asia/Tashkent',
'Asia/Tbilisi',
'Asia/Tehran',
'Asia/Tel_Aviv',
'Asia/Thimbu',
'Asia/Thimphu',
'Asia/Tokyo',
'Asia/Tomsk',
'Asia/Ujung_Pandang',
'Asia/Ulaanbaatar',
'Asia/Ulan_Bator',
'Asia/Urumqi',
'Asia/Ust-Nera',
'Asia/Vientiane',
'Asia/Vladivostok',
'Asia/Yakutsk',
'Asia/Yangon',
'Asia/Yekaterinburg',
'Asia/Yerevan',
'Atlantic/Azores',
'Atlantic/Bermuda',
'Atlantic/Canary',
'Atlantic/Cape_Verde',
'Atlantic/Faeroe',
'Atlantic/Faroe',
'Atlantic/Jan_Mayen',
'Atlantic/Madeira',
'Atlantic/Reykjavik',
'Atlantic/South_Georgia',
'Atlantic/St_Helena',
'Atlantic/Stanley',
'Australia/ACT',
'Australia/Adelaide',
'Australia/Brisbane',
'Australia/Broken_Hill',
'Australia/Canberra',
'Australia/Currie',
'Australia/Darwin',
'Australia/Eucla',
'Australia/Hobart',
'Australia/LHI',
'Australia/Lindeman',
'Australia/Lord_Howe',
'Australia/Melbourne',
'Australia/NSW',
'Australia/North',
'Australia/Perth',
'Australia/Queensland',
'Australia/South',
'Australia/Sydney',
'Australia/Tasmania',
'Australia/Victoria',
'Australia/West',
'Australia/Yancowinna',
'Brazil/Acre',
'Brazil/DeNoronha',
'Brazil/East',
'Brazil/West',
'CET',
'CST6CDT',
'Canada/Atlantic',
'Canada/Central',
'Canada/Eastern',
'Canada/Mountain',
'Canada/Newfoundland',
'Canada/Pacific',
'Canada/Saskatchewan',
'Canada/Yukon',
'Chile/Continental',
'Chile/EasterIsland',
'Cuba',
'EET',
'EST',
'EST5EDT',
'Egypt',
'Eire',
'Etc/GMT',
'Etc/GMT+0',
'Etc/GMT+1',
'Etc/GMT+10',
'Etc/GMT+11',
'Etc/GMT+12',
'Etc/GMT+2',
'Etc/GMT+3',
'Etc/GMT+4',
'Etc/GMT+5',
'Etc/GMT+6',
'Etc/GMT+7',
'Etc/GMT+8',
'Etc/GMT+9',
'Etc/GMT-0',
'Etc/GMT-1',
'Etc/GMT-10',
'Etc/GMT-11',
'Etc/GMT-12',
'Etc/GMT-13',
'Etc/GMT-14',
'Etc/GMT-2',
'Etc/GMT-3',
'Etc/GMT-4',
'Etc/GMT-5',
'Etc/GMT-6',
'Etc/GMT-7',
'Etc/GMT-8',
'Etc/GMT-9',
'Etc/GMT0',
'Etc/Greenwich',
'Etc/UCT',
'Etc/UTC',
'Etc/Universal',
'Etc/Zulu',
'Europe/Amsterdam',
'Europe/Andorra',
'Europe/Astrakhan',
'Europe/Athens',
'Europe/Belfast',
'Europe/Belgrade',
'Europe/Berlin',
'Europe/Bratislava',
'Europe/Brussels',
'Europe/Bucharest',
'Europe/Budapest',
'Europe/Busingen',
'Europe/Chisinau',
'Europe/Copenhagen',
'Europe/Dublin',
'Europe/Gibraltar',
'Europe/Guernsey',
'Europe/Helsinki',
'Europe/Isle_of_Man',
'Europe/Istanbul',
'Europe/Jersey',
'Europe/Kaliningrad',
'Europe/Kiev',
'Europe/Kirov',
'Europe/Lisbon',
'Europe/Ljubljana',
'Europe/London',
'Europe/Luxembourg',
'Europe/Madrid',
'Europe/Malta',
'Europe/Mariehamn',
'Europe/Minsk',
'Europe/Monaco',
'Europe/Moscow',
'Europe/Nicosia',
'Europe/Oslo',
'Europe/Paris',
'Europe/Podgorica',
'Europe/Prague',
'Europe/Riga',
'Europe/Rome',
'Europe/Samara',
'Europe/San_Marino',
'Europe/Sarajevo',
'Europe/Saratov',
'Europe/Simferopol',
'Europe/Skopje',
'Europe/Sofia',
'Europe/Stockholm',
'Europe/Tallinn',
'Europe/Tirane',
'Europe/Tiraspol',
'Europe/Ulyanovsk',
'Europe/Uzhgorod',
'Europe/Vaduz',
'Europe/Vatican',
'Europe/Vienna',
'Europe/Vilnius',
'Europe/Volgograd',
'Europe/Warsaw',
'Europe/Zagreb',
'Europe/Zaporozhye',
'Europe/Zurich',
'Factory',
'GB',
'GB-Eire',
'GMT',
'GMT+0',
'GMT-0',
'GMT0',
'Greenwich',
'HST',
'Hongkong',
'Iceland',
'Indian/Antananarivo',
'Indian/Chagos',
'Indian/Christmas',
'Indian/Cocos',
'Indian/Comoro',
'Indian/Kerguelen',
'Indian/Mahe',
'Indian/Maldives',
'Indian/Mauritius',
'Indian/Mayotte',
'Indian/Reunion',
'Iran',
'Israel',
'Jamaica',
'Japan',
'Kwajalein',
'Libya',
'MET',
'MST',
'MST7MDT',
'Mexico/BajaNorte',
'Mexico/BajaSur',
'Mexico/General',
'NZ',
'NZ-CHAT',
'Navajo',
'PRC',
'PST8PDT',
'Pacific/Apia',
'Pacific/Auckland',
'Pacific/Bougainville',
'Pacific/Chatham',
'Pacific/Chuuk',
'Pacific/Easter',
'Pacific/Efate',
'Pacific/Enderbury',
'Pacific/Fakaofo',
'Pacific/Fiji',
'Pacific/Funafuti',
'Pacific/Galapagos',
'Pacific/Gambier',
'Pacific/Guadalcanal',
'Pacific/Guam',
'Pacific/Honolulu',
'Pacific/Johnston',
'Pacific/Kanton',
'Pacific/Kiritimati',
'Pacific/Kosrae',
'Pacific/Kwajalein',
'Pacific/Majuro',
'Pacific/Marquesas',
'Pacific/Midway',
'Pacific/Nauru',
'Pacific/Niue',
'Pacific/Norfolk',
'Pacific/Noumea',
'Pacific/Pago_Pago',
'Pacific/Palau',
'Pacific/Pitcairn',
'Pacific/Pohnpei',
'Pacific/Ponape',
'Pacific/Port_Moresby',
'Pacific/Rarotonga',
'Pacific/Saipan',
'Pacific/Samoa',
'Pacific/Tahiti',
'Pacific/Tarawa',
'Pacific/Tongatapu',
'Pacific/Truk',
'Pacific/Wake',
'Pacific/Wallis',
'Pacific/Yap',
'Poland',
'Portugal',
'ROC',
'ROK',
'Singapore',
'Turkey',
'UCT',
'US/Alaska',
'US/Aleutian',
'US/Arizona',
'US/Central',
'US/East-Indiana',
'US/Eastern',
'US/Hawaii',
'US/Indiana-Starke',
'US/Michigan',
'US/Mountain',
'US/Pacific',
'US/Samoa',
'UTC',
'Universal',
'W-SU',
'WET',
'Zulu',
'build/etc/localtime'}
Now we can use ZoneInfo
to determine the current times in different regions:
# Function to convert datetime into ISO formatted time
def iso(time, time_format="
return time.strftime(time_format)
# CET time zone
cet_tz = ZoneInfo("Europe/Paris")
# PST time zone
pst_tz = ZoneInfo("America/Los_Angeles")
# Current time in Central Europe
dt_cet = datetime.now(tz=cet_tz)
# Current time in California
dt_pst = datetime.now(tz=pst_tz)
print(f"Current time in Central Europe is {iso(dt_cet)}.")
print(f"Current time in California is {iso(dt_pst)}.")
Current time in Central Europe is 2022-02-14 11:33:42.
Current time in California is 2022-02-14 02:33:42.
Let's print datetime.now(tz=cet_tz)
:
print(datetime.now(tz=cet_tz))
2022-02-14 11:33:43.048967+01:00
We see that there is +01:00
, which indicates the UTC offset. Indeed, the CET time zone is one hour ahead of UTC.
Moreover, the ZoneInfo
class handles daylight saving time. For example, we can add one day (24 hours) to a day when DST change occurs. In the USA, in 2022, it'll happen on November 5 (clock backward).
# Define timedelta
time_delta = timedelta(days=1)
# November 5, 2022, 3 PM
november_5_2022 = datetime(2022, 11, 5, 15, tzinfo=pst_tz) # Note that we should use tzinfo in the datetime construct
print(november_5_2022)
# Add 1 day to November 5, 2022
print(november_5_2022 + time_delta)
2022-11-05 15:00:00-07:00
2022-11-06 15:00:00-08:00
As we can see, the offset changed from -07:00
to -08:00
, but the time remained the same (15:00).
Countdown Timer to New Year 2023 in New York City
Times Square in New Your City attracts thousands of people on New Year's Eve. Let's apply everything we've learned so far to create a countdown timer to Times Square New Year's Eve!
Here we'll use tz
from the dateutil
package, which allows us to set our local time zone to demonstrate the utility of the dateutil
package. However, we can also use the build/etc/localtime
time zone from zoneinfo
to do the same thing.
from zoneinfo import ZoneInfo
from dateutil import tz
from datetime import datetime
def main():
"""Main function."""
# Set current time in our local time zone
now = datetime.now(tz=tz.tzlocal())
# New York City time zone
nyc_tz = ZoneInfo("America/New_York")
# New Year 2023 in NYC
new_year_2023 = datetime(2023, 1, 1, 0, 0, tzinfo=nyc_tz)
# Compute the time left to New Year in NYC
countdown = relativedelta(new_year_2023, now)
# Print time left to New Year 2023
print(f"New Year in New Your City will come on: {new_year_2023.strftime('
print(f"Time left to New Year 2023 in NYC is: {countdown.months} months, {countdown.days} days, {countdown.hours} hours, {countdown.minutes} minutes, {countdown.seconds} seconds.")
if __name__ == "__main__":
main()
New Year in New Your City will come on: January 1, 2023 00:00:00.
Time left to New Year 2023 in NYC is: 10 months, 17 days, 18 hours, 26 minutes, 16 seconds.
We wrapped the code in the main()
function, and now we can use it in a .py
file. In this script, we worked with time zones, created a datetime
object, converted it into a string using strftime()
, and even accessed time attributes of a relativedelta
object!
For practice, you can improve the script. I'm writing this tutorial in 2022, so for me, the New Year hasn't come yet. If you're reading it in future years, you can improve it and account for the fact that the New Year 2023 has already come. You can also include times left until future New Years. Or you may count the time that passed from the previous New Years. You can also update the script using the pytz
package to make it compatible with older versions of Python (before 3.9). It's up to you now.
Conclusions
Here's what we've covered in this tutorial:
- Issues with representing dates and times on computers
- Creating
date
, time
, and datetime
objects
- Standard date format, ISO 8061
- Extracting dates from strings using
fromisoformat()
and strptime()
- Converting
datetime
objects into strings using strftime()
- Timestamps
- Arithmetic operations with dates and
timedelta
objects
- Dealing with time zones in Python with
- Creating a countdown timer to New Year 2023 in New York City
Now you have plenty of tools in your toolkit, and you can start working with dates and times in Python.
Feel free to connect with me on LinkedIn and GitHub. Happy coding!