在我们的项目中,我们使用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的一些奇怪行为会迟早修好吗?
答案 0 :(得分:16)
看起来这个问题的简短回答是“不,这不安全” - 这个结论是在MySQL shell的一系列实验之后进行的。尽管如此,仍然会欣赏更“理论化”的答案......
显然,即使将sql_mode
设置为STRICT_ALL_TABLES,MySQL引擎(默认情况下)也接受它作为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)
在传统模式下,解析更加轻松 - 但不是更精确;此外,在严格模式下被认为是不正确的字符串会给出一些“无声警告”,但操作会成功:
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开发人员。但我认为那是另一个故事。 )
答案 1 :(得分:4)
据我所知,无法在MySQL日期或时间类型中存储时间偏移信息(ISO 8601字符串末尾的+03:00),因此您可以自行查找解决方案。
一种可能的方法是拆分ISO 8601字符串并将偏移量存储在char(5)列中,但不可否认它会使它难以使用。我想你可以将偏移存储在时间列中,这可能会使日期/时间操作更容易一些。
修改强>
我只是偶然发现了MySQL文档中的this,这可能会有所帮助。
答案 2 :(得分:2)
默认情况下,MySQL使用ISO9075格式进行日期时间
第一个和第二个参数的可能值导致几个可能的格式字符串(对于使用的说明符,请参阅DATE_FORMAT()函数说明中的表)。 ISO格式是指ISO 9075,而不是ISO 8601。
http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_get-format