2012-06-15 41 views
14

在我們的項目中,我們使用Zend框架的模式發生器,產生這樣的設置存儲在數據庫(MySQL的)作爲DATETIME字段屬性:MySQL插入到DATETIME:使用ISO :: 8601格式安全嗎?

public function setObjectDatetime($data) { 
    if (! $data instanceof Zend_Date) { ... some conversion code ... } 
    $this->objectDatetime = $data->toString(Zend_Date::ISO_8601); 
} 

所以ISO 8601 ::格式的字符串(」 2012-06-15T18:33:00 + 03:00「)是實際存儲爲屬性的內容。

當我們嘗試save這個模型,並將此字符串傳遞給MySQL(版本5.5.16)時,出現問題:它引發警告,但仍然插入/更新相應的行並得到正確的結果。這很容易檢查問題是由MySQL造成的,而不是一些司機的行爲:剛發出這樣的查詢...

UPDATE table_name SET datetime_field = '2012-06-15T18:33:00+03:00' WHERE id = 1; 

...,結果將是1 row affected, 1 warning,與

1264 | Out of range value for column 'dt' at row 1

警告(由SHOW WARNINGS顯示)。

對我來說,phpMyAdmin並沒有顯示任何警告;並且所有服務器端代碼都將這個查詢處理爲一個實體。 )

所以問題是:我們是否應該將我們模型中存儲的內容重新格式化爲另一種字符串格式(例如,'YY-MM-dd HH:mm:ss')或者它只是一些奇怪的行爲MySQL將被修復遲早?

+1

尤其是在MySQL 5.7,你會得到一個錯誤這樣做。 「Y-m-d H:i:s」 – John

回答

15

它看起來像短這個問題的答案是「不,這不是安全」 - 這一結論如下與MySQL殼了一系列實驗。雖然...

顯然MySQL引擎是(默認情況下)它接受作爲日期時間文字的非常自由,即使sql_mode設置爲STRICT_ALL_TABLES:不僅接受各種分隔符,他們可能也不同:

INSERT INTO t(dt) VALUES('2012-01,03.04:[email protected]'); -- Query OK, 1 row affected

此外,如果字符串太短,它將被零填充...但可能有驚喜:

INSERT INTO t(dt) VALUES('2012011'); -- 2020-12-01 01:00:00 is what's inserted

可悲的是,字符串太長(當最後一個可分析的數字之後,除空白的東西)將被視爲在嚴格模式下無效值:

mysql> INSERT INTO t(dt) VALUES('2012-06-27T05:25Z'); 
ERROR 1292 (22007): Incorrect datetime value: '2012-06-27T05:25Z' for column 'dt' at row 1 
mysql> INSERT INTO t(dt) VALUES('2012-06-27T05:25'); 
Query OK, 1 row affected (0.10 sec) 

在傳統模式下解析更加輕鬆 - 但不是更精確;此外,被認爲是在嚴格的模式會給那種「沉默警告」的不正確的字符串,雖然操作會成功:

mysql> INSERT INTO t(dt) VALUES('2012-06-27T05:25Z'); 
Query OK, 1 row affected, 1 warning (0.10 sec) 

mysql> SHOW WARNINGS; 
+---------+------+---------------------------------------------+ 
| Warning | 1264 | Out of range value for column 'dt' at row 1 | 
+---------+------+---------------------------------------------+ 

mysql> SELECT dt FROM t; 
+---------------------+ 
| dt     | 
+---------------------+ 
| 2012-06-27 05:25:00 | 
+---------------------+ 

的底線是,我們不得不重寫一些DAL相關的代碼,以便日期(和日期時間)總是以「規範化」形式發送到數據庫。我想知道爲什麼我們必須這樣做,而不是Zend_Db開發人員。但我想這是另一回事。 )

4

據我知道有沒有辦法保存時間偏移信息(+03:00在你的ISO 8601字符串的結尾)在MySQL日期或時間類型的,所以你在你自己都有點找到解決方案。

一種可能的方法是分裂ISO 8601串並存儲在一個char(5)行的偏移,但無可否認它會使它的排序很難處理。我想你可以存儲在一個時間列,這可能使日期/時間的操作更容易些偏移。

編輯
我只是在MySQL的文檔,這可能是有益的偶然this

+0

我明白你的觀點,但問題更多的是格式本身的有效性。 )實際上,在我們的例子中,Zend_Date將所有日期時間轉換爲GMT時間,所以這些字符串中的時區偏移總是+00:00。無論如何,謝謝你的回答。 ) – raina77ow

+0

看起來MySQL根本沒有解析時區偏移量:至少TIMESTAMP字段使用相同的數據更新,無論使用的是「+ XX:00」。傷心。 – raina77ow

+0

哦,好吧,我的誤解 - 我認爲時區信息是重要/必要的。 –