Mysql
 sql >> Baza danych >  >> RDS >> Mysql

PHP, MySQL i strefy czasowe

Ta odpowiedź została zaktualizowana, aby uwzględnić nagrodę. Oryginalna, nieedytowana odpowiedź znajduje się pod linią.

Prawie wszystkie pytania dodane przez właściciela bounty dotyczą tego, w jaki sposób daty i godziny MySQL i PHP powinny współdziałać w kontekście stref czasowych.

MySQL wciąż jest żałosny obsługa stref czasowych , co oznacza, że ​​inteligencja musi być po stronie PHP.

  • Ustaw swoją strefę czasową połączenia w MySQL do UTC, jak udokumentowano w powyższym linku. Spowoduje to, że wszystkie daty i godziny obsługiwane przez MySQL, w tym NOW() , które należy traktować rozsądnie.
  • Zawsze używaj DATETIME , nigdy nie używaj TIMESTAMP chyba że bardzo wyraźnie wymagasz specjalnego zachowania w TIMESTAMP . Jest to mniej bolesne niż kiedyś.
    • Jest w porządku do przechowywania czasu epoki Uniksa jako liczby całkowitej, jeśli masz do, na przykład do celów odziedziczonych. Epoka to UTC.
    • Preferowany format daty i godziny MySQL jest tworzony przy użyciu ciągu formatu daty PHP Y-m-d H:i:s
  • Konwertuj wszystkie Daty PHP do UTC podczas przechowywania ich w MySQL, co jest trywialną rzeczą, jak opisano poniżej
  • Datetimes zwrócone z MySQL można bezpiecznie przekazać do konstruktora PHP DateTime. Pamiętaj, aby przejść również w strefie czasowej UTC!
  • Konwertuj PHP DateTime na lokalną strefę czasową użytkownika na echo , nie wcześniej. Na szczęście porównanie DateTime i matematyka z innymi DateTimes uwzględni strefę czasową, w której każda z nich się znajduje.
  • Nadal spełniasz kaprysy bazy danych DST dostarczanej z PHP. Aktualizuj swoje poprawki PHP i OS! Utrzymuj MySQL w błogim stanie UTC, aby usunąć jedną potencjalną irytację czasu letniego.

To dotyczy większości punktów.

Ostatnia rzecz to doozy:

  • Co powinien zrobić ktoś, kto wcześniej wstawił dane (np. za pomocą NOW() ) bez martwienia się o strefę czasową, aby upewnić się, że wszystko pozostaje spójne?

To prawdziwa irytacja. Jedna z innych odpowiedzi wskazywała na CONVERT_TZ , chociaż osobiście zrobiłbym to, przeskakując między strefami czasowymi serwera i UTC podczas wybierania i aktualizacji, ponieważ jestem taki hardkorowy.

aplikacja powinna również być w stanie odpowiednio ustawić/wybrać czas letni dla każdego użytkownika.

Nie musisz i nie powinieneś zrób to w epoce nowożytnej.

Nowoczesne wersje PHP mają DateTimeZone klasa, która zawiera możliwość listy nazwanych stref czasowych . Nazwane strefy czasowe pozwalają użytkownikowi wybrać swoją rzeczywistą lokalizację, a system automatycznie określić swoje zasady czasu letniego na podstawie tej lokalizacji.

Możesz połączyć DateTimeZone z DateTime dla prostej, ale potężnej funkcjonalności. Możesz po prostu przechowywać i używać wszystko Twoich znaczników czasu w UTC domyślnie i przekonwertuj je na wyświetlaną strefę czasową użytkownika.

// UTC default
    date_default_timezone_set('UTC');
// Note the lack of time zone specified with this timestamp.
    $nowish = new DateTime('2011-04-23 21:44:00');
    echo $nowish->format('Y-m-d H:i:s'); // 2011-04-23 21:44:00
// Let's pretend we're on the US west coast.  
// This will be PDT right now, UTC-7
    $la = new DateTimeZone('America/Los_Angeles');
// Update the DateTime's timezone...
    $nowish->setTimeZone($la);
// and show the result
    echo $nowish->format('Y-m-d H:i:s'); // 2011-04-23 14:44:00

Dzięki tej technice system automatycznie wybierz prawidłowe ustawienia czasu letniego dla użytkownika, nie pytając użytkownika, czy aktualnie pracuje w czasie letnim.

Możesz użyć podobnej metody do renderowania menu wyboru. Możesz stale ponownie przypisywać strefę czasową dla pojedynczego obiektu DateTime. Na przykład ten kod wyświetli listę stref i ich aktualne godziny, w tej chwili:

$dt = new DateTime('now', new DateTimeZone('UTC')); 
foreach(DateTimeZone::listIdentifiers() as $tz) {
    $dt->setTimeZone(new DateTimeZone($tz));
    echo $tz, ': ', $dt->format('Y-m-d H:i:s'), "\n";
}

Możesz znacznie uprościć proces selekcji, używając magii po stronie klienta. JavaScript ma niekonsekwentny, ale funkcjonalny Klasa daty ze standardową metodą uzyskania przesunięcia UTC w minutach . Możesz to wykorzystać, aby zawęzić listę prawdopodobnych stref czasowych, przy ślepym założeniu, że zegar użytkownika jest prawidłowy.

Porównajmy tę metodę z robieniem tego samemu. Trzeba by właściwie wykonać obliczenia na datach za każdym razem manipulujesz datą i godziną, a także narzucasz użytkownikowi wybór, o który tak naprawdę nie będzie dbał. To nie jest tylko nieoptymalne, to szaleństwo nietoperza. Zmuszanie użytkowników do zaznaczenia, kiedy chcą wsparcia czasu letniego, jest proszeniem o kłopoty i zamieszanie.

Co więcej, jeśli chcesz użyć do tego nowoczesnego frameworka PHP DateTime i DateTimeZone, musisz użyj przestarzałego Etc/GMT... ciągi stref czasowych zamiast nazwanych stref czasowych. Te nazwy stref mogą zostać usunięte z przyszłych wersji PHP, więc nie byłoby to rozsądne. Mówię to wszystko z doświadczenia.

tl;dr :Korzystaj z nowoczesnego zestawu narzędzi, oszczędź sobie koszmarów matematyki na randce. Zaprezentuj użytkownikowi listę nazwanych strefy czasowe. Przechowuj swoje daty w UTC , na który w żaden sposób nie ma wpływu czas letni. Konwertuj daty i godziny na wybraną przez użytkownika nazwaną strefę czasową na wyświetlaczu , nie wcześniej.

Zgodnie z żądaniem, oto pętla dostępnych stref czasowych, wyświetlająca ich przesunięcie GMT w minutach. Wybrałem tutaj minuty, aby zademonstrować niefortunny fakt:nie wszystkie przesunięcia są w pełnych godzinach! Niektórzy faktycznie przełączają się pół godziny do przodu podczas czasu letniego zamiast całej godziny. Wynikowe przesunięcie w minutach powinno pasuje do Date.getTimezoneOffset JavaScriptu .

$utc = new DateTimeZone('UTC');
$dt = new DateTime('now', $utc); 
foreach(DateTimeZone::listIdentifiers() as $tz) {
    $local = new DateTimeZone($tz);
    $dt->setTimeZone($local);
    $offset = $local->getOffset($dt); // Yeah, really.
    echo $tz, ': ', 
         $dt->format('Y-m-d H:i:s'),
         ', offset = ',
         ($offset / 60),
         " minutes\n";
}


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Jak sprawdzić, czy MySQLnd jest aktywnym sterownikiem?

  2. Jak MySQL przetwarza ORDER BY i LIMIT w zapytaniu?

  3. Jak działa funkcja POSITION() w MySQL

  4. Nie mogę znaleźć my.cnf na moim komputerze z systemem Windows

  5. MySQL (lub PHP?) grupuje wyniki według danych pola