PHP: Перевод даты в формате числа Double (MS Access) в формат даты PHP и наоборот

Сегодня мы поговорим о том, как преобразовать дату, представленную в виде числа типа double (используется в базе MS Access) в привычный многим формат даты языка PHP.
Для того чтобы перевести дату, представленную числом с плавающей точкой, в привычный формат нужно понимать, что обозначает это число. Вот цитата из документации Microsoft:

Тип данных «Дата/Время» хранится в Access в формате числа двойной точности с плавающей запятой и числом десятичных разрядов до 15. Целая часть числа двойной точности представляет собой дату. Дробная часть представляет время.
Дата может принимать значения от -657 434 (1 января 100 г. н.э.) до 2 958 465 (31 декабря 9999 г. н.э.). Нулевому значению даты соответствует 30 декабря 1899 г. Даты до 30 декабря 1899 г. хранятся в Access в виде отрицательных чисел.
Время может принимать значения от 0,0 (00:00:00) до 0,99999 (23:59:59). Числовое значение представляет собой долю дня. Можно перевести числовое значение в часы, минуты и секунды, умножив его на 24.

Почему майкрософт решил пойти таким путем я не знаю, возможно в этом есть какой то смысл. Однако много разработчиков сталкиваются с проблемой как же преобразовать такое число в привычный формат даты. Я приведу пример функции данного преобразования на языке PHP, однако логика реализации на других языках будет аналогична.

function fsMsDoubleDateToPhpTime($doubleDate, $asTime = true) {
      $result = strtotime('+'.((int)$doubleDate).' days', strtotime('1899-12-30 00:00:00'));
      $seconds = ($doubleDate - (int)$doubleDate) * 86400; //86400 количество секунд в сутках
      return $asTime ? $result + $seconds : date('Y-m-d H:i:s', $result + $seconds);
}

PS: Для тех кто не знаком с логикой работы PHP, функция strtotime возвращает число секунд, прошедших с полуночи 1 января 1970 года. Соответственно переменная $result хранит число секунд, прошедших с данной даты, до высчитываемой даты.

Как видно ничего сложного нет. Логика проста и понятна:
1) Получаем число прошедших дней и прибавляем их к начальной дате в результате получаем нужный день.
2) Высчитываем сколько секунд прошло от начала нужной даты (это в любом случае будет менее 1 суток (менее 86400)) и прибавляем их к результату.

Зная это, легко написать обратную функцию преобразования даты PHP в формат даты MS Access. Однако в данном случае стоит учесть временную зону сервера.

function fsPhpTimeToMsDoubleDate($timeOrDate) {
      $zone = date_default_timezone_get();
      date_default_timezone_set('UTC');
      if(!is_numeric($timeOrDate)) $timeOrDate = strtotime($timeOrDate);
      $dateFrom = $timeOrDate - strtotime('1899-12-30 00:00:00');
      $days = (int)($dateFrom / 86400); 
      date_default_timezone_set($zone);
      return $days + ($timeOrDate % 86400 / 86400);
}

Важно: Так же в связи с тем, что из расчетов были выброшены миллисекунды, при преобразовании дат, возможна погрешность в одну секунду. В большинстве случаев она не критична, однако если Вам нужны точные преобразования, необходимо учитывать и миллисекунды во время преобразования времени.

Запись опубликована в рубрике PHP с метками , , , , , , , , , . Добавьте в закладки постоянную ссылку.