Python 的6個日期時間庫


曾幾何時,我們中的一個人(Lacey)盯了一個多小時的python文檔中描述日期和時間格式化字符串的表格。當我試圖編寫從 API 中將日期時間字符串轉換為Python datetime對象時,我很難理解其中的特定部分,因此我決定請求幫助。
有人問道:“為什么你不使用 dateutil 呢?”
讀者,如果你沒有從這個月的 Python 專欄中獲得任何東西,只是學習到有比 datetime 的 strptime 更容易地將 datetime 字符串轉換為 datetime 對象的方法,那么我們覺得就已經成功了。
但是,除了將字符串轉換為更有用的 Python 對象之外,還有許多庫都有一些有用的方法和工具,可以讓您更輕松地進行時間測試、將時間轉換為不同的時區、以人類可讀的格式傳遞時間信息,等等。如果這是你在 Python 中第一次接觸日期和時間,請暫停並閱讀如何使Python的日期和時間 。要理解為什么在編程中處理日期和時間是困難的,請閱讀 《愚蠢的程序員相信時間》
隨意跳過那些你已經熟悉的庫,專注於那些對你而言是新的庫。
內建的 datetime 模塊
在跳轉到其他庫之前,讓我們回顧一下如何使用 datetime 模塊將日期字符串轉換為 Python datetime 對象。
假設我們從 API 接受到一個日期字符串,並且需要它作為 Python datetime 對象存在:

1 22018-11-29T17:45:25Z

這個字符串包括:
日期是 YYYY-MM-DD 格式的
字母 T 表示時間即將到來
時間是 HH:II:SS 格式的
表示此時間的時區指示符 Z 采用 UTC (詳細了解日期時間字符格式)
要使用 datetime 模塊將此字符串轉換為 Python datetime 對象,你應該從 strptime 開始。 datetime.strptime 接受日期字符串和格式化字符並返回一個 Python datetime 對象。
我們必須手動將日期時間字符串的每個部分轉換為 Python 的 datetime.strptime 可以理解的合適的格式化字符串。四位數年份由 %Y 表示,兩位數月份是 %m,兩位數的日期是 %d。在 24 小時制中,小時是 %H,分鍾是 %M,秒是 %S。
為了得出這些結論,需要在Python 文檔的表格中多加注意。
由於字符串中的 Z 表示此日期時間字符串采用 UTC,所以我們可以在格式中忽略此項。(現在,我們不會擔心時區。)
轉換的代碼是這樣的:

1 4$ from datetime import datetime 
2 $ datetime.strptime('2018-11-29T17:45:25Z', '%Y-%m-%dT%H:%M:%SZ')
3 datetime.datetime(2018, 11, 29, 17, 45, 25)

格式字符串很難閱讀和理解。我必須手動計算原始字符串中的字母 T 和 “Z”的位置,以及標點符號和格式化字符串,如 %S 和 %m。有些不太了解 datetime 的人閱讀我的代碼可能會發現它很難理解,盡管其含義已有文檔記載,但它仍然很難閱讀。
讓我們看看其他庫是如何處理這種轉換的。
Dateutil
dateutil 模塊對 datetime 模塊做了一些擴展。
繼續使用上面的解析示例,使用 dateutil 實現相同的結果要簡單得多:

1 4$ from dateutil.parser import parse
2 $ parse('2018-11-29T17:45:25Z')
3 datetime.datetime(2018, 11, 29, 17, 45, 25, tzinfo=tzutc())

如果字符串包含時區,那么 dateutil 解析器會自動返回字符串的時區。由於我們在 UTC 時區,你可以看到返回來一個 datetime 對象。如果你想解析完全忽略時區信息並返回原生的 datetime 對象,你可以傳遞 ignoretz=True 來解析,如下所示:

1 4$ from dateutil.parser import parse
2 $ parse('2018-11-29T17:45:25Z', ignoretz=True)
3 datetime.datetime(2018, 11, 29, 17, 45, 25)

dateutil 還可以解析其他人類可讀的日期字符串:

1 3$ parse('November 29th, 2018 at 5:45 pm')
2 datetime.datetime(2018, 11, 29, 17, 45)

dateutil 還提供了像 relativedelta 的工具,它用於計算兩個日期時間之間的時間差或向日期時間添加或刪除時間,rrule 創建重復日期時間,tz 用於解決時區以及其他工具。
Arrow
Arrow 是另一個庫,其目標是操作、格式化,以及處理對人類更友好的日期和時間。它包含 dateutil,根據其文檔,它旨在“幫助你使用更少的包導入和更少的代碼來處理日期和時間”。
要返回我們的解析示例,下面介紹如何使用 Arrow 將日期字符串轉換為 Arrow 的 datetime 類的實例:

1 4$ import arrow 
2 $ arrow.get('2018-11-29T17:45:25Z')
3 <Arrow [2018-11-29T17:45:25+00:00]>

你也可以在 get() 的第二個參數中指定格式,就像使用 strptime 一樣,但是 Arrow 會盡力解析你給出的字符串,get() 返回 Arrow 的 datetime 類的一個實例。要使用 Arrow 來獲取 Python datetime 對象,按照如下所示鏈式 datetime:

1 3$ arrow.get('2018-11-29T17:45:25Z').datetime
2 datetime.datetime(2018, 11, 29, 17, 45, 25, tzinfo=tzutc())

通過 Arrow datetime 類的實例,你可以訪問 Arrow 的其他有用方法。例如,它的 humanize() 方法將日期時間翻譯成人類可讀的短語,就像這樣:

1 5$ import arrow
2 $ utc = arrow.utcnow()
3 $ utc.humanize()
4 'seconds ago'

在 Arrow 的文檔中閱讀更多關於其有用方法的信息。
Moment
Moment 的作者認為它是“內部測試版”,但即使它處於早期階段,它也是非常受歡迎的,我們想來討論它。
Moment 的方法將字符轉換為其他更有用的東西很簡單,類似於我們之前提到的庫:

1 4$ import moment
2 $ moment.date('2018-11-29T17:45:25Z')
3 <Moment(2018-11-29T17:45:25)>

就像其他庫一樣,它最初返回它自己的 datetime 類的實例,要返回 Python datetime 對象,添加額外的 date() 調用即可。

1 3$ moment.date('2018-11-29T17:45:25Z').date
2 datetime.datetime(2018, 11, 29, 17, 45, 25, tzinfo=<StaticTzInfo 'Z'>)

這將 Moment datetime 類轉換為 Python datetime 對象。
Moment 還提供了使用人類可讀的語言創建新日期的方法。例如創建一個明天的日期:

1 3$ moment.date("tomorrow")
2 <Moment(2018-11-06T11:24:42)>

它的 add() 和 subtract() 命令使用關鍵字參數來簡化日期的操作。為了獲得后天,Moment 會使用下面的代碼:

1 3$ moment.date("tomorrow").add(days=1)
2 <Moment(2018-11-07T11:26:48)>

Maya
Maya 包含了 Python 中其他流行處理日期時間的庫,包括 Humanize、 pytz 和 pendulum 等等。這個項目旨在讓人們更容易處理日期。
Maya 的 README 包含幾個有用的實例。以下是如何使用 Maya 來重新處理以前的解析示例:

1 4$ import maya
2 $ maya.parse('2018-11-29T17:45:25Z').datetime()
3 datetime.datetime(2018, 11, 29, 17, 45, 25, tzinfo=<UTC>)

注意我們必須在 maya.parse() 之后調用 datetime()。如果我們跳過這一步,Maya 將會返回一個 MayaDT 類的示例:。
由於 Maya 與 datetime 庫中很多有用的方法重疊,因此它可以使用 MayaDT 類的實例執行諸如使用 slang_time() 方法將時間偏移量轉換為純文本語言,並將日期時間間隔保存在單個類的實例中。以下是如何使用 Maya 將日期時間表示為人類可讀的短語:

1 4$ import maya
2 $ maya.parse('2018-11-29T17:45:25Z').slang_time()
3 '23 days from now

顯然,slang_time() 的輸出將根據距離 datetime 對象相對較近或較遠的距離而變化。
Delorean
Delorean,以 《返回未來》 電影中的時間旅行汽車命名,它對於操縱日期時間特別有用,包括將日期時間轉換為其他時區並添加或減去時間。
Delorean 需要有效的 Python datetime 對象才能工作,所以如果你需要使用時間字符串,最好將其與上述庫中的一個配合使用。例如,將 Maya 與 Delorean 一起使用:

1 3$ import maya 
2 $ d_t = maya.parse('2018-11-29T17:45:25Z').datetime()

現在,你有了一個 datetime 對象 d_t,你可以使用 Delorean 來做一些事情,例如將日期時間轉換為美國東部時區:

1 7$ from delorean import Delorean
2 $ d = Delorean(d_t)
3 $ d
4 Delorean(datetime=datetime.datetime(2018, 11, 29, 17, 45, 25), timezone='UTC')
5 $ d.shift('US/Eastern')
6 Delorean(datetime=datetime.datetime(2018, 11, 29, 13, 45, 25), timezone='US/Eastern')

看到小時是怎樣從 17 變成 13 了嗎?
你也可以使用自然語言方法來操作 datetime 對象。獲取 2018 年 4 月 29 日之后的下個星期五(我們現在使用的):

1 3$ d.next_friday()
2 Delorean(datetime=datetime.datetime(2018, 5, 4, 13, 45, 25), timezone='US/Eastern')

在 Delorean 的文檔中閱讀更多關於其的用法。
Freezegun
Freezegun 是一個可以幫助你在 Python 代碼中測試特定日期的庫。使用 @freeze_time 裝飾器,你可以為測試用例設置特定的日期和時間,並且所有對 datetime.datetime.now()、 datetime.datetime.utcnow() 等的調用都將返回你指定的日期和時間。例如:

1 7from freezegun import freeze_time
2 import datetime
3  
4 @freeze_time("2017-11-14")
5 def test(): 
6  assert datetime.datetime.now() == datetime.datetime(2017, 11, 14)

要跨時區進行測試,你可以將 tz_offset 參數傳遞給裝飾器。freeze_time 裝飾器也接受更簡單的口語化日期,例如 @freeze_time(‘April 4, 2017’)。
上面提到的每個庫都提供了一組不同的特性和功能,也許很難決定哪一個最適合你的需要。Maya 的作者, Kenneth Reitz 說到:“所有這些項目相輔相成,它們都是我們的朋友”。
這些庫共享一些功能,但不是全部。有些擅長時間操作,有些擅長解析,但它們都有共同的目標,即讓你對日期和時間的工作更輕松。下次你發現自己對 Python 的內置 datetime 模塊感到沮喪,我們希望你可以選擇其中的一個庫進行試驗。
原文出處:Lacey Williams Henschel & Jeff Triplett 譯文出處:Linux中國/MjSeven


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM