The datetime
module is a built-in module in Python that allows us to work with dates and times easily. Inside the module we can find a few classes, but the most used ones are datetime
and timedelta
.
This usually means that we work with the datetime
class inside the datetime
module—somewhat confusing, but that's why you'll normally see things like datetime.datetime
when looking at Python code that uses this.
What is a datetime
object?
Put simply, a datetime
object is one that stores information about a specific point in time. Information such as year, month, day, hour, minute, and second. With all that information, we can use a datetime
object to refer to one particular moment in time. For example:
import datetime
today = datetime.datetime(year=2019, month=12, day=23, hour=11, minute=49, second=30)
print(today) # 2019-12-23 11:49:30
In addition to storing data about the specific point in time, it also has methods that help us interact with or process that data in a way that makes sense.
For example, given two datetime
objects you can compare them to see which one is further into the future.
import datetime
today = datetime.datetime(year=2019, month=12, day=23, hour=11, minute=49, second=30)
tomorrow = datetime.datetime(year=2019, month=12, day=24, hour=11, minute=49, second=30)
print(today > tomorrow) # False
Here we would print False
because today
is in the past, relative to tomorrow
. This is how we can compare two dates, for example to tell whether something happened in the past.
How to get today's date
Because getting today's date is so common, the datetime
class comes with a method you can use to get a new datetime
object for today's date:
import datetime
print(datetime.datetime.now())
# 2019-12-23 11:54:13.151509
You can also use datetime.datetime.today()
to get the current time and date, but it can sometimes be less precise. Also, it does now allow us to give it timezone information (more on that later!)
Notice that when we're doing this, we get microseconds as well as the other time measures. This can be unnecessary, but when dealing with computers it can sometimes be useful.
How to modify dates
You can't add two dates together, as that seldom makes sense. For example, what should happen if you add "today" to "today"?
import datetime
print(datetime.datetime.now() + datetime.datetime.now())
# Error
Instead, when you want to change a date—for example by adding a few days to it—we use the timedelta
class. A "delta" in mathematics means a "change", so that's where the name comes from.
import datetime
today = datetime.datetime.now()
one_week = datetime.timedelta(days=7)
print(today + one_week) # 2019-12-30 11:58:52.073407
You can use timedelta
with these arguments:
days
seconds
microseconds
milliseconds
minutes
hours
weeks
But the object itself will only store days
, seconds
, and microseconds
. All other arguments will be converted to those (e.g. minutes * 60
will be added to seconds
).
How to display dates
You can print
dates or convert them to strings by using the built-in str()
function, so that they'll be shown in this format:
import datetime
print(datetime.datetime.now())
# 2019-12-23 11:54:13.151509
Sometimes you may want more flexibility regarding how you print it out. Maybe you only want to print out the date portion. Or maybe, just "hours and minutes".
You can do this by using .strftime()
, which stands for "string format time".
import datetime
today = datetime.datetime.now()
print(today.strftime("%Y-%m-%d")
# 2019-12-23
print(today.strftime("%H:%M")
# 11:54
Doing this does not modify the today
object at all, it just creates a string representing the date or time as dictated by the "format string" passed.
This is a good reference for all different things you can pass to strftime
: [https://strftime.org/](https://strftime.org/).
How to parse dates
Very similarly to printing dates with a specific format, we can read in dates with a specific format.
For example, let's say your user gives you a string describing today's date: 23-12-2019
. Clearly this string is in the format "day-month-year". In Python datetime
format: "%d-%m-%Y"
.
We can use .strptime
to parse a date string into a datetime
object:
import datetime
user_date = input("Enter today's date: ")
# Assume they entered 23-12-2019
today = datetime.datetime.strptime(user_date, "%d-%m-%Y")
print(today) # 2019-12-23 00:00:00
The same format strings as we used for strftime
can be used in strptime
What is a timestamp?
A timestamp is the number of seconds that have passed since 1st January, 1970, at midnight.
We use timestamps because it is easier to work with a single number (albeit large) than with many numbers each describing a different measurement.
The timestamp for "2nd January, 1970, at midnight" would be 86400
: the number of seconds in one day.
To get a timestamp you can call the timestamp()
method of any datetime
object:
import datetime
today = datetime.datetime.now()
print(today.timestamp()) # 1577104357.558527
Because it is so common to get the timestamp of right now, we can use the time
module to get it more easily:
import time
print(time.time()) # 1577104492.7515678
Timezones
A timezone is a region where the same standard time is used.
For example, a lot of Western Europe uses the same standard time—Spain, France, Italy, Germany, etc. They are all in the "Central European Time" timezone. In Summer, when daylight savings are in effect, they are all in the "Central European Summer Time" timezone.
If you are running Python in a computer that is using CET, then doing datetime.datetime.now()
would give you the local time of the computer.
However if you grab a different computer that is using Pacific Standard Time, then datetime.datetime.now()
would give you a different time.
That is why it is important to tell the datetime
objects what timezone the time they represent is in: so that no matter what computer is running the code, the time represented will always be the same.
The "central" time is called Universal Time Coordinated (UTC). All other timezones can be described by using UTC as a reference. For example, CET is UTC + 1 hour. PST is UTC - 6 hours.
We would thus write CET as +01:00
, and PST as -06:00
.
We call that the "offset", and it is usually placed after a date and time. For example:
2019-12-23 11:54:13+01:00
The above time is 11:54 with an offset of 1 hour.
That means that that timezone might be CET (or any other timezone with a +1 hour offset from UTC).
We can calculate the UTC time by subtracting 1 hour from the time, which would put us at 10:54.
Getting the current date and time in UTC
We've learned that you can get the local time like so:
import datetime
today = datetime.datetime.now()
print(today) # 2019-12-23 15:35:56.133138
When doing this you can ask Python to get you the current time, but translated to a different timezone. Below we pass datetime.timezone.utc
to .now()
so that Python will give us the current time in the UTC timezone.
import datetime
today = datetime.datetime.now(datetime.timezone.utc)
print(today) # 2019-12-23 15:35:56.133138+00:00
You can see that in my case, the time is the same. That is because at the moment my timezone also has an offset of +00:00, so it matches UTC.
If your timezone does not match UTC, you'll see those two times are different (indeed, the difference will be your timezone's offset from UTC).
Note that when we did .now()
without passing a timezone, our printed string did not contain an offset. But when we did .now(datetime.timezone.utc)
, the printed string contained the +00:00
offset.
Naive vs. aware datetimes
If your datetime
object knows what timezone the date and time it represents is in, then we call that an aware datetime
object. If it doesn't have timezone information, we call that a naive object.
Aware objects represent specific points in time in specific places in the world. Naive objects only represent specific points in time.
Note that working with naive objects can be dangerous because different pieces of code may interpret the naive object to be using a different timezone. For example, some of your code might use a naive object as if it were in UTC. Some other code might use a naive object as if it were in the current, local timezone.
Therefore it's almost always a good idea to store timezone information in your datetime
objects.
Converting from one timezone to another using pytz
You can convert from one timezone to another using the built-in datetime
module, but you'll need to tell Python what timezones exist and can be used by writing a class for each timezone that subclasses the datetime.tzinfo
class. You'll also have to do a lot of manual work so that your timezone classes keep track of daylight savings.
Alternatively you can use (and probably should use) the pytz
module for working with timezones in your Python code.
First of all, install pytz
by following their installation instructions or using pip install pytz
.
Getting a timezone from pytz
The pytz
module comes with a whole database of timezones, accessible by their official names:
import pytz
eastern = pytz.timezone("US/Eastern")
amsterdam = pytz.timezone("Europe/Amsterdam")
Adding timezone information to a native datetime
If you have a naive datetime
object (from the built-in module), you can use pytz
to add timezone information:
import datetime
import pytz
eastern = pytz.timezone("US/Eastern")
local_time = datetime.datetime.now()
print(local_time) # 2020-02-12 11:47:21.817708
eastern_time = eastern.localize(local_time)
print(eastern_time) # 2020-02-12 11:47:21.817708-05:00
Note that doing this does not change the time information in the datetime
object.
Converting from one timezone to another
If you have an aware datetime
object and you want to translate it to another timezone, then you can also do this with pytz
:
import datetime
import pytz
eastern = pytz.timezone("US/Eastern")
amsterdam = pytz.timezone("Europe/Amsterdam")
local_time = datetime.datetime.now()
eastern_time = eastern.localize(local_time)
print(eastern_time) # 2020-02-12 11:47:21.817708-05:00
amsterdam_time = eastern_time.astimezone(amsterdam)
print(amsterdam_time) # 2020-02-12 17:47:21.817708+01:00
Now the displayed time has changed because it's the same date and time, but in a different timezone. Both eastern_time
and amsterdam_time
refer to the same exact point in time.
You can make sure of that by converting each to UTC yourself. Add 5 hours to eastern_time
and subtract 1 hour from amsterdam_time
to reach a +00:00 offset. You'll see the times are identical.
Dealing with daylight savings
The pytz
module deals with daylight savings with you. For example the US/Eastern
timezone may sometimes be at -05:00
and other times at -04:00
, depending on the time of year.
An example of this shown below
Working with dates and times in software applications
Usually I would recommend to always work in UTC in your applications. Ask the users for local time and timezone, and convert it to UTC. Store UTC in your database. Only change back to the user's local time when you are displaying a date and time to them (and only if your users want to see times in their local time).
That way you will not have to worry about timezones within your application logic; only when dealing with user interaction.
The pytz
module comes with a pytz.utc
timezone that you can use when constructing datetime
objects in order to simplify this:
import datetime
import pytz
eastern = pytz.timezone("US/Eastern")
user_date = datetime.datetime(2020, 4, 15, 6, 0, 0, tzinfo=eastern)
utc_date = user_date.astimezone(pytz.utc)
print(utc_date) # 2020-04-15 10:56:00+00:00
As long as you always work with UTC, and only convert to the user's local timezone when you are displaying information, it will be relatively simple!
Wrapping Up
Thank you for reading this blog post on working with dates and times in Python using datetime
and pytz
. I hope it's been useful!
If you want to learn more about Python as a whole, check out our Complete Python Course. It's a 30-hour video-course that takes you from beginner to expert in Python. We'd love to see you there!