Mysql
 sql >> база данни >  >> RDS >> Mysql

PHP, MySQL и часови зони

Този отговор е актуализиран, за да се съобрази с наградата. Оригиналният, нередактиран отговор е под реда.

Почти всички въпроси, добавени от собственика на bounty, са във връзка с това как MySQL и PHP да взаимодействат в контекста на часовите зони.

MySQL все още има жалък поддръжка за часови зони , което означава, че интелигентността трябва да е от страна на PHP.

  • Задайте часовата зона на връзката на MySQL до UTC, както е документирано в връзката по-горе. Това ще доведе до всички дати и времена, обработвани от MySQL, включително NOW() , да се третира разумно.
  • Винаги използвайте DATETIME , никога не използвайте TIMESTAMP освен ако изрично не изисквате специалното поведение в TIMESTAMP . Това е по-малко болезнено, отколкото преди.
    • Всичко е Добре за да съхраните времето за епохата на Unix като цяло число, ако имате до, като например за наследствени цели. Епохата е UTC.
    • Предпочитаният формат за дата и час на MySQL се създава с помощта на низа за формат на датата в PHP Y-m-d H:i:s
  • Преобразуване всички PHP дати до UTC, когато ги съхранявате в MySQL, което е тривиално нещо, както е посочено по-долу
  • Datetimes, върнати от MySQL, могат да бъдат предадени безопасно на PHP DateTime конструктора. Не забравяйте да прехвърлите и UTC часова зона!
  • Преобразувайте PHP DateTime в местната часова зона на потребителя на ехо , не по-рано. За щастие сравнението DateTime и математиката спрямо други DateTimes ще вземат предвид часовата зона, в която се намира всеки.
  • Все още сте доволни от капризите на базата данни DST, предоставена с PHP. Поддържайте вашите PHP и OS корекции актуални! Поддържайте MySQL в блаженото състояние на UTC, за да премахнете едно потенциално дразнене на DST.

Това се отнася до повечето от точките.

Последното нещо е гадно:

  • Какво трябва да направи някой, ако преди това е вмъкнал данни (напр. използвайки NOW() ), без да се притеснявате за часовата зона, за да сте сигурни, че всичко остава последователно?

Това е истинска досада. Един от другите отговори посочва CONVERT_TZ , въпреки че аз лично бих го направил, като прескачам между часовите зони на сървъра и UTC по време на избори и актуализации, защото аз съм хардкор като такъв.

приложението също трябва да може да задава/избира съответно DST за всеки потребител.

Не е нужно и не трябва направете това в съвременната ера.

Съвременните версии на PHP имат DateTimeZone клас, който включва възможността за изброяване на часови зони с име . Наименуваните часови зони позволяват на потребителя да избере действителното си местоположение и да настрои системата автоматично определят своите правила за DST въз основа на това местоположение.

Можете да комбинирате DateTimeZone с DateTime за някои прости, но мощни функции. Можете просто да съхранявате и използвате всички от вашите времеви марки в UTC по подразбиране и ги преобразувайте в часовата зона на потребителя на дисплея.

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

Използвайки тази техника, системата ще автоматично изберете правилните настройки за DST за потребителя, без да питате потребителя дали в момента е в DST или не.

Можете да използвате подобен метод за изобразяване на менюто за избор. Можете непрекъснато да преназначавате часовата зона за единичния обект DateTime. Например, този код ще изброява зоните и тяхното текущо време в този момент:

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

Можете значително да опростите процеса на избор, като използвате магия от страна на клиента. Javascript има петнист, но функционален Клас Date, със стандартен метод за получаване на UTC отместване за минути . Можете да използвате това, за да стесните списъка с вероятни часови зони, при сляпото предположение, че часовникът на потребителя е правилен.

Нека сравним този метод с това да го направите сами. Ще трябва действително да извършвате математика за дата всеки път вие манипулирате дата и час, в допълнение към изтласкването на избор на потребителя, за който наистина няма да го интересува. Това не е просто неоптимално, това е лудост прилеп-гуано. Принуждаването на потребителите да посочват, когато искат поддръжка за DST, изисква проблеми и объркване.

Освен това, ако искате да използвате модерната PHP DateTime и DateTimeZone рамка за това, ще трябва да използвайте отхвърления Etc/GMT... низове за часови зони вместо наименувани часови зони. Тези имена на зони може да бъдат премахнати от бъдещи версии на PHP, така че би било неразумно да се прави това. Казвам всичко това от опит.

tl;dr :Използвайте съвременния набор от инструменти, спестете си ужасите на математиката за дати. Представете на потребителя списък с именувани времеви зони. Съхранете датите си в UTC , което няма да бъде повлияно от DST по никакъв начин. Преобразувайте датите и часа в избраната от потребителя именувана часова зона на дисплей , не по-рано.

Както е поискано, ето цикъл върху наличните часови зони, показващ тяхното GMT изместване в минути. Тук избрах минути, за да демонстрирам един жалък факт:не всички компенсации са в цели часове! Някои всъщност превключват половин час напред по време на DST вместо цял час. Полученото изместване в минути трябва съвпада с този на Date.getTimezoneOffset на Javascript .

$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. TRIGGERS, които причиняват неуспех на INSERT? Възможен?

  2. Как да получите данни за последните 12 месеца в MySQL

  3. Как да увеличите максималния брой връзки в MySQL

  4. Грешка:Клиентът не поддържа протокол за удостоверяване, поискан от сървъра; помислете за надграждане на MySQL клиента

  5. Как да попълним таблица с диапазон от дати?