Хранить в UTC в SQLite и отображать в местном часовом поясе с помощью PHP - PullRequest
0 голосов
/ 27 апреля 2019

У меня есть таблица, содержащая столбец datetime:

$db = new SQLite3('test.db');
$results = $db->query('CREATE TABLE test (id INTEGER PRIMARY KEY AUTOINCREMENT,
                                                        date DATE, foo TEXT);');

и я добавляю строку (сохраняя дату и время добавления строки в UTC) с помощью

$results = $db->query('INSERT INTO test (date, foo) VALUES(CURRENT_TIMESTAMP, "bar");');

Это работает. Теперь при отображении строк:

$results = $db->query('SELECT * FROM test ORDER BY date desc');
while ($row = $results->fetchArray()) {
    echo $row['date'];
}

дата отображается в формате UTC: 2019-04-27 16:41:33.

Как вместо этого отобразить его в местном часовом поясе? (включая летнее время)

Я могу представить, что есть разные варианты:

  • хранить напрямую в SQLite с локальным часовым поясом (но я думаю, что это не очень хорошая практика)

  • сохраните в SQLite в UTC и выполните преобразование UTC-> местного часового пояса во время SELECT. Как?

  • сохранить в SQLite в UTC и выполнить преобразование UTC-> локального часового пояса через PHP.

Как это сделать правильно?

Ответы [ 2 ]

0 голосов
/ 28 апреля 2019

Я бы сказал, что вам нужно сохранить значения времени как нечто, называемое «меткой времени Unix», которое буквально равно количеству секунд с UTC 1 января 1970 00:00.Вы можете узнать текущее время с помощью функции PHP time().Затем измените столбец «Дата» вашей БД на целочисленный тип.Таким образом, данные времени, хранящиеся в вашей базе данных, полностью независимы от часового пояса и т. Д., Что хорошо!

Чтобы правильно интерпретировать эти часовые пояса, мы можем использовать объект PHP DateTime, который будет выполнять всю тяжелую работу всроки часовых поясов и летнее время.Следующий фрагмент кода дает основные идеи:

// These need to be provided from the client side
// Native JS will get you the offset, read my comment below for where to get DST from 
$TimeOffset = $_POST['TZOffset'];
$isDST = $_POST['isDST'];

// DST needs to be an integer
if ($isDST == 'true'){
    $isDst = 1;
}else{
    $isDst = 0;
}

// Will give a result like Europe/London
// In most use cases, save this into the users session :)
$TimeZoneName = timezone_name_from_abbr('', $TimeZone * -60, $isDst);

// Now to tell PHP we are working in this timezone
date_default_timezone_set($TimeZoneName);

///// Somewhere else in your script

// Fetched a unix timestamp from your DB; $timestamp
$DT = new DateTime();
$DT -> setTimestamp($timestamp);

// Now you have control over how it is displayed
// For instance, this gives a 2010-04-28 22:41:43 type format
// This will be correct to the user's timezone we calculated earlier
echo $DT -> format('Y-m-d H:i:s');

Если клиент находится в DST, следует получить из JS, взгляните на ответ на этот вопрос для простого метода , номногие библиотеки и т. д. также могут это делать.

Итак, большой вопрос, зачем идти дальше?

  • Данные о времени в вашей базе данных полностью не зависят от конфигурации БД / сервера.Со временем они могут бродить, и ошибки могут вступать в игру;вы хотите, чтобы ваши фундаментальные данные были согласованными.
  • Это позволяет PHP выполнять всю тяжелую работу по настройке часовых поясов и летнего времени в каждом регионе / режиме летнего времени.Быстро становится большой головной болью, если вы попытаетесь решить это самостоятельно, DST очень неудобен.
  • Математика времени гораздо эффективнее и проще, особенно в вызовах БД.Все, что вам нужно сделать, это числовое сравнение секунд, а не иметь дело с функциями SQL и т. Д. И т. Д.
  • Не полагаться на конкретные функции или механизмы БД;это просто целочисленное значение!Облегчает переносимость.

Предостережение, будьте осторожны с максимальным значением в столбце целых чисел БД.Найдите максимальные / минимальные значения, преобразуйте их в дату (, это полезный инструмент ) и сравните с вашим вариантом использования.

Последнее, что нужно сказать, это то, что вы можете использовать объект DateTime для интерпретации временных строк (как вы используете сейчас) в UTC, а затем установить часовой пояс перед их печатью.Это будет работать, но я чувствую, что это намного более подвержено ошибкам.

Надеюсь, это поможет :)

0 голосов
/ 27 апреля 2019

Как следует из комментария, на этой странице упоминается модификатор localtime.Вот решение:

$results = $db->query('SELECT datetime(date, "localtime") AS localdate, foo FROM test ORDER BY date desc');
while ($row = $results->fetchArray()) {
    echo $row['localdate'];
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...