數據庫存儲時間的時區問題

先說一下mysql中DATETIME和TIMESTAMP的區別mysql

TIMESTAMP是標準的unix timestamp,它存儲的是1970-1-1到如今通過的秒數,4字節存儲。mysql用這個類型還蠻方便的,一個是有不少內置的函數和trigger來處理它,好比CURRENT_TIMESTAMP宏,最關鍵的是在取數據的時候mysql會自動幫你處理DST和時區的問題。sql

DATETIME的範圍更大,好像能夠從0000-00-00 00:00:00到9999-12-31 23:59:59,8字節存儲,固然mysql內部確定也是用整數而不是字符串的(說了是8字節了),因此效率不是大問題。但DATETIME不帶時區,好比我在程序裏生成了一個2015-05-07 15:26:00的時間(其實是+8時區的,但這個對象多是timezone naive)的,存到mysql裏,再從不一樣時區的地方拿出來,這個時間可能就混了。數據庫

但TIMESTAMP也有兩個很大的問題:服務器

  1. 4字節長度限制,它只能到2038年
  2. 不少時候咱們但願根據用戶所在地的時區顯示時間而不是光顯示一個服務器時間

因此比較好的作法是,數據庫中使用DATETIME,而後存時間的時候一概用程序生成UTC時間(而不是local時區的時間)存進去,取出來的時候無論想顯示服務器時間仍是顯示用戶的時間均可以處理。session

順便提一句,根據用戶所在地時區顯示時間有兩種作法:框架

  1. 當用戶第一次訪問網站的時候,用js獲取時區發送到服務器上存到session裏
  2. 用js處理時間的顯示(我以爲這種比較方便一點,畢竟不用改服務端代碼)

使用這種作法的惟一缺點是sqlite3沒有internal的DATETIME類型,因此在ORM框架如sqlalchemy中,它會直接存字符串進去。(sqlite3的文檔也說,你要麼存成int要麼real要麼字符串)。儘管這可能帶來一些不方便和性能的降低,但我認爲仍是符合「keep it simple and stupid」的原則。函數

至於用INT存時間,是另外一種可行的方法,參見http://www.liaoxuefeng.com/article/0014132675721847f569c3514034f099477...
我我的不是很喜歡這麼作,由於這樣你必須把模型中表示時間的成員聲明爲int類型。這樣是比較不符合邏輯的(那些Date呀Datetime之類的類就沒有用了呀,最多就有個Dateutil就行了),並且會使得程序不易讀(臥槽這個publishedDate爲何是int,它到底表示的是時間嗎?)。總之見仁見智。性能

相關文章
相關標籤/搜索