Edit: TL;DR
# This query ---------------------------------------
SELECT STR_TO_DATE('2020-10-20T14:43:49+00:00', '%Y-%m-%dT%H:%i:%s') AS date;
# Results in----------------------------------------
+---------------------+
| date |
+---------------------+
| 2020-10-20 14:43:49 |
+---------------------+
# But throws----------------------------------------
+---------+------+-----------------------------------------------------------------+
| Level | Code | Message |
+---------+------+-----------------------------------------------------------------+
| Warning | 1292 | Truncated incorrect datetime value: '2020-10-20T14:43:49+00:00' |
+---------+------+-----------------------------------------------------------------+
Why?
Detailed description
I have read through a lot of questions regarding similar issues, but could not find a definitive answer to this problem.
I'm running Doctrine migrations in a Symfony 5.2.x project on a MariaDB 10.2 database. I am trying to extract a date string from a JSON data column into its own column on the same table, but running into error messages when the original date string has a certain format.
ALTER TABLE form
ADD updated_at DATETIME DEFAULT NULL;
UPDATE form AS f
SET updated_at = STR_TO_DATE(
TRIM(BOTH '"' FROM (
SELECT JSON_EXTRACT(f.data, '$.updatedAt')
)),
'%Y-%m-%dT%H:%i:%s+00:00'
);
This works for any date string with a timezone offset of 0, like 2020-12-04T11:14:07+00:00. For obvious reasons, it fails for a non-zero offset like 2020-12-04T11:14:07+01:00, because
Literal characters in format must match literally in str.
-- https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_str-to-date
and results in an error
Warning | 1411 | Incorrect datetime value: '2020-12-04T11:14:07+01:00' for function str_to_date
However, if I understand the documentation correctly, I shouldn't even have to include the timezone offset in the format string:
Extra characters at the end of str are ignored.
But when I change the format string from '%Y-%m-%dT%H:%i:%s+00:00' to '%Y-%m-%dT%H:%i:%s', the update operation fails for all items, even though the dates are parsed correctly (or, at least, look correct):
MariaDB [db]> select STR_TO_DATE('2020-10-20T14:43:49+00:00', '%Y-%m-%dT%H:%i:%s') as date;
+---------------------+
| date |
+---------------------+
| 2020-10-20 14:43:49 |
+---------------------+
1 row in set, 1 warning (0.00 sec)
MariaDB [db]> show warnings;
+---------+------+-----------------------------------------------------------------+
| Level | Code | Message |
+---------+------+-----------------------------------------------------------------+
| Warning | 1292 | Truncated incorrect datetime value: '2020-10-20T14:43:49+00:00' |
+---------+------+-----------------------------------------------------------------+
1 row in set (0.00 sec)
The Question
Apart from the historic bug in the application that would in some cases result in a non-UTC updated_at date, what am I doing wrong? As I understand it, anything in the string after the bit matching %s should be ignored by STR_TO_DATE() and irrelevant to the query. Why are my migrations failing when the DB clearly manages to parse the strings to something that looks like the datetime type it understands? How can I make sure it parses every item's date irrespective of its TZ offset (I wouldn't even mind if the result was updated_at times for some items with an hour's difference to the actual datetime)?
Edit
Because I don't fully understand what it does or what the implications are, I've tried changing sql_mode before executing my queries, but got the same results:
SET @@SQL_MODE = REPLACE(@@SQL_MODE, 'NO_ZERO_IN_DATE', '');
SET @@SQL_MODE = REPLACE(@@SQL_MODE, 'NO_ZERO_DATE', '');
Edit II
I ended up rewriting the migration and manually looping over each entry in PHP, re-setting the timezone and writing the corrected (UTC) value back to the DB. This is obviously way more verbose and much slower than the SQL one-liner. The lack of answers (or even comments) here suggests I might have stumbled upon either a Maria/MySQL bug or faulty documentation.