San Francisco Time ??
Beijing Time ??
把一個時區的時間,比如灣區9:00am,轉換成另一個時區的時間,比如北京/香港/新加坡時間,應該是很簡單的問題。用Python做時區轉換好像挺麻煩的,容易出錯。Google出來的前幾條結果都不是很讓人滿意,本文總結我測試過可靠可行不太複雜的方法,以及一些容易出錯的地方。
先上可行的Python例子,把三藩(SF)灣區時間9am, 轉換成對應的北京時間,用了datetime
和pytz
。先構造一個灣區時間的對象,然後轉化成北京/香港/新加坡時間。
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
參考
- Python3中datetime時區轉換介紹與踩坑
- python datetime時區轉換
- 技巧:用datetime模塊處理時區轉換,不要用time模塊
- 將UTC、EST時區的時間轉化成北京時間(python)
- pytz庫時區的坑(轉)
- The Solution to the Problem of Pyrtz Formatting Beijing Time Over 6 Minutes
- Python 時間處理 時區的轉換 時間的計算
- 【Python】python獲取國內時間及其時區 pytz模塊的使用
- Making sense of timezones in Python
- pytz – World Timezone Definitions for Python
- List of time zones – countryinfo.py on github
- List All TimeZones in Python
- 「how to convert time from one timezone to another in python」 Code Answer』s. 這個只有now到其他時區時間,沒有任意時間