Rozgryzłem to do swoich celów. Podsumuję, czego się nauczyłem (przepraszam, te notatki są rozwlekłe; są tak samo ważne dla mojego przyszłego polecenia, jak cokolwiek innego).
Wbrew temu, co powiedziałem w jednym z moich poprzednich komentarzach, pola datetime i godziną należy zachowywać się inaczej. Pola TIMESTAMP (jak wskazują dokumenty) pobierają wszystko, co je wyślesz w formacie „RRRR-MM-DD gg: mm: ss” i konwertują z aktualnej strefy czasowej na czas UTC. Odwrotna sytuacja dzieje się w sposób przejrzysty za każdym razem, gdy pobierasz dane. Pola DATETIME nie powodują tej konwersji. Biorą wszystko, co im wyślesz i po prostu przechowują to bezpośrednio.
Ani typy pól DATETIME, ani TIMESTAMP nie mogą dokładnie przechowywać danych w strefie czasowej, w której obserwuje się czas letni . Jeśli zapiszesz „2009-11-01 01:30:00”, pola nie będą miały możliwości rozróżnienia, którą wersję z 1:30 chcesz - wersję -04: 00 lub -05: 00.
Ok, więc musimy przechowywać nasze dane w strefie czasowej innej niż DST (np. UTC). Pola TIMESTAMP nie mogą dokładnie obsłużyć tych danych z powodów, które wyjaśnię: jeśli twój system jest ustawiony na strefę czasową DST, to to, co umieścisz w TIMESTAMP, może nie być tym, co otrzymujesz. Nawet jeśli wyślesz dane, które już przekonwertowałeś na UTC, nadal przyjmie dane z Twojej lokalnej strefy czasowej i dokona kolejnej konwersji na UTC. Ta wymuszona przez TIMESTAMP podróż w obie strony lokalna do czasu UTC z powrotem do lokalnego jest stratna, gdy lokalna strefa czasowa obserwuje czas letni (od „2009-11-01 01:30:00” odwzorowuje 2 różne możliwe czasy).
Dzięki DATETIME możesz przechowywać dane w dowolnej strefie czasowej i mieć pewność, że odzyskasz wszystko, co wyślesz (nie zostaniesz zmuszony do stratnych konwersji w obie strony, które narzucają Ci pola TIMESTAMP). Tak więc rozwiązaniem jest użycie pola DATETIME i przed zapisaniem w polu przekonwertowanie ze strefy czasowej systemu na dowolną strefę inną niż DST, w której chcesz ją zapisać (myślę, że UTC jest prawdopodobnie najlepszą opcją). Pozwala to na zbudowanie logiki konwersji w języku skryptów, dzięki czemu można jawnie zapisać odpowiednik UTC „2009-11-01 01:30:00 -04: 00” lub „” 2009-11-01 01:30: 00 -05: 00 ”.
Inną ważną rzeczą, na którą należy zwrócić uwagę, jest to, że funkcje matematyczne daty / czasu MySQL nie działają poprawnie w granicach czasu letniego, jeśli przechowujesz daty w DST TZ. Tym bardziej warto oszczędzać w UTC.
Krótko mówiąc, teraz robię to:
Podczas pobierania danych z bazy danych:
Jawnie interpretuj dane z bazy danych jako UTC poza MySQL, aby uzyskać dokładną sygnaturę czasową Uniksa. Używam do tego funkcji PHP strtotime () lub jego klasy DateTime. Nie można tego niezawodnie wykonać wewnątrz MySQL przy użyciu funkcji MySQL CONVERT_TZ () lub UNIX_TIMESTAMP (), ponieważ CONVERT_TZ wyświetli tylko wartość „RRRR-MM-DD gg: mm: ss”, która cierpi na problemy z niejednoznacznością, a UNIX_TIMESTAMP () zakłada wejście znajduje się w strefie czasowej systemu, a nie w strefie czasowej, w której dane były AKTUALNIE przechowywane w (UTC).
Podczas przechowywania danych w bazie danych:
Przekonwertuj swoją datę na dokładny czas UTC, którego potrzebujesz poza MySQL. Na przykład: w klasie PHP DateTime możesz określić „2009-11-01 1:30:00 EST” wyraźnie od „2009-11-01 1:30:00 EDT”, a następnie przekonwertować je na UTC i zapisać prawidłowy czas UTC do pola DATETIME.
Uff. Dziękuję bardzo za wkład i pomoc wszystkich. Miejmy nadzieję, że to zaoszczędzi komuś innemu bólu głowy w przyszłości.
BTW, widzę to w MySQL 5.0.22 i 5.0.27