2012-06-15 42 views
14

En nuestro proyecto utilizar el generador Zend Framework Modelo, que produce algo como esto para establecer las propiedades que se almacenan en la base de datos (MySQL) como campos DATETIME:Inserción de MySQL a DATETIME: ¿es seguro usar el formato ISO :: 8601?

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

Así que la ISO 8601 :: cadena con formato (' 2012-06-15T18: 33: 00 + 03: 00 'por ejemplo) es lo que realmente se almacena como una propiedad.

El problema surge cuando tratamos de save este modelo, y pasamos esta cadena a MySQL (versión 5.5.16): levanta la advertencia, pero aún inserta/actualiza la fila correspondiente con un resultado correcto. Es fácil comprobar que el problema está causado por MySQL, y no el comportamiento de algunos pilotos: acaba de emitir consulta como ...

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

... y el resultado será 1 row affected, 1 warning, con

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

advertencia (mostrado por SHOW WARNINGS).

En mi conocimiento, phpMyAdmin no muestra ningún tipo de advertencia; y todo el código del lado del servidor procesó esta consulta como una sólida.)

Entonces, la pregunta es: ¿deberíamos cambiar el formato de lo que almacenamos en nuestro Modelo en otro formato de cadena ('AA-MM-dd HH: mm: ss', por ejemplo?) ¿O es simplemente un comportamiento extraño de MySQL que se solucionará tarde o temprano

+1

Especialmente en MySQL 5.7 obtendrá un error hacer eso. "Y-m-d H: i: s" – John

Respuesta

15

Parece que la respuesta corta a esta pregunta es "No, no es seguro" - esta conclusión sigue a una serie de experimentos con shell MySQL. Aún así, apreciaría una respuesta más "teórica", aunque ...

Aparentemente, el motor MySQL es (por defecto) bastante liberal en lo que acepta como un literal Datetime incluso con sql_mode configurado en STRICT_ALL_TABLES: no solo se aceptan varios separadores, que pueden ser diferentes, así:

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

Además, si la cadena es demasiado corta, se rellena con ceros ...pero puede haber sorpresas:

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

Lo triste es que la cadena demasiado tiempo (cuando el último dígito apta para su procesamiento es seguida por algo que no sea un espacio en blanco) será considerado como un valor no válido en modo estricto:

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) 

En el modo tradicional, el análisis es aún más relajado, pero no más preciso; Además, las cadenas que se consideran incorrecto en el modo estricto dará especie de 'advertencias silenciosos', aunque las operaciones tendrán éxito:

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

La conclusión es que tuvimos que volver a escribir algo de código relacionadas con el DAL de manera que las fechas (y datetimes) siempre se envían al DB en forma "normalizada". Me pregunto por qué somos nosotros quienes tenemos que hacerlo, y no los desarrolladores de Zend_Db. Pero esa es otra historia, supongo.)

4

Por lo que yo sé, no hay forma de almacenar la información de compensación de tiempo (el +03: 00 al final de su cadena ISO 8601) en tipos de fecha y hora de MySQL, por lo que es más o menos por su cuenta encuentra una solución.

Un posible enfoque es dividir el string ISO 8601 y almacenar el offset en una columna char (5), aunque es cierto que dificultaría trabajar con él. Supongo que podría almacenar el desplazamiento en una columna de tiempo, lo que podría hacer que las manipulaciones de fecha/hora sean un poco más fáciles.

EDITAR
simplemente me topé this en la documentación de MySQL, que pueden ser útiles.

+0

Veo su punto, pero la pregunta es más sobre la validez del formato en sí.) En realidad, Zend_Date convirtió todas las fechas en GMT en nuestro caso, por lo que el desplazamiento de la zona horaria en estas cadenas siempre fue +00: 00. De todos modos, gracias por tu respuesta.) – raina77ow

+0

Parece que MySQL no analiza el offset de la zona horaria: al menos los campos TIMESTAMP se actualizaron con los mismos datos con el valor '+ XX: 00' que utilicé. Triste. – raina77ow

+0

Oh, bien, mi malentendido: pensé que la información de la zona horaria era importante/necesaria. –

Cuestiones relacionadas