Pull to refresh

Решение проблемы 2038 года на PHP 5.2

19 января 2038 года в 03:14:07 по Всемирному времени, в приложениях, работающих под 32-битной версией PHP, может произойти сбой. В этот момент, стандартные функции работы с датой и временем перестанут корректно обрабатывать текущее время.


 


Все это связано с тем, что для представления даты и времени используется целое число. Данное число представляет собой количество секунд прошедших с начала эпохи UNIX, а именно с полночи 1 января 1970 года по Всемирному времени. В 32-битной версии PHP для хранения этого числа используется 32-битное целое со знаком. Максимально возможным значением для такого типа является 2 147 483 647, которое соответствует указанной критической дате.



Существует большая степень вероятности того, что к 2038 году все функционирующие системы и PHP-интерпретаторы будут 64-битные. Такое изменение, даст возможность беспрепятственно работать с датой примерно на 290 миллиардов лет вперед. Однако возникает сомнение, что это произойдет к 2038 году.


 


Еще одной проблемой 2038 года является невозможность работы с датами в прошлом и в будущем, уже сейчас. Под данное ограничение подпадают даты находящиеся до 1902 и после 2037 года.


 


Пути решения


Существует 2 способа решения данной проблемы:


  1. Не делать ничего, т.к. к 2038 году проблема будет решена естественным образом;
  2. Использовать встроенный класс «DateTime».

Первый способ полностью себя исчерпывает и, несмотря на свою простоту, является недальновидным.


Второй способ, напротив, имеет право на существование. О нем и пойдет речь далее.


 


Класс «DateTime»


Класс «DateTime», появившийся в PHP 5.2, призван полностью решить проблему 2038 года. Однако, программистам, привыкшим к стандартным функциям обработки даты и времени, работать с этим классом будет неудобно. Для ускорения процесса разработки приложений лучше всего использовать функции являющиеся интерфейсом к классу «DateTime».


 


Чтобы упростить жизнь программистов, я написал несколько аналогов часто используемых функций работы с датой и временем. Стоит заметить, что входные параметры и поведение функций не идентично встроенным аналогам.


 


Функция получения текущей метки времени Unix


<source lang="php">
//
// Улучшенная функция «time»
// (функция возвращает текущую метку времени)
//
function enhanced_time()
{
  $DateTime_obj = new DateTime();
  return $DateTime_obj->format("U");
}
</source>

 


Функции вывода даты и времени в определенном формате


<source lang="php">
//
// Улучшенная функция «date»
// (функция форматирует системную дату/время)
//
function enhanced_date($format_str, $timestamp = NULL, $timezone = NULL)
{
  //
  // Явно объявить переменные
  //
  settype($format_str, "string"); // Формат, в котором следует выводить дату и время



  //
  // Если не указана метка времени - использовать текущую метку времени
  //
  if (is_null($timestamp))
  {
    $timestamp = "now";
  }
  else // Иначе - использовать переданную метку времени
  {
    $timestamp = "@" . number_format($timestamp, 0, ".", "");
  }



  //
  // Если не указан часовой пояс - использовать часовой пояс по умолчанию
  //
  if (!is_string($timezone))
  {
    $timezone = date_default_timezone_get();
  }



  //
  // Создать экземпляр класса DateTime с необходимыми параметрами 
  //
  $DateTime_obj = new DateTime($timestamp);
  $DateTime_obj->setTimezone(new DateTimeZone($timezone));



  //
  // Вернуть дату и время в указанном формате
  //
  return $DateTime_obj->format($format_str);
}



//
// Улучшенная функция «gmdate»
// (функция форматирует системную дату/время по Гринвичу)
//
function enhanced_gmdate($format_str, $timestamp = NULL)
{
  return enhanced_date($format_str, $timestamp, "UTC");
}
</source>

 


Функция получения информации о метке времени Unix


<source lang="php">
//
// Улучшенная функция «getdate»
// (функция возвращает информацию о дате/времени)
//
function enhanced_getdate($timestamp = NULL, $timezone = NULL)
{
  //
  // Получить информации о дате/времени в виде неассоциативного массива
  //
  $arr = explode("=", enhanced_date("s=i=H=d=w=m=Y=z=l=F=U", $timestamp, $timezone));



  //
  // Вернуть информацию о дате/времени в виде ассоциативного массива
  //
  return array(
                "seconds" => (int) $arr[0], 
                "minutes" => (int) $arr[1], 
                "hours"   => (int) $arr[2], 
                "mday"    => (int) $arr[3], 
                "wday"    => (int) $arr[4], 
                "mon"     => (int) $arr[5], 
                "year"    => (int) $arr[6], 
                "yday"    => (int) $arr[7], 
                "weekday" =>       $arr[8], 
                "month"   =>       $arr[9], 
                0         =>       $arr[10]                
              );
}
</source>

 


Функции формирования метки времени Unix для заданной даты и времени


<source lang="php">
//
// Улучшенная функция «mktime»
// (функция возвращает метку времени для заданной даты)
//
function enhanced_mktime($timezone = NULL, $hour = NULL, $minute = NULL, $second = NULL, $month = NULL, $day = NULL, $year = NULL)
{
  //
  // Если не указан часовой пояс - использовать часовой пояс по умолчанию
  //
  if (!is_string($timezone))
  {
    $timezone = date_default_timezone_get();
  }



  //
  // Получить массив информации о времени по умолчанию
  //
  $default_datetime_arr = enhanced_getdate(NULL, $timezone);
  


  //
  // Заполнить значениями по умолчанию, параметры, которые не были переданы в функцию
  //
  if (is_null($hour))   { $hour   = $default_datetime_arr["hours"]; }
  if (is_null($minute)) { $minute = $default_datetime_arr["minutes"]; }
  if (is_null($second)) { $second = $default_datetime_arr["seconds"]; }
  if (is_null($month))  { $month  = $default_datetime_arr["mon"]; }
  if (is_null($day))    { $day    = $default_datetime_arr["mday"]; }
  if (is_null($year))   { $year   = $default_datetime_arr["year"]; }



  //
  // Изменить тип переменных при необходимости
  //
  settype($hour, "integer");
  settype($minute, "integer");
  settype($second, "integer");
  settype($month, "integer");
  settype($day, "integer");
  settype($year, "integer");



  //
  // Создать экземпляр класса DateTime с необходимыми параметрами
  //
  $DateTime_obj = new DateTime();
  $DateTime_obj->setTimezone(new DateTimeZone($timezone));
  $DateTime_obj->setDate($year, $month, $day);
  $DateTime_obj->setTime($hour, $minute, $second);



  //
  // Вернуть метку времени
  //
  return $DateTime_obj->format("U");
}



//
// Улучшенная функция «gmmktime»
// (возвращает метку времени Unix для времени по Гринвичу)
//
function enhanced_gmmktime($hour = NULL, $minute = NULL, $second = NULL, $month = NULL, $day = NULL, $year = NULL)
{
  return enhanced_mktime("UTC", $hour, $minute, $second, $month, $day, $year);
}
</source>

 


Заключение


Не стоит забывать, что теперь, при использовании типичных функций, в обязательном порядке, следует указывать часовой пояс по умолчанию. Делать это необходимо следующим образом:


<source lang="php">
//
// Установить часовой пояс по умолчанию
//
date_default_timezone_set("Asia/Bangkok");
</source>

 


Также приведу несколько вариантов применения указанных функций:


<source lang="php">
//
// Получить и вывести текущую метку времени Unix
//
$timestamp_now = time();
echo $timestamp_now . "<br>";

$timestamp_now_e = enhanced_time();
echo $timestamp_now_e . "<br><br>";



//
// Получить и вывести информацию о текущей метке времени Unix
//
echo "<pre>";
var_dump(getdate($timestamp_now));
var_dump(enhanced_getdate($timestamp_now_e));
echo "
";

//
// Вывести текущую дату и время в указанном формате
//
echo date(«Y-m-d H:i:s», $timestamp_now). "
";
echo enhanced_date(«Y-m-d H:i:s», $timestamp_now_e). "

";

//
// Получить и вывести метку времени Unix для даты и времени в далеком будущем
//
$year = 2050;
$month = 3;
$day = 18;
$hour = 22;
$minute = 56;
$second = 53;

$timestamp_future = mktime($hour, $minute, $second, $month, $day, $year);
echo $timestamp_future. "
";

$timestamp_future_e = enhanced_mktime(NULL, $hour, $minute, $second, $month, $day, $year);
echo $timestamp_future_e. "

";

//
// Вывести дату и время в будущем в указанном формате
//
echo date(«Y-m-d H:i:s», «2531257013»). "
";
echo enhanced_date(«Y-m-d H:i:s», «2531257013»). "

";

 


Ссылки


Проблема 2038 года
UNIX-время
Date/Time Функции
Класс «DateTime»
Список поддерживаемых часовых поясов

Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.