sql >> Databáze >  >> RDS >> Mysql

PHP, MySQL a časová pásma

Tato odpověď byla aktualizována, aby odpovídala odměně. Původní, neupravená odpověď je pod čarou.

Téměř všechny otázky, které přidal vlastník odměny, se týkají toho, jak by měly datatime MySQL a PHP interagovat v kontextu časových pásem.

MySQL je stále žalostné podpora časového pásma , což znamená, že inteligence musí být na straně PHP.

  • Nastavte časové pásmo připojení MySQL do UTC, jak je zdokumentováno v odkazu výše. To způsobí, že všechna data a časy zpracovávají MySQL, včetně NOW() , je třeba s nimi zacházet rozumně.
  • Vždy používejte DATETIME , nikdy nepoužívejte TIMESTAMP pokud výslovně nepožadujete zvláštní chování v TIMESTAMP . Je to méně bolestivé než dříve.
    • Je to v pořádku ukládat čas Unixové epochy jako celé číslo, pokud máte například pro účely dědictví. Epochou je UTC.
    • Preferovaný formát data a času MySQL je vytvořen pomocí řetězce formátu data PHP Y-m-d H:i:s
  • Převést vše PHP datatimes do UTC při jejich ukládání v MySQL, což je triviální věc, jak je uvedeno níže
  • Datumy vrácené z MySQL lze bezpečně předat konstruktoru PHP DateTime. Nezapomeňte zadat také časové pásmo UTC!
  • Převeďte PHP DateTime na místní časové pásmo uživatele on echo , ne dříve. Naštěstí porovnání DateTime a matematika s jinými DateTimes vezme v úvahu časové pásmo, ve kterém se každý nachází.
  • Stále jste v souladu s rozmary databáze DST poskytované s PHP. Udržujte své opravy PHP a OS aktuální! Udržujte MySQL v blaženém stavu UTC, abyste odstranili jednu potenciální nepříjemnost DST.

To řeší nejvíce bodů.

Poslední věc je blbost:

  • Co by měl někdo udělat, pokud již dříve vložil data (např. pomocí NOW() ), aniž byste se museli starat o časové pásmo, abyste se ujistili, že vše zůstane konzistentní?

To je skutečná otrava. Jedna z dalších odpovědí poukázala na CONVERT_TZ , i když osobně bych to udělal přeskakováním mezi nativním serverem a časovým pásmem UTC během výběru a aktualizací, protože jsem takový hardcore.

aplikace by také měla být schopna SET/Volba DST sama pro každého uživatele.

Nemusíte a neměli byste udělejte to v moderní době.

Moderní verze PHP mají DateTimeZone třídy, která zahrnuje možnost seznam pojmenovaných časových pásem . Pojmenovaná časová pásma umožňují uživateli vybrat si svou skutečnou polohu a mají systém automaticky určit jejich pravidla DST na základě tohoto umístění.

DateTimeZone můžete kombinovat s DateTime pro některé jednoduché, ale výkonné funkce. Můžete jednoduše uložit a používat vše vašich časových razítek v UTC ve výchozím nastavení a převést je na zobrazené časové pásmo uživatele.

// 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

Při použití této techniky bude systém automaticky vyberte správná nastavení letního času pro uživatele, aniž byste se ho zeptali, zda se aktuálně nachází v letním čase.

Podobnou metodu můžete použít k vykreslení nabídky výběru. Časové pásmo můžete neustále měnit pro jeden objekt DateTime. Například tento kód vypíše zóny a jejich aktuální časy v tuto chvíli:

$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";
}

Proces výběru můžete výrazně zjednodušit použitím některých kouzel na straně klienta. Javascript má nepatrný, ale funkční Třída data se standardní metodou k postupu UTC během několika minut . Můžete to použít k zúžení seznamu pravděpodobných časových pásem za slepého předpokladu, že hodiny uživatele jsou správné.

Porovnejme tuto metodu s tím, že to uděláte sami. Ve skutečnosti byste museli vypočítat datum pokaždé manipulujete s datem a časem a navíc podsouváte uživateli volbu, o kterou se ve skutečnosti nebude starat. To není jen suboptimální, je to šílené bat-guano. Nutit uživatele, aby uvedli, kdy chtějí podporu DST, si žádá potíže a zmatky.

Dále, pokud byste k tomu chtěli použít moderní PHP DateTime a DateTimeZone framework, museli byste použijte zastaralé Etc/GMT... řetězce časového pásma místo pojmenovaných časových pásem. Tyto názvy zón mohou být z budoucích verzí PHP odstraněny, takže by nebylo rozumné to dělat. To vše říkám ze zkušenosti.

tl;dr :Použijte moderní sadu nástrojů, ušetříte si hrůzy datovací matematiky. Nabídněte uživateli seznam pojmenovaných časová pásma. Uložte svá data v UTC , které nebude letním časem nijak ovlivněno. Převeďte datum a čas na uživatelem vybrané pojmenované časové pásmo na displeji , ne dříve.

Jak bylo požadováno, zde je smyčka přes dostupná časová pásma zobrazující jejich posun vůči GMT v minutách. Vybral jsem zde minuty, abych demonstroval nešťastnou skutečnost:ne všechny offsety jsou v celých hodinách! Někteří ve skutečnosti přepínají během letního času o půl hodiny dopředu místo celé hodiny. Výsledný posun v minutách by měl shodují se s hodnotou 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. Jaký je nejlepší způsob, jak velké první písmeno každého slova v řetězci použít na SQL Server

  2. SQLite - příkazy JOIN

  3. Jak získat všechny tabulky, které mají omezení primárního klíče vytvořené v databázi SQL Server - SQL Server / TSQL výukový program 57

  4. 10 tipů a triků pro správu efektivní databáze