舊金山灣區時間與北京時間轉換,用python實現時區轉換例子

San Francisco Time ??

Beijing Time ??

把一個時區的時間,比如灣區9:00am,轉換成另一個時區的時間,比如北京/香港/新加坡時間,應該是很簡單的問題。用Python做時區轉換好像挺麻煩的,容易出錯。Google出來的前幾條結果都不是很讓人滿意,本文總結我測試過可靠可行不太複雜的方法,以及一些容易出錯的地方。

先上可行的Python例子,把三藩(SF)灣區時間9am, 轉換成對應的北京時間,用了datetimepytz。先構造一個灣區時間的對象,然後轉化成北京/香港/新加坡時間。

from pytz import timezone
from datetime import datetime

bjtz = timezone('Asia/Harbin')
sftz = timezone('US/Pacific')

dt9amsf = sftz.localize(datetime(2022, 7, 11, 9, 0))
dt9amsf2bj = dt9amsf.astimezone(bjtz)

加上註解和debug信息。

from pytz import timezone
from datetime import datetime

format = '%Y-%m-%d %H:%M:%S %Z %z'

bjtz = timezone('Asia/Harbin')
sftz = timezone('US/Pacific')

# construct SF 9am datetime object
dt9amsf = sftz.localize(datetime(2022, 7, 11, 9, 0))

# for debug
print(dt9amsf.strftime(format)) # 2022-07-11 09:00:00, 09:00AM PDT -0700
print(dt9amsf.timestamp()) #1657555200.0

# Convert to Beijing time
dt9amsf2bj = dt9amsf.astimezone(bjtz)
# debug
print(dt9amsf2bj.strftime(format)) #2022-07-12 00:00:00, 12:00AM CST +0800

可以看到建立的灣區時間時區為-0700而北京時間為0800,可以驗證灣區和中國時差為15小時。

時區行話解釋

全球標準時間用的是位於英國的格林威治時間(GMT, Greenwich Mean Time)。因為以前格林威治天文台是世界中心,本初子午線或者0度經線就定義為穿過它的經線。然後又有了一個叫世界協調時間的東西(UTC, Coordinated Universal Time)。這個和GMT基本一致,大概就是北京話和普通話的區別吧。北京在Greenwich的東邊,時間領先GMT/UTC 8小時,所以叫東八區,代號0800。而灣區在格林威治的西邊,時間滯後7個小時(美國國會通過了永久使用夏令時法案),所以叫西7區,代號-0700。而兩地時差為7+9=15,北京時間比灣區時間領先15個小時。

同理,日本和韓國位於東9區,代號為0900,那麼時間就比為與東八區的中國早1小時。

當地真實時間和約定標準時間

一個地方的真實時間只取決於太陽相對當地的位置,也就是取決於當地經度。但是為了方便,每個國家可以人為規定用什麼時間。比如整個中國雖然跨了幾個緯度,確人為規定了各地都使用北京時間。新加坡真實時間應該為0655,確規定使用0800,也許是和大中華區保持一致比較方便。

回到Python上,這也正是pytz包的一些坑的來源。pytz用的是地理意義上的真實時間,而人們真正使用的是當地法律約定的時間,這兩者是有差別的。

Python datetime不設時區是什麼時間?

如果新建一個datetime對象,不設時區的話,會是當地時間。

from datetime import datetime

dt = datetime(2022, 7, 1)
format = '%Y-%m-%d %H:%M:%S %Z %z'
print(dt.strftime(format)) # => '2022-07-01 00:00:00  ' time zone missing
print(dt.timestamp()) # => 1656658800.0

epochconverter轉換1656658800.0,正是灣區時間2022-07-01 00:00:00

如果replace了timezone,就把底下的timestamp變了,而不是保持timestamp而改變時間表示形式(日期,小時/分/秒)。所以replace(tzinfo=…)並不是做時區變換。而且注意下面例子里上海時間是0806,並不是0800,應該用了地理意義上的真實時間而不是法定時間。這個地理時間在生活中基本沒用,這個pytz的坑之一。

bjdt = dt.replace(tzinfo=bjtz) # bjdt is datetime.datetime(2022, 7, 1, 0, 0, tzinfo=<DstTzInfo 'Asia/Harbin' LMT+8:06:00 STD>), dt itself is not changed
print(bjdt.strftime(format)) # => '2022-07-01 00:00:00 LMT +0806'
bjdt.timestamp() # => 1656604440.0

參考

Leave a Comment

Your email address will not be published.