18

私たちのプロジェクトでは、Zend Framework モデル ジェネレーターを使用します。これは、次のようなものを生成して、DB (MySQL) に格納されているプロパティを DATETIME フィールドとして設定します。

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' など) に本当に再フォーマットする必要があるかということです。遅かれ早かれ?

4

3 に答える 3

19

この質問に対する短い答えは「いいえ、安全ではありません」のようです。この結論は、MySQL シェルを使用した一連の実験に基づいています。ただし、より「理論的な」回答をいただければ幸いです...

どうやら、MySQL エンジンは (デフォルトで) sql_modeSTRICT_ALL_TABLES に設定されていても、Datetime リテラルとして受け入れるものに関してかなり寛大です: さまざまな区切り文字が受け入れられるだけでなく、それらも異なる場合があります。

INSERT INTO t(dt) VALUES('2012-01,03.04:05@06'); -- 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)

従来のモードでは、構文解析はさらに緩和されますが、より正確ではありません。さらに、strict モードで正しくないと見なされた文字列は、操作は成功しますが、一種の「無言の警告」を発します。

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 |
+---------------------+

肝心なのは、日付 (および日時) が常に「正規化された」形式で DB に送信されるように、DAL 関連のコードを書き直す必要があったことです。Zend_Db 開発者ではなく、なぜ私たちがやらなければならないのか不思議です。しかし、それは別の話だと思います。)

于 2012-06-27T17:50:03.723 に答える
4

私の知る限り、タイムオフセット情報(ISO 8601文字列の最後の+03:00)をMySQLの日付または時刻タイプに格納する方法はないので、解決策を見つけるのは自分で行う必要があります。

考えられるアプローチの1つは、ISO 8601文字列を分割し、オフセットをchar(5)列に格納することですが、確かに、操作が難しくなります。オフセットを[時間]列に格納すると、日付/時刻の操作が少し簡単になると思います。

編集私はMySQLのドキュメントでこれ
に 遭遇しました。これは役立つかもしれません。

于 2012-06-15T15:46:47.527 に答える
3

デフォルトでは、MySQL は日時に ISO9075 形式を使用します

最初と 2 番目の引数の可能な値は、いくつかの可能な形式文字列になります (使用される指定子については、DATE_FORMAT() 関数の説明の表を参照してください)。ISO 形式は、ISO 8601 ではなく、ISO 9075 を指します。

http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_get-format

于 2015-02-04T14:32:19.700 に答える