Python 開發者長期以來一直在與標準庫的 datetime 模塊作鬥爭,儘管該模塊已經存在了二十多年,但它包含了許多陷阱和邊緣情況,即使是經驗豐富的程序員也可能會陷入其中。一個名為 Whenever 的新庫旨在通過提供類型安全、支持夏令時(DST)的替代方案來解決這些問題,該庫從其他語言中成熟的日期時間庫汲取了靈感。
關於 Whenever 的討論突顯了 Python 生態系統中的一個常見痛點:處理日期時間充滿了意外行為,可能導致生產代碼中出現微妙的錯誤。許多開發者對找到一個專門解決這些問題的庫表示欣慰,有幾位還分享了他們遇到的與日期時間相關的問題經歷。
標準庫的問題
Python 內置的 datetime 模塊因其對夏令時(DST)的處理和缺乏類型安全性而受到批評。最常被提及的問題之一是,在單一時區內執行算術運算時,datetime 無法正確處理夏令時。例如,在夏令時轉換期間,給晚上10點的就寢時間加上8小時,會錯誤地返回早上6點而不是7點,因為該庫沒有考慮到失去的那一小時。
另一個主要抱怨是 Python 的類型系統無法區分樸素日期時間(沒有時區信息)和感知日期時間(有時區信息)。這使得無法在類型檢查級別強制函數期望一種或另一種,從而導致潛在的錯誤。
「我是一名經驗豐富的程序員,但每當我處理 datetime 對象時,我盡力進行單元測試,然後只希望這些'邊緣'情況不適用於我們。這意味着:我真的不知道它在底層是如何工作的。」
替代庫及其侷限性
在 Whenever 出現之前,開發者們曾轉向 Arrow 和 Pendulum 等替代品,但這些庫並沒有完全解決核心問題。Arrow 保留了與標準庫相同的基本問題,並通過將所有內容簡化為單一 Arrow 類型而使類型檢查變得更加困難。Pendulum 試圖修復一些與夏令時相關的陷阱,但隨着時間的推移,性能有所下降,並且似乎處於維護停滯狀態,在過去四年中只發布了一次。
許多評論者指出,他們嘗試過各種庫,但對邊緣情況仍感到不確定。一位開發者提到,在使用過 Arrow、Delorean 和 Pendulum 之後,最終選擇了 Whenever,因為它更適合我實際使用日期時間的方式,並且似乎維護更加活躍。
依賴性爭論
Whenever 的發佈引發了關於是否使用第三方庫或堅持使用標準庫的熱烈討論。一些開發者表示傾向於完全避免依賴,認為它們會殺死項目並造成維護負擔。而另一些人則反駁説,對於像日期時間處理這樣的複雜領域,由領域專家創建的維護良好的庫值得付出依賴成本。
特別是醫療保健領域的開發者強調,他們寧願使用可信賴的依賴項,也不願冒險自己實現複雜的日期時間邏輯。其他人也呼應了這一觀點,指出雖然標準庫經過了良好的測試,但如果不進行破壞性更改,其基本設計缺陷是無法修復的。
性能和實現
Whenever 同時提供 Rust 和純 Python 實現,其中 Rust 版本提供了顯著的性能優勢。根據作者分享的基準測試,Rust 實現的性能優於標準庫和其他第三方替代品。純 Python 版本比 Rust 版本慢約10倍,但通常仍比 Arrow 和 Pendulum 更快。
一些用户對使用二進制包或從源代碼構建的複雜性表示擔憂,特別是關於純 Python 實現,它需要特殊的環境變量才能安裝。作者承認這些擔憂,但解釋了打包決策中涉及的權衡。
庫比較
功能 | Whenever | datetime | Arrow | Pendulum |
---|---|---|---|---|
DST安全 | ✅ | ❌ | ❌ | ⚠️ |
類型感知/樸素 | ✅ | ❌ | ❌ | ❌ |
快速 | ✅ | ⚠️ | ❌ | ❌ |
Whenever 的主要特點
- DST安全的算術運算
- 類型安全API防止常見錯誤
- 基於其他語言中經過驗證的概念
- 高性能(尤其是 Rust 版本)
- 支持日期算術
- 納秒精度
- 提供 Rust 或純 Python 版本
展望未來
Whenever 的出現反映了在其他語言生態系統中看到的更廣泛模式。Java 在引入 Java 8(JSR-310)中的新 API 之前也面臨類似的日期時間問題,該 API 受到流行的 Joda Time 庫的啓發。JavaScript 目前正在實現 Temporal,這是一個解決類似問題的新日期時間 API。
一些評論者表達了希望 Whenever 能夠遵循類似的路徑,最終影響 Python 標準庫的改進。然而,目前使用 Python 處理日期時間的開發者有了一個新選擇,它承諾使他們的代碼更可靠、更易於維護。
隨着日期時間處理繼續成為各種語言中軟件開發的一個挑戰性方面,像 Whenever 這樣吸收其他生態系統經驗教訓的庫為開發者提供了寶貴的工具,幫助他們編寫正確、類型安全的代碼,而不會陷入常見陷阱。
參考:Whenever