學習《Python Cookbook》第三版
你有一個安排在2021年3月21日早上9:30的電話會議,地點在上海。而你的朋友在芝加哥,那麼他應該在當地時間幾點參加這個會議呢?
對幾乎所有涉及到時區的問題,你都應該使用 pytz 模組。這個包提供了 Olson 時區資料庫,它是時區資訊的事實上的標準,在很多語言和作業系統裡面都可以找到。
關於Olson的介紹,可以檢視維基百科:https://en.wikipedia.org/wiki/Tz_database
pytz 模組一個主要用途是將 datetime 庫建立的簡單日期物件本地化。比如,下面如何表示一個芝加哥時間的示例:
from datetime import datetime, timedelta, datefrom pytz import timezonecat = datetime(2021, 3, 21, 9, 30, 0)print(cat) # "2021-03-21 09:30:00"own = timezone('Asia/Shanghai')loc_cat = own.localize(cat)print(loc_cat) # "2021-03-21 09:30:00+08:00"
一旦日期被本地化了,它就可以轉換為其他時區的時間了。為了得到芝加哥對應的時間,你可以這樣做:
chicago_cat = loc_cat.astimezone(timezone('America/Chicago'))print(chicago_cat) # "2021-03-20 20:30:00-05:00"
如果你打算在本地化日期上執行計算,你需要特別注意夏令時轉換和其他細節。比如,在2018年,美國標準夏令時時間開始於本地時間3月11日凌晨2:00(在那時,時間向前跳過一小時)。如果你正在執行本地計算,你會得到一個錯誤。比如:
d = datetime(2018, 3, 11, 1, 45, 0)print(d) # "2018-03-11 01:45:00"central = timezone('America/Chicago')loc_d = central.localize(d)print(loc_d) # "2018-03-11 01:45:00-06:00"later = loc_d + timedelta(minutes=30)print(later) # "2018-03-11 02:15:00-06:00"
結果錯誤是因為它並沒有考慮在本地時間中有一小時的跳躍。為了修正這個錯誤,可以使用時區物件 normalize() 方法。比如:
later = central.normalize(loc_d + timedelta(minutes=30))print(later) # "2018-03-11 03:15:00-05:00"
更多的年份的夏令時時間可以檢視: https://www.timeanddate.com/time/zone/usa/chicago
為了不讓你被這些東東弄的暈頭轉向,處理本地化日期的通常的策略先將所有日期轉換為 UTC 時間,並用它來執行所有的中間儲存和操作。比如:
import pytzfrom pytz import timezonecat = datetime(2018, 3, 11, 1, 45, 0)print(cat) # "2018-03-11 01:45:00"chicago_zone = timezone('America/Chicago')chicago_cat = chicago_zone.localize(cat)print(chicago_cat) # "2018-03-11 01:45:00-06:00"utc_chicago = chicago_cat.astimezone(pytz.utc)print(utc_chicago) # "2018-03-11 07:45:00+00:00"
一旦轉換為 UTC,你就不用去擔心跟夏令時相關的問題了。因此,你可以跟之前一樣放心的執行常見的日期計算。當你想將輸出變為本地時間的時候,使用合適的時區去轉換下就行了。比如:
later_utc_chicago = utc_chicago + timedelta(minutes=30)print(later_utc_chicago.astimezone(chicago_zone)) # "2018-03-11 03:15:00-05:00"
當涉及到時區操作的時候,有個問題就是我們如何得到時區的名稱。比如,在這個例子中,我們如何知道“America/Chicago”就是芝加哥對應的時區名呢?為了查詢,可以使用 ISO 3166 國家程式碼作為關鍵字去查閱字典 pytz.country_timezones 。比如:
print(pytz.country_timezones['US'])"""['America/New_York', 'America/Detroit', 'America/Kentucky/Louisville', ...]"""
更多的時區區名可以檢視: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones