Однажды мне пришлось столкнуться с исправлением бага на сайте. Все казалось просто. Я работал с JDate и пришлось иметь дело с часовыми поясами. Мне показалось, что хватит двух часов для того, чтобы все завершить. В итоге я потратил на это полтора дня.

Разберемся с проблемой более детально. Пользовать А заполняет форму с полем, в котором содержится дата. Лучший способ хранить дату в БД – это конвертировать ее в UTC (Всемирное координированное время). Что такое UTC? Всегда можно использовать начальную точку, а в последствии добавлять часовые пояса в зависимости от местонахождения пользователя. Важно знать, как конвертировать дату обратно в UTC. С этим может помочь JDate. Если взглянуть на класс JDate в libraries/joomla/utilities/date.php видно, что конструктор требует два параметра – дату и часовой пояс. При сохранении даты нужно сделать следующее:

$date = new JDate($myDate, $myTimezone);

Теперь разберемся, как правильно вычислить часовой пояс. В этом также поможет Joomla. Напишем несложную служебную функцию, которая выглядит следующим образом:

/** 
* Возвращает пользовательскую временную зону (если она им установлена) 
* или установленную в конфигурации Joomla 
* 
* @return object DateTimeZone 
*/ 
public static function getTimeZone() 
{ 
	$userTz = JFactory::getUser()->getParam('timezone'); 
	$timeZone = JFactory::getConfig()->get('offset'); 
	if ($userTz) 
	{ 
		$timeZone = $userTz; 
	} 
	return new DateTimeZone($timeZone); 
} 

В первой строчке указываем часовой пояс пользователя, во второй – устанавливаем глобальные настройки поясов. Если пользователь установил часовой пояс, передадим значение в объект DateTimeZone. Если же пользователь не установил часовой пояс, будет работать глобальная настройка поясов. Имея правильный часовой пояс, можно отформатировать дату в MySQL и хранить в базе данных.

$myTimezone = myHelperClass:getTimezone();
$date = new JDate($myDate, $myTimezone)->format('Y-m-d H:i:s', false, false); 

Первый параметр у функции форматирования - 'Y-m-d H:i:s'. Это формат, в котором дата будет храниться в базе данных. Второй – указывает, что нужно отображать время в GMT/UTC. Третий параметр указывает функции на то, что дату не нужно переводить.

Теперь можно сохранить корректную дату UTC в базе данных. Давайте покажем дату пользователю. Но не повторяйте мою ошибку. Когда я пытался показать дату, хранимую в БД, я посчитал, что второй параметр, который нужно передать в JDate – это часовой пояс. Я использовал служебную функцию и передал часовой пояс в качестве второго параметра. Далее, я вывел данные с помощью служебной операции, но к мооему удивлению, время отставало на два часа. Мне требовался часовой пояс Берлина - GMT+1 (и +1 для DST), но время имело вид -2. В последствии, я купил книгу Date and Time programming. Эта книга полезна детальной информацией об обсуждаемом предмете, а также будет интересна PHP разработчикам.

Я понял, что второй параметр должен помочь JDate конвертировать дату в UTC, и нужно было передать параметр часового пояса, если время было в формате UTC. Вот, что для этого нужно:

$date = new JDate($myDate);
$date->setTimezone($myTimezone);
echo $date->format(...); 

Все просто. Еще несколько полезных вещей:

  1. JHtml::_('date', $myDate) выводит автоматически дату UTC в формате пользователя и не нужно высчитывать ее самому.
  2. JHtml::_('calendar', myDate ...) не конвертирует дату в формат пользователя, так что нужно самому настроить правильные часовые пояса.
  3. При использовании календарного время в JForm, можно настроить фильтр SERVER_UTC или USER_UTC, который будет высчитывать часовые пояса.