Я понял это для моих целей. Я резюмирую то, что я узнал (извините, эти заметки многословны; они предназначены для моего будущего обращения, как и все остальное).
Вопреки тому , что я сказал в одном из моих предыдущих комментариев, DATETIME и TIMESTAMP поля действительно ведут себя по- разному. Поля TIMESTAMP (как указано в документации) принимают все, что вы им отправляете, в формате «ГГГГ-ММ-ДД чч: мм: сс» и преобразуют его из текущего часового пояса во время UTC. Обратное происходит прозрачно всякий раз, когда вы извлекаете данные. Поля DATETIME не выполняют это преобразование. Они берут все, что вы им отправляете, и просто хранят это напрямую.
Ни типы полей DATETIME, ни TIMESTAMP не могут точно хранить данные в часовом поясе, который соблюдает DST . Если вы сохраняете «2009-11-01 01:30:00», в полях не будет возможности отличить, какая версия 1:30 вам нужна - версия -04: 00 или -05: 00.
Хорошо, поэтому мы должны хранить наши данные в часовом поясе без летнего времени (например, в UTC). Поля TIMESTAMP не могут точно обрабатывать эти данные по причинам, которые я объясню: если ваша система настроена на часовой пояс DST, то то, что вы вводите в TIMESTAMP, может быть не тем, что вы получите обратно. Даже если вы отправите ему данные, которые вы уже преобразовали в UTC, он все равно примет данные в вашем местном часовом поясе и выполнит еще одно преобразование в UTC. Этот принудительный TIMESTAMP-обратный переход от локального к UTC-обратно к локальному происходит с потерями, когда в вашем часовом поясе наблюдается летнее время (поскольку «2009-11-01 01:30:00» сопоставляется с 2 различными возможными временами).
С DATETIME вы можете хранить свои данные в любом часовом поясе и быть уверенными, что вернете все, что отправите (вы не будете вынуждены выполнять двусторонние преобразования с потерями, которые навязывают вам поля TIMESTAMP). Таким образом, решение состоит в том, чтобы использовать поле DATETIME и перед сохранением в поле преобразовать часовой пояс вашей системы в любую зону, отличную от DST, в которой вы хотите его сохранить (я думаю, что UTC, вероятно, лучший вариант). Это позволяет вам встроить логику преобразования в ваш язык сценариев, чтобы вы могли явно сохранить UTC-эквивалент «2009-11-01 01:30:00 -04: 00» или «» 2009-11-01 01:30: 00 -05: 00 ".
Еще одна важная вещь, на которую следует обратить внимание, это то, что математические функции даты и времени MySQL не работают должным образом в пределах границ летнего времени, если вы храните свои даты в TZ летнего времени. Так что еще одна причина сохранять в формате UTC.
Вкратце я сейчас делаю так:
При получении данных из базы данных:
Явно интерпретируйте данные из базы данных как UTC вне MySQL, чтобы получить точную метку времени Unix. Для этого я использую функцию PHP strtotime () или ее класс DateTime. Это не может быть надежно выполнено внутри MySQL с использованием функций MySQL CONVERT_TZ () или UNIX_TIMESTAMP (), потому что CONVERT_TZ будет выводить только значение 'YYYY-MM-DD hh: mm: ss', которое страдает проблемами неоднозначности, а UNIX_TIMESTAMP () предполагает его ввод находится в часовом поясе системы, а не в часовом поясе, в котором ДЕЙСТВИТЕЛЬНО хранились данные (UTC).
При сохранении данных в базе данных:
Преобразуйте вашу дату в точное время в формате UTC, которое вы хотите вне MySQL. Например: с классом PHP DateTime вы можете указать «2009-11-01 1:30:00 EST» отдельно от «2009-11-01 1:30:00 EDT», затем преобразовать его в UTC и сохранить правильное время UTC. в ваше поле DATETIME.
Фух. Большое спасибо за вклад и помощь. Надеюсь, это избавит кого-то от головной боли в будущем.
Кстати, я вижу это в MySQL 5.0.22 и 5.0.27