濮阳杆衣贸易有限公司

主頁(yè) > 知識(shí)庫(kù) > 淺談Python3中datetime不同時(shí)區(qū)轉(zhuǎn)換介紹與踩坑

淺談Python3中datetime不同時(shí)區(qū)轉(zhuǎn)換介紹與踩坑

熱門標(biāo)簽:成都呼叫中心外呼系統(tǒng)哪家強(qiáng) 南昌地圖標(biāo)注 百應(yīng)電話機(jī)器人總部 地圖標(biāo)注與注銷 無(wú)錫智能外呼系統(tǒng)好用嗎 宿州電話機(jī)器人哪家好 電梯新時(shí)達(dá)系統(tǒng)外呼顯示e 旅游廁所地圖標(biāo)注怎么弄 西青語(yǔ)音電銷機(jī)器人哪家好

最近的項(xiàng)目需要根據(jù)用戶所屬時(shí)區(qū)制定一些特定策略,學(xué)習(xí)、應(yīng)用了若干python3的時(shí)區(qū)轉(zhuǎn)換相關(guān)知識(shí),這里整理一部分記錄下來(lái)。

下面涉及的幾個(gè)概念及知識(shí)點(diǎn):

GMT時(shí)間:Greenwich Mean Time, 格林尼治平均時(shí)間

UTC時(shí)間:Universal Time Coordinated 世界協(xié)調(diào)時(shí),可以認(rèn)為是更精準(zhǔn)的GMT時(shí)間,但兩者誤差極小,在1s以內(nèi),一般可視為等同

LMT:Local Mean Time, 當(dāng)?shù)貥?biāo)準(zhǔn)時(shí)間

Python中的北京時(shí)間:Python的標(biāo)準(zhǔn)timezone中信息中并沒有Asia/Beijing,原因要追溯到國(guó)民政府期間上報(bào)給國(guó)際標(biāo)準(zhǔn)的五個(gè)時(shí)區(qū)城市沒有北京,因此一般使用Asia/Shanghai獲取東8區(qū)時(shí)間

Python使用到的時(shí)間相關(guān)函數(shù)及概念:

包含時(shí)區(qū)信息的datetime稱為: offset-aware datetime,反之稱為offset-naive datetime

pytz.timezone(x): pytz package中預(yù)定義的時(shí)區(qū)相關(guān)對(duì)象, pytz可通過(guò) python3 -m pip install pytz 安裝

datetime(...) : 直接指定year/month/day/hour/second生成naive datetime

datetime(...tzinfo=tz) : 直接指定year/month/day/hour/second+時(shí)區(qū)信息生成offset-aware datetime

datetime.now(): 生成當(dāng)前默認(rèn)時(shí)區(qū)的 naive datetime

datetime.now(tzinfo=tz): 生成指定時(shí)區(qū)的offset-aware datetime

datetime.strptime(string, format) : 生成當(dāng)前默認(rèn)時(shí)區(qū)的string、format表示的 naive datetime

datetime.replace(tzinfo=tz): 直接替換datetime 時(shí)區(qū)信息為tz時(shí)區(qū)offset-aware datetime--不針對(duì)時(shí)區(qū)進(jìn)行任何轉(zhuǎn)換

datetime.astimezone(tz): 將時(shí)間轉(zhuǎn)換為新的tz時(shí)區(qū)的offset-aware datetime

下述代碼示例中,由于云主機(jī)位于日本,所以默認(rèn)時(shí)區(qū)為東9區(qū)(Asia/Tokyo)

Python中獲取當(dāng)前時(shí)刻時(shí)間:

In [1]: import pytz

In [2]: from datetime import datetime, timedelta

In [3]: datetime.now() # 默認(rèn)時(shí)區(qū)當(dāng)前時(shí)間
Out[3]: datetime.datetime(2021, 8, 1, 18, 36, 8, 352873)

In [4]: datetime.now(pytz.timezone('Asia/Tokyo')) # 指定Tokyo時(shí)區(qū)當(dāng)前時(shí)間
Out[4]: datetime.datetime(2021, 8, 1, 18, 36, 25, 421048, tzinfo=DstTzInfo 'Asia/Tokyo' JST+9:00:00 STD>)

可以看到,datetime.now()未指定時(shí)區(qū)時(shí),獲取到的對(duì)象是offset-navie datetime,而指定時(shí)區(qū)后則是offset-aware datetime,naive和aware的datetime是不可以執(zhí)行比較、相減相關(guān)操作的,只有同類型的datetime才能求時(shí)間差值、比較大小,如下:

In [5]: datetime.now() - datetime.now(pytz.timezone('Asia/Tokyo'))
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
ipython-input-5-8b6c111dc5de> in module>
----> 1 datetime.now() - datetime.now(pytz.timezone('Asia/Tokyo'))

TypeError: can't subtract offset-naive and offset-aware datetimes

In [6]: datetime.now() - datetime.now() # 只有同樣的offset-naive datetime才能求差值
Out[6]: datetime.timedelta(days=-1, seconds=86399, microseconds=999991)
In [8]: datetime.now(pytz.timezone('Asia/Tokyo')) - datetime.now(pytz.timezone('Asia/Tokyo')) # 同樣的offset-aware datetime才能求差值
Out[8]: datetime.timedelta(days=-1, seconds=86399, microseconds=999976)

這里碰到了第一個(gè)坑,比如我們想獲得北京時(shí)間2021年1月1日0點(diǎn)的datetime,然后將其轉(zhuǎn)換為東京時(shí)間,直覺上我們很可能這么寫:

In [19]: datetime(2021, 1, 1, tzinfo=pytz.timezone('Asia/Shanghai')) # 這里獲取北京時(shí)間20210101 0點(diǎn)的datetime
Out[19]: datetime.datetime(2021, 1, 1, 0, 0, tzinfo=DstTzInfo 'Asia/Shanghai' LMT+8:06:00 STD>) # 注意獲取的是LMT時(shí)間
In [21]: datetime(2021, 1, 1, tzinfo=pytz.timezone('Asia/Shanghai')).astimezone(pytz.timezone('Asia/Tokyo')) # 將北京時(shí)轉(zhuǎn)換為東京時(shí)間
Out[21]: datetime.datetime(2021, 1, 1, 0, 54, tzinfo=DstTzInfo 'Asia/Tokyo' JST+9:00:00 STD>) # 獲取的是日本標(biāo)準(zhǔn)時(shí)間JST+9
In [22]: datetime.now(pytz.timezone('Asia/Shanghai')) # 示例獲取當(dāng)前時(shí)刻北京時(shí)間
Out[22]: datetime.datetime(2021, 8, 1, 18, 11, 6, 706727, tzinfo=DstTzInfo 'Asia/Shanghai' CST+8:00:00 STD>) # 獲取的是中國(guó)標(biāo)準(zhǔn)時(shí)間(CST+8)

仔細(xì)一看,北京時(shí)間的0點(diǎn)轉(zhuǎn)化為東京時(shí)間卻是0:54,相差是54分鐘,而不是1個(gè)小時(shí),這就奇怪了,仔細(xì)一看tzinfo中的信息是LMT+8:06:00 STD,表示這是LMT時(shí)間,相比UTC快8小時(shí)6分鐘,而不是東8區(qū)標(biāo)準(zhǔn)時(shí)間,而通過(guò)astimezone方法轉(zhuǎn)換后得到的就是日本標(biāo)準(zhǔn)時(shí)間(東9區(qū)),所以兩者之前的差值并不是1小時(shí)整。

第一個(gè)坑究其原因,通過(guò)datetime(..tzinfo=..)指定時(shí)區(qū)獲取的是LMT,而datetime.now(tz)、datetime.astimezone(tz) 獲取的卻是UTC(GMT)標(biāo)準(zhǔn)時(shí)間,LMT和GMT標(biāo)準(zhǔn)時(shí)間可能會(huì)有甚至十分鐘級(jí)的差值,這已經(jīng)足夠影響到程序的正常邏輯了。

 所以如果要保證獲取標(biāo)準(zhǔn)時(shí)區(qū)的時(shí)間,建議避免使用Asia/Shanghai、Asia/Tokyo這類大洲/城市 字符串表示時(shí)間,而使用GMT、UTC這些無(wú)歧義的標(biāo)準(zhǔn)時(shí)區(qū),如下:

In [45]: datetime(2021, 1, 1, tzinfo=pytz.timezone('Etc/GMT-9'))
Out[45]: datetime.datetime(2021, 1, 1, 0, 0, tzinfo=StaticTzInfo 'Etc/GMT-9'>) # 東9區(qū)應(yīng)使用GMT-9

這里第二個(gè)坑出現(xiàn)了,由于歷史原因,Python中timezone的表示中,時(shí)區(qū)偏移以西為正,以東為負(fù),和我們熟悉的ISO標(biāo)準(zhǔn)剛好相反,所以東9區(qū)應(yīng)該表示為Etc/GMT-9, 而Etc/GMT+9表示的其實(shí)是西9區(qū),如下可以驗(yàn)證GMT-9與JST相差0, GMT+9與JST相差18小時(shí)(64800s):

In [50]: datetime(2021, 1, 1, tzinfo=pytz.timezone('Etc/GMT-9')) - datetime(2021, 1, 1).astimezone(pytz.timezone('Asia/Tokyo'))
Out[50]: datetime.timedelta(0)

In [51]: datetime(2021, 1, 1, tzinfo=pytz.timezone('Etc/GMT+9')) - datetime(2021, 1, 1).astimezone(pytz.timezone('Asia/Tokyo'))
Out[51]: datetime.timedelta(seconds=64800)

最后,獲取指定時(shí)區(qū)2021年1月1日datetime的方式,以北京時(shí)間為例:

In [56]: datetime(2021, 1, 1, tzinfo=pytz.timezone('Etc/GMT-8'))
Out[56]: datetime.datetime(2021, 1, 1, 0, 0, tzinfo=StaticTzInfo 'Etc/GMT-8'>)
In [58]: datetime(2021, 1, 1, tzinfo=pytz.timezone('Etc/GMT-8')).astimezone(pytz.timezone('Asia/Shanghai'))
Out[58]: datetime.datetime(2021, 1, 1, 0, 0, tzinfo=DstTzInfo 'Asia/Shanghai' CST+8:00:00 STD>) # 可見GMT-8和東八區(qū)標(biāo)準(zhǔn)時(shí)間(CST+8)一致

進(jìn)一步如果要獲取指定時(shí)區(qū)零點(diǎn)的時(shí)間戳就很簡(jiǎn)單了:

In [44]: datetime(2021, 1, 1, tzinfo=pytz.timezone('Etc/GMT0')).timestamp() # 獲取格林尼治時(shí)區(qū)2021年1月1日0點(diǎn)時(shí)間戳
Out[44]: 1609459200.0

另外兩種獲取指定時(shí)區(qū)時(shí)刻的方法,此三種方式彼此等價(jià):

In [51]: datetime(2021, 1, 1, tzinfo=pytz.timezone('Etc/GMT0')) == datetime(2021, 1, 1).replace(tzinfo=pytz.timezone('Etc/GMT0'))
Out[51]: True
In [53]: datetime(2021, 1, 1, tzinfo=pytz.timezone('Etc/GMT0')) == datetime.strptime('20210101', '%Y%m%d').replace(tzinfo=pytz.timezone('Etc/GMT0'))

到此這篇關(guān)于淺談Python3中datetime不同時(shí)區(qū)轉(zhuǎn)換介紹與踩坑的文章就介紹到這了,更多相關(guān)Python3 datetime不同時(shí)區(qū)轉(zhuǎn)換 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

您可能感興趣的文章:
  • Python time.time()方法
  • 一篇文章帶你了解python標(biāo)準(zhǔn)庫(kù)--time模塊
  • 一篇文章帶你了解python標(biāo)準(zhǔn)庫(kù)--datetime模塊
  • python標(biāo)準(zhǔn)庫(kù)之time模塊的語(yǔ)法與簡(jiǎn)單使用
  • python常見模塊之OS模塊和time模塊
  • Python time庫(kù)的時(shí)間時(shí)鐘處理
  • python語(yǔ)言time庫(kù)和datetime庫(kù)基本使用詳解
  • 關(guān)于python time庫(kù)整理匯總

標(biāo)簽:西安 贛州 辛集 渭南 許昌 雅安 濰坊 七臺(tái)河

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《淺談Python3中datetime不同時(shí)區(qū)轉(zhuǎn)換介紹與踩坑》,本文關(guān)鍵詞  淺談,Python3,中,datetime,不同,;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問題,煩請(qǐng)?zhí)峁┫嚓P(guān)信息告之我們,我們將及時(shí)溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無(wú)關(guān)。
  • 相關(guān)文章
  • 下面列出與本文章《淺談Python3中datetime不同時(shí)區(qū)轉(zhuǎn)換介紹與踩坑》相關(guān)的同類信息!
  • 本頁(yè)收集關(guān)于淺談Python3中datetime不同時(shí)區(qū)轉(zhuǎn)換介紹與踩坑的相關(guān)信息資訊供網(wǎng)民參考!
  • 推薦文章
    同心县| 敦化市| 醴陵市| 武陟县| 临桂县| 马尔康县| 普陀区| 永和县| 扎赉特旗| 来宾市| 遂宁市| 罗江县| 边坝县| 老河口市| 延寿县| 沙雅县| 石渠县| 阜阳市| 道真| 广西| 扎赉特旗| 华容县| 若羌县| 建德市| 白玉县| 江津市| 阿克陶县| 宁武县| 河间市| 云浮市| 涟源市| 老河口市| 香港| 桂阳县| 汤阴县| 万宁市| 忻州市| 玛纳斯县| 扎赉特旗| 长兴县| 丽江市|