Wymyśliłem to dla moich celów. Podsumuję to, czego się nauczyłem (przepraszam, te notatki są szczegółowe; są tak samo przydatne do mojego przyszłego skierowania, jak wszystko inne).
W przeciwieństwie do tego, co powiedziałem w jednym z moich poprzednich komentarzy, pola DATETIME i TIMESTAMP zrób zachowywać się inaczej. Pola TIMESTAMP (jak wskazują dokumenty) przyjmują wszystko, co je wysyłasz, w formacie „RRRR-MM-DD gg:mm:ss” i konwertują je z bieżącej strefy czasowej na czas UTC. Odwrotna sytuacja dzieje się w sposób przezroczysty za każdym razem, gdy pobierasz dane. Pola DATETIME nie dokonują tej konwersji. Biorą wszystko, co im wyślesz, i po prostu przechowują to bezpośrednio.
Ani pola typu DATETIME, ani TIMESTAMP nie mogą dokładnie przechowywać danych w strefie czasowej, w której obowiązuje czas letni . Jeśli zapiszesz „2009-11-01 01:30:00”, pola nie mają możliwości rozróżnienia, którą wersję 1:30 rano chciałeś — wersję -04:00 lub -05:00.
Ok, więc musimy przechowywać nasze dane w strefie czasowej innej niż czas letni (np. UTC). Pola TIMESTAMP nie są w stanie 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 mu dane, które już przekonwertowałeś na UTC, nadal przyjmie, że dane są w Twojej lokalnej strefie czasowej i wykona kolejną konwersję na UTC. Ta wymuszona ZNACZNIKIEM CZASOWYM podróż w obie strony z lokalnego na UTC z powrotem do lokalnego jest stratna, gdy lokalna strefa czasowa przestrzega czasu letniego (od „2009-11-01 01:30:00” mapuje się na 2 różne możliwe czasy).
Dzięki DATETIME możesz przechowywać swoje dane w dowolnej strefie czasowej i mieć pewność, że otrzymasz zwrot tego, co je wyślesz (nie będziesz zmuszony do stratnych konwersji w obie strony, które narzucają ci pola TIMESTAMP). Rozwiązaniem jest więc użycie pola DATETIME i przed zapisaniem w tym polu przekonwertuj ze strefy czasowej systemu na dowolną strefę inną niż DST, w której chcesz ją zapisać (myślę, że UTC jest prawdopodobnie najlepszą opcją). Umożliwia to wbudowanie logiki konwersji w język skryptowy, dzięki czemu można jawnie zapisać odpowiednik czasu 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 MySQL dotyczące daty/godziny nie działają poprawnie w granicach czasu letniego, jeśli przechowujesz daty w DST TZ. Tym bardziej więc 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ładny uniksowy znacznik czasu. Używam do tego funkcji strtotime() PHP lub jej klasy DateTime. Nie można tego niezawodnie wykonać w MySQL za pomocą funkcji MySQL CONVERT_TZ() lub UNIX_TIMESTAMP(), ponieważ CONVERT_TZ wypisze tylko wartość „RRRR-MM-DD gg:mm:ss”, która ma problemy z niejednoznacznością, a UNIX_TIMESTAMP() przyjmuje jej wejście jest w strefie czasowej systemu, a nie w strefie czasowej, w której dane faktycznie były przechowywane (UTC).
Podczas przechowywania danych w bazie danych:
Konwertuj swoją datę na dokładny czas UTC, którego potrzebujesz poza MySQL. Na przykład:za pomocą klasy 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ć to na UTC i zapisać poprawny czas UTC do pola DATETIME.
Uff. Dziękuję bardzo za wkład i pomoc wszystkich. Mam nadzieję, że oszczędzi to komuś innego bólu głowy.
BTW, widzę to w MySQL 5.0.22 i 5.0.27