sql >> Databasteknik >  >> RDS >> Mysql

PHP, MySQL och tidszoner

Det här svaret har uppdaterats för att ta emot belöningen. Det ursprungliga, oredigerade svaret är under linjen.

Nästan alla frågepunkter som lagts till av bounty-ägaren är i relation till hur MySQL- och PHP-datumtider ska interagera, i samband med tidszoner.

MySQL har fortfarande patetiskt tidszonsstöd , vilket betyder att intelligensen måste vara PHP-sida.

  • Ställ in din MySQL anslutningstidszon till UTC som dokumenterats i länken ovan. Detta kommer att orsaka alla datumtider som hanteras av MySQL, inklusive NOW() , som ska hanteras på ett förnuftigt sätt.
  • Använd alltid DATETIME , använd aldrig TIMESTAMP såvida du inte uttryckligen kräver det speciella beteendet i en TIMESTAMP . Detta är mindre smärtsamt än det brukade vara.
    • Det är ok för att lagra Unix-epoktiden som ett heltal om du har till, såsom för äldre ändamål. Epok är UTC.
    • MySQL:s föredragna datetime-format skapas med PHP-datumformatsträngen Y-m-d H:i:s
  • Konvertera alla PHP datumtider till UTC när de lagras i MySQL, vilket är en trivial sak som beskrivs nedan
  • Datumtider som returneras från MySQL kan lämnas säkert till PHP DateTime-konstruktorn. Se till att passera i en UTC-tidszon också!
  • Konvertera PHP DateTime till användarens lokala tidszon on echo , inte tidigare. Tack och lov kommer jämförelser och matematik mot andra DateTimes att ta hänsyn till tidszonen som var och en befinner sig i.
  • Du är fortfarande upp till nyckerna i DST-databasen som tillhandahålls med PHP. Håll dina PHP- och OS-patchar uppdaterade! Håll MySQL i det lyckliga tillståndet UTC för att ta bort en potentiell sommarstörning.

Det adresserar de flesta av poängen.

Det sista är en dumhet:

  • Vad ska någon göra om de tidigare har infogat data (t.ex. med NOW() ) utan att oroa dig för tidszonen för att se till att allt förblir konsekvent?

Detta är ett verkligt irritationsmoment. Ett av de andra svaren pekade ut MySQL:s CONVERT_TZ , även om jag personligen skulle ha gjort det genom att hoppa mellan servernative och UTC-tidszoner under val och uppdateringar, för jag är så hård.

appen ska också kunna ställa in/välja sommartid för varje användare.

Du behöver inte och bör inte gör detta i modern tid.

Moderna versioner av PHP har DateTimeZone klass, som inkluderar möjligheten att lista namngivna tidszoner . Namngivna tidszoner tillåter användaren att välja sin faktiska plats och få systemet automatiskt bestämma deras sommartidsregler baserat på den platsen.

Du kan kombinera DateTimeZone med DateTime för en enkel men kraftfull funktionalitet. Du kan helt enkelt lagra och använda alla av dina tidsstämplar i UTC som standard , och konvertera dem till användarens tidszon som visas.

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

Genom att använda denna teknik kommer systemet automatiskt välj rätt sommarinställningar för användaren, utan att fråga användaren om de är i sommartid eller inte.

Du kan använda en liknande metod för att återge valmenyn. Du kan kontinuerligt tilldela tidszonen för det enstaka DateTime-objektet. Till exempel kommer den här koden att lista zonerna och deras aktuella tider, för närvarande:

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

Du kan avsevärt förenkla urvalsprocessen genom att använda lite magi på klientsidan. Javascript har en fläckig men funktionell Datumklass, med en standardmetod för att få UTC-offset på några minuter . Du kan använda detta för att begränsa listan över troliga tidszoner, under det blinda antagandet att användarens klocka är rätt.

Låt oss jämföra den här metoden med att göra det själv. Du måste faktiskt utföra datummatematik varje gång du manipulerar ett datum och tid, förutom att trycka bort ett val på användaren som de egentligen inte kommer att bry sig om. Det här är inte bara suboptimalt, det är fladdermus-guano vansinnigt. Att tvinga användare att ange när de vill ha sommarsupport är att be om problem och förvirring.

Vidare, om du vill använda det moderna PHP DateTime och DateTimeZone-ramverket för detta, måste du använd utfasad Etc/GMT... tidszonssträngar istället för namngivna tidszoner. Dessa zonnamn kan komma att tas bort från framtida PHP-versioner, så det vore oklokt att göra det. Jag säger allt detta av erfarenhet.

tl;dr :Använd den moderna verktygsuppsättningen, bespara dig själv dejtmatematikens fasor. Ge användaren en lista med namngivna tidszoner. Lagra dina datum i UTC , som inte kommer att påverkas av sommartid på något sätt. Konvertera datum och tid till användarens valda namngivna tidszon visas , inte tidigare.

Som begärt, här är en slinga över de tillgängliga tidszonerna som visar deras GMT-offset på minuter. Jag valde minuter här för att visa ett olyckligt faktum:alla förskjutningar är inte i hela timmar! Vissa byter faktiskt en halvtimme framåt under sommartid istället för en hel timme. Den resulterande förskjutningen i minuter bör matcha Javascripts Date.getTimezoneOffset .

$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. Hur man får det aktuella datumet (utan tid) i T-SQL

  2. Åtkomst nekad för användaren 'root'@'localhost' med PHPMyAdmin

  3. Hur man utför schemaändringar i MySQL &MariaDB på ett säkert sätt

  4. Eliminera duplicering av Where-uttryck i applikationen