Jose: Hi, guys, and welcome back.
One of the most common problems
with dates and times are time zones.
So we're gonna look at
how to handle time zones well using pytz,
which is a Python library.
First of all, though, what is a time zone?
It is a region where the same standard time is used.
And this is often geographical regions,
but they don't have to be.
So it is a little bit complicated.
But the key thing is that, for different computers,
right now the current time means a different time
and potentially a different date.
I'm sure you're all aware of this,
but, for example, if we've got a map here,
a computer in the US might think it's 11:47 AM on May 14th,
and at the same time a computer in Japan
may think it's 48 minutes past midnight on May 15th.
So, clearly, different times, different dates,
but it's actually the same actual point in time.
So this can get quite complicated,
especially when you start taking into account
that some times of the year Japan
may actually be on the same day
because it may be 10 minutes to midnight on May 14th
if they don't have daylight savings enabled.
And, similarly, the US might go on to a different time.
So this all gets quite tricky.
And, fortunately, we don't have to handle this
in our code ourselves.
That's what pytz is for as well as a few other libraries.
The important part of this, though, is that
there is a central time zone,
and that's UTC, Universal Time Coordinated.
So this is the central time,
and all other time zones can be described
with UTC as a reference.
Well, really, any time zone can be described
with any other time zone as a reference.
But UTC is the central one,
doesn't have daylight savings enabled,
so it's always the same time.
CET, for example, the Central European time,
is UTC +1 and you write that as +01:00.
Whenever you see +01:00 at the end of a datetime,
that means that that datetime is one hour ahead of CET.
That means that datetime is one hour ahead of UTC.
For PST, for example, Pacific Standard Time,
you've got -6 hours,
so you would write -06:00.
Note that some time zones don't use :00.
They have 30 minutes more of an offset
over UTC than other time zones, or even 45 minutes.
So you can't assume that all time zones
are gonna be very regular, and so on.
Also, time zones can change
for any number of reasons, including political reasons.
So there is a central time zone database
that is generally kept up-to-date quite well,
and that is what we're gonna be using
to handle these time-zone transitions.
pytz uses the central time zone database,
so we are covered in that regard.
Let's look at how to get the current date in UTC.
The reason for this is because
if we are always working in UTC,
that makes our life a little bit easier.
We don't have to worry about whether,
when we are comparing two dates,
one of them is actually less than the other
even though it looks like it's more
because of daylight savings, and so forth.
So here's how we get the current date in UTC.
We simply do datetime.datetime.now,
we print the date today,
and we know that this gives us
the current date and time of your computer.
And notice that at the end of that printout
we don't have plus anything.
So there's no datetime information.
That means that we're working with a naive datetime object.
So if your datetime object knows the timezone
and the datetime time it represents,
then we call that an aware datetime object.
And if it doesn't have a time zone information,
we call that a naive object.
Here we've got an aware object.
We are again creating the datetime
using datetime.datetime.now,
but now we're passing the time zone datetime.timezone.utc.
And now you can see when we print it out
we have +00:00 at the end.
Also, Python knows that in my computer
we are in BST at the moment,
which is a +1 time zone or one hour ahead of UTC.
So when we're converting to UTC,
we go one hour backwards to five o'clock,
well, seven minutes past five.
So aware objects represent specific points in time.
Naive objects only make the suggestion of a point in time.
The reason for that is because
if I give you a naive datetime object,
you don't know where I generated it
and what time zone it represents.
So, therefore, it could mean yesterday
if you were in the US
or it could mean tomorrow if you were in Japan.
So naive data objects, not all that useful.
But aware datetime objects do have a lot of use.
Working in your code with naive datetime objects
can be dangerous because different parts
of your code base may think that, "Oh, if it doesn't have
"a time zone, it represents UTC time."
But some other parts might think
that it represents PST time.
And you'll end up with code that does different things
with that datetime.
It's almost always a good idea
to store time zone information in your datetime objects.
So here's how we can convert between time zones with pytz.
The pytz module comes with a whole database of time zones
that is accessible by their official names.
So here we are importing datetime and pytz
and then we are creating or getting the time zone
using US/Eastern.
That's the official name of the time zone,
and I'm gonna leave a link in the resources section
of this video linking you to the whole database.
So what does is essentially it let's pytz know
what we're working with in terms of a time zone.
Now we then go ahead and grab the current time
without any time zone information.
But this datetime object, assuming that my computer
is currently in US/Eastern time zone,
does represent the current US/Eastern time
because it's the current time of my computer.
So then what we'll do is we'll
convert the naive datetime to an aware one.
But that doesn't change the time.
It just adds the time zone information.
So you can see here, we grabbed the local time,
and we printed it out, and that's 11:47.
And then we did eastern.localize.
So that's the time zone we created .localise.
And we pass in the local_time.
And that gives us the exact same time,
but now it has this minus five there.
So, again, if my computer is currently in this time zone,
then this is how we convert a local time to that time zone.
The very important part, of course, is to make sure
that my computer is using this time zone.
The way to do that is to ask users
what time zone they were using
or potentially to store that in a database
beside the user information
or maybe a config file, et cetera.
Now that we have the localised date and time,
we can convert between time zones.
So here we've got more or less the same code.
We've got the Eastern time zone there.
We're grabbing the local time.
We're converting it to Eastern,
and we've got our Eastern time zone.
Now if we have another time zone,
for example, Europe/Amsterdam, we can do Eastern time,
that is, this time here .astimezone
and pass in the Amsterdam time zone.
And this is all part of pytz.
And what it's gonna do is it's going to change
the date and time so that this point in time, Eastern time,
is the same as it would be
if it had the Amsterdam time zone.
So it's gonna essentially go forward by six hours.
Note that this deals with daylight savings changes for you.
So if one of these time zones was using daylight savings
and the other one wasn't, for example,
then it's gonna take care of that.
If this looks a little bit complicated, don't worry.
We're gonna simplify it right for you in just a moment.
But first of all, let's look at how to use pytz
to get the UTC time.
We can do something like this.
We can grab datetime.datetime.now,
and that is the local time.
Or we can do datetime.datetime.now,
and then pass in a keyword argument,
tz for time zone, =pytz.utc.
And that is going to bring the time back one hour,
because at the moment I am in BST, as I mentioned.
So this is a way to get the current UTC time.
So you've got, really, two main things to think about.
The current user's time and time zone
and the central UTC time and time zone.
And here's how I recommend you work
with time zones in your apps.
First, you ask users for their local time,
or you use datetime.datetime.now.
And you also ask them for their time zone.
Then you use their time zone to localise the local time
so that you know, essentially, what point in time
that datetime is representing.
And then whenever you're working with a database,
what you're gonna do is you're gonna convert
that localised time into UTC.
And you're always gonna store UTC in your database.
So your database will always have UTC dates in it,
and you'll know that they are +00:00.
Then whenever you wanna go back and show the user a date,
you grab their local time,
and you convert the UTC time in your database to local time,
and you print it out and show them.
That way you only have to worry about time zones
when you are showing the user something
or getting something from them.
And you never have to worry about time zones
within your code because you'll always be working with UTC.
So here's how you can do this.
Assuming you've got user's time zone,
which, again, might be in a database or a config file,
you grab the datetime and you localise it into Eastern time
and you do user_date.astimezone with pytz.utc.
And that's gonna take their local time,
convert it into UTC,
and then you might save that into your database.
And to go the other way round,
well, you would do exactly the same,
but you would do user_date.astimezone eastern.
And that would give you the Eastern time equivalent.
Thank you, guys, for joining me in this video.
I hope this makes sense.
Again, we've got the ebook that has all of this covered
as well with the code examples and everything.
So you can read that and review it if anything's unclear.
Thank you, guys, for joining me.
Thanks for watching this video,
and I'll see you in the next one.