私たちのプロジェクトでは、Zend Framework Modelジェネレーターを使用しています。これは、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」など)に本当に再フォーマットする必要があるのか、それとも修正されるMySQLの奇妙な動作だけなのか遅かれ早かれ?
この質問に対する短い答えは「いいえ、安全ではありません」のようです。この結論は、MySQL Shellを使用した一連の実験に従っています。それでも、もっと「理論的な」答えをいただければ幸いです...
どうやらMySQLエンジンは、(デフォルトでは)_sql_mode
_がSTRICT_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
悲しいことに、文字列が長すぎる(最後の解析可能な数字の後に空白以外のものが続く場合)は、strictモードでは無効な値と見なされます。
_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の開発者ではなく、なぜ私たちがそうする必要があるのでしょうか。しかし、それは別の話だと思います。 )
私が知る限り、時間オフセット情報(ISO 8601文字列の最後の+03:00)をMySQLの日付または時間タイプに格納する方法はないので、自分で解決策を見つける必要があります。
考えられる1つのアプローチは、ISO 8601文字列を分割し、char(5)列にオフセットを格納することですが、確かに操作が多少困難になります。オフセットをTime列に格納すると、日付/時刻の操作が少し簡単になると思います。
[〜#〜]編集[〜#〜]
MySQLのドキュメントで this を偶然見つけました。
デフォルトでは、MySQLは日時にISO9075形式を使用します
1番目と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