I found it difficult to understand how to handle time zones in Python, so this is an organized memo.
version information
There are the following two types of instances in the same class.
Aware and Naive Objects - datetime — Basic date and time types — Python 3.8.1rc1 documentation
TZ = JST-9
from datetime import datetime
from datetime import timezone
now = datetime.now()
print(now) # =>Now in Japan time
print(now.tzinfo) # => None
# Naive
now = datetime.utcnow()
print(now) # =>Time minus 9 hours from Japan time
print(now.tzinfo) # => None
# Naive
now = datetime.now(timezone.utc)
print(now) #At the time minus 9 hours"+00:00"With the notation
print(now.tzinfo) # => UTC
# Aware
from datetime import datetime
from datetime import timezone
unixtime = 1572764400
now = datetime.fromtimestamp(unixtime)
print(now) # =>Notation in Japan time of the moment represented by unix time
print(now.tzinfo) # => None
# Naive
now = datetime.utcfromtimestamp(unixtime)
print(now) #Time minus 9 hours=UTC notation of the moment represented by unix time
print(now.tzinfo) # => None
# Naive
now = datetime.fromtimestamp(unixtime, timezone.utc)
print(now) #At the time minus 9 hours"+00:00"With the notation
print(now.tzinfo)
# => UTC
# Aware
from datetime import datetime
from datetime import timedelta
now = datetime.now() # Naive
print(now) # =>Now in Japan time(No time zone information)
print(now - timedelta(hours = +9)) # =>Time minus 9 hours(No time zone information)
now = datetime.utcnow() # Naive
print(now) # =>I've pulled 9 hours now(No time zone information)
print(now + timedelta(hours = +9)) # =>Japan time plus 9 hours(No time zone information)
tzinfo
is an abstract class with the following information.
--Time zone name --Time offset value from UTC --Time offset value from UTC during daylight saving time
tzinfo - datetime — Basic date and time types — Python 3.8.1rc1 documentation
Use timezone
or pytz
as the concrete class. pytz
is not in the standard library and needs to be installed.
timezone
is a concrete class of tzinfo
with a fixed offset value. It is fixed and can be used as a time zone such as +09: 00, but it cannot be considered that the offset value changes depending on the date and time such as daylight saving time.
The pytz
package allows you to generate a concrete class of tzinfo
from a string like " Asia / Tokyo "
. It can be considered that the offset value with UTC changes depending on the date and time.
An example where the offset value changes depending on the date and time
--Summer time in North America, Europe, Australia, etc. --In 1995, a part of Kiribati advanced the 24-hour clock. --Returned the clock for one hour in Russia in 2014
pytz
is not a standard library and needs to be installed.
$ pip install pytz
timezone class
from datetime import datetime
from datetime import timedelta
from datetime import timezone
import pytz
dt = datetime.utcfromtimestamp(1572764400)
print(dt)
# => 2019-11-03 07:00:00
#1572764400 is 16:00 on the 3rd in Japan time
# timezone.utc has an offset value of 0 and no daylight savings time
utc = timezone.utc
print(utc.utcoffset(dt))
# => 0:00:00
print(utc.dst(dt))
# => None
#Instance of timezone class
tz8 = timezone(timedelta(hours=-8)) #Timezone representing 8 hours behind UTC
print(tz8.utcoffset(dt))
# => -1 day, 16:00:00
print(tz8.dst(dt))
# => None
#Offset value is for Japan time+9 hours with no daylight savings time
tokyo = pytz.timezone('Asia/Tokyo') #Japan time
print(tokyo.utcoffset(dt))
# => 9:00:00
print(tokyo.dst(dt))
# => 0:00:00
#At 7 o'clock on November 3rd in UTC, the offset value is in US Pacific time.-8 hours is not daylight saving time
lasvegas = pytz.timezone('America/Los_Angeles') #American Pacific Time
print(lasvegas.utcoffset(dt))
# => -1 day, 16:00:00
print(lasvegas.dst(dt))
# => 0:00:00
#The day before, the offset value was in US Pacific time-7 hours is daylight saving time
print(lasvegas.utcoffset(dt - timedelta(days = 1)))
# => -1 day, 17:00:00
print(lasvegas.dst(dt - timedelta(days = 1)))
# => 1:00:00
If you use astimezone for a Naive datetime instance without timezone information, it will be converted from the local environment timezone to the specified timezone. After conversion, it becomes an Aware instance.
from datetime import datetime
from datetime import timedelta
from datetime import timezone
import pytz
dt = datetime.utcfromtimestamp(1572764400)
print(dt)
# => 2019-11-03 07:00:00
#1572764400 is 16:00 on the 3rd in Japan time
#dt is an instance created in UTC at 7 o'clock on the 3rd,
#Because it is a Naive instance with no timezone information
#It will be converted to the specified time zone as 7 o'clock on the 3rd of Japan time.
tokyo = pytz.timezone('Asia/Tokyo') #Japan time
print(dt.astimezone(tokyo))
# => 2019-11-03 07:00:00+09:00
#Since the local PC environment is Japan time, the time does not change
lasvegas = pytz.timezone('America/Los_Angeles') #American Pacific Time
print(dt.astimezone(lasvegas))
# => 2019-11-02 15:00:00-07:00
#7 o'clock on November 3rd, Japan time is 16 hours behind Japan in daylight saving time in Pacific time.
tz8 = timezone(timedelta(hours=-8)) #Timezone representing 8 hours behind UTC
print(dt.astimezone(tz8))
# => 2019-11-02 14:00:00-08:00
If you use astimezone for an Aware datetime instance with timezone information, the original timezone will be converted to the specified timezone. It will continue to be an Aware instance after conversion.
# dt.replace(tzinfo=utc)Only the time zone information is added without changing the values of year, month, day, hour, minute, and second.
print(dt.replace(tzinfo=utc).astimezone(tokyo))
# => 2019-11-03 16:00:00+09:00
print(dt.replace(tzinfo=utc).astimezone(lasvegas))
# => 2019-11-03 00:00:00-07:00
print(dt.replace(tzinfo=utc).astimezone(tz8))
# => 2019-11-02 23:00:00-08:00
Let's take a look at the conversion from UTC to Pacific Time at the end of daylight saving time.
from datetime import datetime
import pytz
lasvegas = pytz.timezone('America/Los_Angeles') #American Pacific Time
for i in range(7):
dt = datetime.utcfromtimestamp(1572764400 + i * 1800)
#1572764400 is UTC at 7:00 on the 3rd
print(dt.replace(tzinfo=utc).astimezone(lasvegas))
# =>
# 2019-11-03 00:00:00-07:00
# 2019-11-03 00:30:00-07:00
# 2019-11-03 01:00:00-07:00
# 2019-11-03 01:30:00-07:00
# 2019-11-03 01:00:00-08:00 <-Time returns at the end of daylight saving time
# 2019-11-03 01:30:00-08:00
# 2019-11-03 02:00:00-08:00
If you use dt.replace (tzinfo = tokyo)
or datetime (2019, 11, 3, 1, 0, 0, tzinfo = tokyo)
in the timezone object generated from pytz
, 19 There is a problem that can be understood. It is 19 minutes off in Japan time, but 7 minutes off in US Pacific time.
from datetime import datetime
from datetime import timedelta
from datetime import timezone
import pytz
dt = datetime.utcfromtimestamp(1572742800)
print(dt)
# => 2019-11-03 01:00:00
#1572764400 is 1:00 on the 3rd in Japan time
utc = timezone.utc
print(dt.replace(tzinfo=utc))
# => 2019-11-03 01:00:00+00:00
If you set replace (tzinfo = utc)
to an instance of Naive datetime, it will change to an Aware instance with the information of +00: 00
. If you specify Japan time instead of ʻutc`,
tokyo = pytz.timezone('Asia/Tokyo') #Japan time
print(dt.replace(tzinfo=tokyo))
# => 2019-11-03 01:00:00+09:19
For some reason, the time difference is off by 19 minutes.
There is no problem if you use the method localize
. I'm not sure what's different.
print(tokyo.localize(dt))
# => 2019-11-03 01:00:00+09:00
Even if I try it in US Pacific time, the deviation width is different, but it is still the same.
lasvegas = pytz.timezone('America/Los_Angeles') #American Pacific Time
print(dt.replace(tzinfo=lasvegas))
# => 2019-11-03 01:00:00-07:53
print(lasvegas.localize(dt))
# => 2019-11-03 01:00:00-08:00
The 3rd day of US Pacific time is the day when daylight saving time ends, and as shown in the example above, when the time is listed every 30 minutes, the time flows as follows.
2019-11-03 00:00:00-07:00 2019-11-03 00:30:00-07:00 2019-11-03 01:00:00-07:00 2019-11-03 01:30:00-07:00 2019-11-03 01: 00: 00-08: 00 <-Time returns at the end of daylight saving time 2019-11-03 01:30:00-08:00 2019-11-03 02:00:00-08:00
It goes around twice from 1:00 to 1:59. In other words, there is ambiguity that it is not possible to tell whether it is the first time or the second time from the information of 1 o'clock.
With this fact in mind, try localize
.
from datetime import datetime
from datetime import timedelta
from datetime import timezone
import pytz
dt = datetime.utcfromtimestamp(1572742800)
print(dt)
# => 2019-11-03 01:00:00
#dt is a Naive instance at 1 o'clock on the 3rd
lasvegas = pytz.timezone('America/Los_Angeles') #American Pacific Time
print(lasvegas.localize(dt))
# => 2019-11-03 01:00:00-08:00
#The second 1 o'clock was returned
By the way, if you calculate 1 hour before 1 o'clock for the second time, it will be 0 o'clock. It should be summer time at midnight, but it remains winter time.
print(lasvegas.localize(dt) - timedelta(hours=1))
# => 2019-11-03 00:00:00-08:00
If you calculate 1 hour ago for a Naive instance before localize
and then localize
, it will be midnight daylight saving time. This is 2 hours before the second 1 o'clock.
print(lasvegas.localize(dt - timedelta(hours=1)))
# => 2019-11-03 00:00:00-07:00
that's all.
Recommended Posts