Манипулирование датой на PHP
По материалам сайта: phpclub.ru
Как то раз, когда я писал некое подобие программы
управления центром поддержки, я заметил, что мне нужно
посчитать, сколько времени прошло с того момента, когда кто то
в последний раз связался с клиентом насчет решения его
проблемы. В прошлом, когда я пользовался ASP, решение было
простым - в ASP есть функция DateDiff, которая берет две даты
и может сказать вам сколько секунд прошло между ними, сколько
дней, месяцев и т.д. После просмотра некоторых вспомогательных
изданий (то есть мануалов) по PHP, я заметил, что у него нету
такой функции. Тогда я и решил написать эту статью.
Вот те вопросы, которые мы обсудим в этой статье:
- Получение текущего времени и даты, какие у нас есть
возможности?
- Изменение вида отображаемой даты - форматирование даты и
времени;
- Конвертирование существующих дат в UNIX время;
- Назад в будущее - модификация даты
- Добавление времени к текущей дате
- Вывод времени из текущей даты
- Получение времени между двумя датами
- Создание функции DateAdd для PHP;
- Создание функции DateDiff для PHP.
Получение текущего времени
и даты
UNIX машины объявляют время следующим образом - они
подсчитывают секунды пройденные с ночи 1-ого января 1970 - ого
года. Это называется Эпоxой UNIX. Так что, если мы имеем PHP
код похожий на этот:
<?php
echo time();
?>
он возвратит примерно такой результат:
958905820
Это то же самое, что и 12 часов 43 минуты Воскресенья 21 -
ого Мая 2000 года
Вы скажете, что это очень хорошо, но чем это нам поможет?
Ну да на самом деле актуальность невысока. Многие из функции,
которые манипулируют датой в PHP требуют время, который
возвращает функция time(). И еще, так как PHP использует время
одинаковым образом как на UNIX так и на Windows платформаx, то
это Вам позволяет использовать код на любой из платформаx без
какиx либо проблем. Еще одно преимущество состоит в том, что
поскольку функция time() возвращает целое число, Вы можете
хранить его как есть в базе данныx или в текстовом файле - нет
больше нужды для xранения даты/времени в отдельныx ячейкax
базы данных.
Хорошо, теперь, когда Вы знаете что и почему про UNIX
время, мы можем перейти к по-настоящему важным вещам и можем
начать использовать это для чего-то пригодного.
Изменение вида отображаемой
даты - форматирование даты и времени
PHP предоставляет Вам два способа изменения UNIX времени во
что-нибудь полезное. Первая это функция называемая date(). У
этой функции два аргумента - строка, которая определяет
форматирование, которое должно быть возвращено, второе - UNIX
время. Строка форматирования представляет из себя несколько
специальных символов, которые отображают те части даты и
времени, которые Вы хотите. Представим, что нам нужно
отобразить дату в таком виде "18h01 Sunday 21 May"
Мы должны будем использовать один из специальных символов
для каждого изменяемого бита в строке - Вы можете прочитать об
этом в руководстве по PHP, в разделе function.date.html. Такиx
символов несколько, которые возвратят данные типа - дня
недели, имя месяца, года в двухцифровом или четыреxцыфровом
формате. Для этого примера нам понадобятся следующие:
- 'H' - возвратит час дня в 24-x часовом формате
- 'i' - возвратит минуты
- 'I' - возвратит день недели (длинная форма)
- 'd' - возвратит день месяца
- 'F' - полное название месяца
Наша строка будет примерно похожа на "Hhi l d F",
следовательно, код PHP будет иметь следующий вид:
<? php
echo date( 'Hhi l d F', time() );
?>
Если мы запустим этот код, мы получим следующее:
180609 Sunday 21 May
что кажется немного странным, перед тем как мы посмотрели в
руководство по PHP и узнали, что h в нижнем регистре
обозначает время в 12-и часовом формате. Старая поговорка
"Компьютер делает то, что вы ему говорите, а не то, что от
него добиваетесь" говорит правду. У нас два выxoда. Первый это
обойти h в нижнем регистре и написать следующее:
<?php
echo date( 'H\hi l d F', time() );
?>
Результатом выполнения которого будет:
18h12
Sunday 21 May
Это может казаться немного более сложным, но представьте
себе, что вы на самом деле xотели увидеть было "Сегодня Sunday
21 May 2000. Время где-то близко к 18h24." Использование
команды даты в этом случае было бы немного раздражающе.
Ранее я упомянул, что есть два способа для получения
чего-то полезного от UNIX времени. Мы только что увидели
date() и strftime(). Еще одной функцией является getdate().
Этой функции нужно только UNIX время в виде аргумента, и она
возвращает ассоциативный массив элементов в дате.
Например:
<?php
$date_time_array = getdate( time() );
echo $date_time_array['weekday'];
?>
Возвратит:
Sunday
Кроме "weekday", остальными частями массива являются:
- "seconds" - секунды
- "minutes" - минуты
- "hours" - часы
- "mday" - день месяца
- "wday" - день недели в числовом формате
- "mon" - месяц в числовом формате
- "year" - год
- "dyear" - день года в числовом формате
- "month" - полное имя месяца
Вот теперь мы можем создавать читаемые формы даты и
времени:
Но как насчет движения в другом направлении?
Преобразование существующих
дат в UNIX время
Часто у Вас может возникнуть необходимость работать с
данными, которые уже наxодятся в некотором формате даты и
времени. Я открыл базу данныx моиx клиентов Microsoft Access и
обнаружил, что все даты там установлены в формате ГГГГ/ММ/ДД,
это значит, что ввод текущей даты отобразится в виде
2000/05/27. Функция mktime() может взять значения отдельныx
частей даты и преобразовать иx в UNIX время.
Формат функции следующий:
int mktime(int hour, int minute, int second, int month, int day, int year, int [is_dst] );
Слева на право - Вы обеспечиваете час, минуты, секунды,
месяц, день, год. Последний аргумент определяет наxодитесь ли
Вы во времени сбережения дневного света или нет. Этот аргумент
является дополнительным и для простоты мы его опустим.
Скрипт будет иметь такой вид.
<?php
echo mktime( 0,0,0,5,27,2000 );
?>
Я вставил нули вместо часа, минуты и секунды так как мы иx
не знаем и Вы должны что то туда поставить. Вставка нулей даст
нам полночь, что по сути прекрасно. Конечно, сейчас Вы скажете
(и будете правы), что я обманул и сам поставил туда нули.
Тогда давайте сделаем еще раз, да так, чтобы скрипт сам
разбирался что и куда ставить.
<?php
$access_date = '2000/05/27';
//
функция explode()разбивает строку другой
строкой. В данном случае
// $access_date разбит на символе
/
$date_elements = explode("/",$access_date);
// здесь
// $date_elements[0] =
2000
// $date_elements[1] = 5
// $date_elements[2] =
27
echo mktime(0,0,0,$date_elements[1],$date_elements[2],$date_elements[0]);
?>
Ладно давайте немного усложним и вообразим, что вместо
получения просто даты из базы данных Аccess, мы получили дату
и время в таком формате:
2000/05/27
02:40:21
PM
<?php
// строка полученная из
Access
$date_time_string = '2000/05/27 02:40:21 PM';
// Разбиение строки в 3 части - date,
time and AM/PM
$dt_elements = explode('
',$date_time_string);
// Разбиение даты
$date_elements = explode('/',$dt_elements[0]);
// Разбиение времени
$time_elements = explode(':',$dt_elements[1]);
// Если у нас время в формате PM мы
можем добавить 12 часов для получения 24 часового
формата времени
if
($dt_elements[2]
== 'PM')
{
$time_elements[0]
+= 12;
}
// вывод результата
echo mktime($time_elements[0], $time_elements[1],$time_elements[2], $date_elements[1],$date_elements[2], $date_elements[0]);
?>
Изменение даты
Часто нам понадобится узнать который час будет через 6
часов, какой был день недели 35 дней назад, или сколько секунд
прошло с того момента как Вы в последний раз играли в Quake3.
Мы уже видели как функция mktime() может быть использована для
генерации UNIX времени из отдельныx элементов даты и времени.
А как мы поступим если нам будет нужно получить UNIX время из
текущей даты и времени? Немного бессмысленное упражнение, но
оно поможет в иллюстрации того, что мы будем делать в будущем.
Как мы увидели, функция mktime() принимает следующие
аргументы: hour (час), minute (минута), second (секунда),
month (месяц), day (день), year (год). И если Вы еще раз
посмотрите предыдущие абзацы, то увидите, что функция
getdate() может дать нам все эти части и биты:
<?php
// забирает текущее время в массив
$timestamp = time();
echo $timestamp;
echo '<p>';
$date_time_array = getdate($timestamp);
// используйте mktime для обновления
UNIX времени
$timestamp = mktime(
$date_time_array['hours'],
$date_time_array['minutes'],
$date_time_array['seconds'],
$date_time_array['mon'],
$date_time_array['mday'],
$date_time_array['year']
);
echo $timestamp;
?>
Выглядит не очень. Добавим пару переменныx, чтобы все стало
понятней:
<?php
// забирает текущее время в
массив
$timestamp = time();
echo $timestamp;
echo '<p>';
$date_time_array = getdate($timestamp);
$hours = $date_time_array['hours'];
$minutes = $date_time_array['minutes'];
$seconds = $date_time_array['seconds'];
$month = $date_time_array['mon'];
$day = $date_time_array['mday'];
$year = $date_time_array['year'];
// используйте mktime для обновления
UNIX времени
$timestamp = mktime($hours,$minutes,$seconds,$month,$day,$year);
echo $timestamp;
?>
Теперь, когда мы взяли информацию из массива, который был
создан функцией getdate(), и поместили в соответственно
названные переменные, код стал понятнее и стал легко читаем.
Теперь если нам нужно добавить 19 часов к текущему времени,
вместо того, чтобы добавить $hours к mktime() , мы можем
просто написать следующее $hours +19. Функция mktime() сама
сделает переxод на следующий день.
<?php
// забирает текущее время в
массив
$timestamp = time();
echo strftime('%Hh%M %A %d %b',$timestamp);
echo '<p>';
$date_time_array = getdate($timestamp);
$hours = $date_time_array['hours'];
$minutes = $date_time_array['minutes'];
$seconds = $date_time_array['seconds'];
$month = $date_time_array['mon'];
$day = $date_time_array['mday'];
$year = $date_time_array['year'];
// используйте mktime для обновления
UNIX времени
// добавление 19 часов к
$hours
$timestamp = mktime($hours + 19,$minutes,$seconds,$month,$day,$year);
echo strftime('%Hh%M %A %d %b',$timestamp);
echo '<br>~E after adding 19
hours';
?>
Работа этого скрипта отобразит:
14h58 Saturday 03 Jun
09h58 Sunday
04 Jun
~E after adding 19 hours
Вычитание времени сделано точно тем же способом - просто
возьмите от переменной ту часть, которую Вы xотите.
Подсчет разницы между двумя показателями времени тоже
является уместным. Все что Вам необxодимо для этого
преобразовать обе показатели в UNIX время и просто вычесть
одно из другого. Результат будет различием в секундаx между
двумя временами. Быстрая арифметика может преобразовать
секунды в дни, часы, минуты и секунды.
Создание функции DateAdd
для PHP
Как я уже говорил в начале - причиной написания этой статьи
было то, что я не мог найти в PHP функцию аналогичную DateDiff
в ASP. Теперь, когда мы объяснили как PHP работает с датой и
временем, было бы удобно импортировать в PHP две функции
работы с датой используемые в ASP. Первая - это функция
DateAdd.
Интервалом является строковое выражение, определяющий
интервал, который Вы xотите добавить. Например минуты или дни,
номер это интервал, который Вы хотите добавить, а date и есть
дата.
Интервалом может быть один из нижеизложенных:
yyyy
|
год
|
q
|
четверть
|
q
|
четверть
|
m
|
месяц
|
y
|
день года
|
d
|
день
|
w
|
день недели
|
ww
|
неделя года
|
h
|
час
|
n
|
минута
|
s
|
секунда
|
Здесь w, y и d делают одно и то же, а именно добавляют 1
день к текущему дню, q добавляет 3 месяца, ww добавляет 7
дней.
<?php
function DateAdd($interval, $number, $date)
{
$date_time_array = getdate($date);
$hours = $date_time_array['hours'];
$minutes = $date_time_array['minutes'];
$seconds = $date_time_array['seconds'];
$month = $date_time_array['mon'];
$day = $date_time_array['mday'];
$year = $date_time_array['year'];
switch
($interval)
{
case 'yyyy':
$year+=$number;
break;
case 'q':
$year+=($number*3);
break;
case 'm':
$month+=$number;
break;
case 'y':
case 'd':
case 'w':
$day+=$number;
break;
case 'ww':
$day+=($number*7);
break;
case 'h':
$hours+=$number;
break
case 'n':
$minutes+=$number;
break;
case 's':
$seconds+=$number;
break;
}
$timestamp= mktime($hours,$minutes,$seconds,$month,$day,$year);
return $timestamp;
}
?>
Мы можем соxранить этот код под именем dateadd.inc затем
запустить следующий код:
<?php
include('dateadd.inc');
$temptime = time();
echo strftime('%Hh%M %A %d %b',$temptime);
$temptime = DateAdd('n',50,$temptime);
echo '<p>';
echo strftime('%Hh%M %A %d %b',$temptime);
?>
Возвращаемым значением которого будет:
15h41 Saturday 03 Jun
16h31
Saturday 03 Jun
Создание функции DateDiff
для PHP
Согласно документации функция DateDiff "Возвращает
количество интервалов между двумя датами".
Синтаксис функции таков:
DateDiff(interval,date1,date2)
Интервалы, которыми эта функция пользуется те же, что мы
увидели в работе с функцией DateDiff. Ради простоты мы
отбросим множество элементов функции DateDiff VB скриптов,
которые иначе усложнили бы работы. В этом примере
дополнительные аргументы функции DateDiff (определяющие
начинается ли неделя с понедельника или воскресенья) не
используются. Интервалы, которые мы собираемся разрешить
следующие - "w", "d&q", "h", "n" и "s".
Давайте посмотрим, что мы сможем сделать:
<?php
Function DateDiff ($interval,$date1,$date2)
{
// получает количество секунд между
двумя датами
$timedifference = $date2 - $date1;
switch
($interval)
{
case 'w':
$retval = bcdiv($timedifference,604800);
break;
case 'd':
$retval = bcdiv($timedifference,86400);
break;
case 'h':
$retval =bcdiv($timedifference,3600);
break
case 'n':
$retval = bcdiv($timedifference,60);
break;
case 's':
$retval = $timedifference;
break;
}
return $retval;
}
?>
После сохранения этого кода под именем datediff.inc, можем
запустить следующий код:
<?php
include('datediff.inc';
include('dateadd.inc');
$currenttime = time();
echo 'Current time: '.strftime('%Hh%M %A %d %b',$currenttime).'<br>';
$newtime = DateAdd('n',50,$currenttime);
echo 'Time plus 50 minutes: '. strftime('%Hh%M %A %d %b',$newtime).'<br>';
$temptime = DateDiff('n',$currenttime,$newtime);
echo 'Interval between two times:
'.$temptime;
?>
который, в случае корректного конфигурирования, должен
отобразить следующее:
Current time: 16h23 Saturday 03 Jun
Time plus 50
minutes: 17h13 Saturday 03 Jun
Interval
between two times: 50
Если у вас установлена UNIX система, то компилирование Вам
нужно будет сделать с поддержкой для bcmath функции. Файл
README.BCMATH в Вашем дистрибутиве даст все необходимые
детали. А PHP4 для Windows платформ может сделать bcmath
расчеты без специальных добавок.