Статьи

Даты и время — Путь ООП

PHP-расширение Date / Time представляет собой набор классов, которые позволяют вам работать практически со всеми задачами, связанными с датой и временем. Он был доступен с момента выпуска PHP 5.2, и расширение представило несколько новых классов, все из которых сопоставлены с реальными сценариями:

  • Дата или время представлены объектом DateTime .
  • Часовой пояс мира представлен объектом DateTimeZone .
  • Объекты DateInterval представляют интервал. Например, когда мы говорим «два дня», «два дня» — это интервал. Объект DateInterval не зависит от конкретной даты или времени.
  • Объекты DatePeriod представляют период между двумя датами.

Теперь не позволяйте двум последним заметить вас, мы рассмотрим их использование в реальных условиях.


Всякий раз, когда мы хотим показать дату, которую мы использовали date() , это просто и работает. Вам просто нужно передать нужный вам формат даты. Но манипулировать им очень сложно, хорошим примером является форматирование даты и времени в соответствии с пользовательским часовым поясом.

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

1
$date = new DateTime();

Конструктор DateTime принимает строковый параметр, который по умолчанию равен «сейчас», текущему времени и дате. Чтобы создать объект на определенную дату, вы должны передать ему определенную дату и время. Форматирование параметра в большинстве случаев говорит само за себя. Ниже вы можете найти несколько различных примеров построения вашего объекта DateTime :

1
2
3
4
new DateTime(‘2013, March 24’) //DateTime representing 2013, March 24
new DateTime(‘2013-03-24’) //DateTime representing 2013, March 24
new DateTime(‘+2 days’) //DateTime representing 2 days from now on.
new DateTime(‘tomorrow’)

Когда PHP трудно понять формат, он выдаст исключение. Полный список доступного форматирования можно найти в документации

Если форматирование не соответствует вашим потребностям, вы можете указать свой собственный формат, используя DateTime::createFromFormat

1
DateTime::createFromFormat(‘jM-Y’, ’24-Mar-2013′);

Теперь, когда у нас есть объект DateTime, мы можем довольно легко сделать целый ряд вещей.

1
$date->getTimestamp();
1
2
3
4
$date->setDate(2013, 12, 30);
$date->setTime(12, 3, 20);
$date->modify(‘tomorrow’);
$date->setTimestamp(1364798550);

Обратите внимание, что когда заданы значения вне допустимого диапазона, PHP изменит дату соответствующим образом. Например, $date->setDate(2013, 12, 35); будет генерировать 2014-01-04 , то же самое касается времени.


Теперь, когда вы одержимы DateTime, следующее, что вы знаете, ваши приложения будут заполнены объектами DateTime. Вы начнете любить даты и время, как никогда раньше. Отныне вы будете иметь дело с объектами DateTime, а не со «строками», которые вы должны передавать в функцию strtotime когда вам нужно немного подсчитать.

Скажем, например, что вам нужно сравнить два дня рождения:

1
2
3
4
5
$sheldon = new DateTime(‘May 20th, 1980’);
$neo = new DateTime(‘March 11th, 1962’);
 
if ($sheldon > $neo)
    echo ‘Sheldon is younger than neo’;

Другой сценарий может быть сравнение двух дат. Мы можем сравнить даты друг с другом следующим образом:

1
$diff = $neo->diff($sheldon);

Вызов diff возвращает объект DateInterval. Если мы выбрасываем возвращаемое значение:

01
02
03
04
05
06
07
08
09
10
11
DateInterval Object
(
    [y] => 18
    [m] => 2
    [d] => 9
    [h] => 0
    [i] => 0
    [s] => 0
    [invert] => 0
    [days] => 6645
)

Это публичные объекты. Вы можете сгенерировать дружественный вывод из объекта DateInterval:

1
$diff->format(‘Neo is older by %Y years and %m months older’);

Что лучше всего в объекте DateInterval, так это то, что вы можете применить интервал к другому объекту DateTime:

1
$neo->add($diff);

Примечание. Изменения в DateTime, такие как добавление, не возвращают новые объекты DateTime, а влияют на исходный объект. Всегда помните об этом при передаче объектов DateTime по всему вашему приложению. В PHP 5.5 появился новый класс, который возвращает новые объекты после модификации.

diff — не единственное место, где вы можете создать объект DateInterval. Поскольку это класс, новые объекты могут быть инициированы как обычно:

1
$new_diff = new DateInterval(‘P2Y’);

Количество лет / месяцев / дней и т. Д. Передается конструктору в виде строки. Более подробную информацию можно найти в документации конструктора .


При создании новых объектов DateTime второй аргумент конструктора определяет часовой пояс. Если мы пропустим это, часовой пояс по умолчанию будет date.timezone в php.ini . Вы можете изменить это во время выполнения, вызвав date_default_timezone_set :

1
2
date_default_timezone_set(‘America/New_York’);
new DateTime(‘today’);

Вы также можете менять часовые пояса на лету. Как вы уже догадались, сначала нам нужен объект Timezone.

1
2
$timezone = new DateTimeZone(‘America/New_York’);
$sheldon->setTimezone($timezone);

Вы можете определить часовой пояс при создании вашего нового объекта DateTime:

1
$sheldon = new DateTime(‘May 20th, 1980’, $timezone);

Однако важно отметить, что setTimezone изменяет исходный объект DateTime. В основном мы просим «форматировать эту дату в этот часовой пояс» всякий раз, когда мы вызываем метод setTimezone . С другой стороны, в последнем примере, где мы передаем часовой пояс в конструктор DateTime, мы говорим: «Дата, которую я создаю, находится в этом часовом поясе».

Список действительных часовых поясов доступен в онлайн-документации .


Я думаю, что официальное руководство дает лучшее объяснение:

Период даты позволяет выполнять итерацию по набору дат и времени, повторяющихся через равные промежутки времени в течение заданного периода.

DatePeriod позволяет нам генерировать набор DateTimes, используя два дня, которые мы определяем между интервалами. Мы пропускаем дату начала, интервал и дату окончания. На каждом интервале создается новый объект DateTime.

Допустим, мы хотим получить все даты рождения Шелдона, начиная с его рождения:

01
02
03
04
05
06
07
08
09
10
//since birthdays occur every year, the interval is one year
$interval = new DateInterval(‘P1Y’);
 
//third argument is the end date, new DateTime() == right now
$period = new DatePeriod($sheldon, $interval, new DateTime());
 
foreach($period as $dt) {
    //DateTime objects
    echo $dt->format(‘Ymd — D’), «\n»;
}

Результат будет:

1
2
3
4
5
6
7
1981-05-20 — Wed
1982-05-20 — Thu
1983-05-20 — Fri
1984-05-20 — Sun
1985-05-20 — Mon
1986-05-20 — Tue

Теперь по умолчанию DatePeriod включает начальную дату, которую мы передаем. Однако четвертый аргумент конструктора позволяет нам пропустить начальную дату:

1
$period = new DatePeriod($sheldon, $interval, new DateTime(), DatePeriod::EXCLUDE_START_DATE);

Давайте посмотрим, сколько вечеринок у Нео было до рождения Шелдона:

1
2
$bdays = new DatePeriod($neo, $interval, $sheldon, DatePeriod::EXCLUDE_START_DATE);
echo iterator_count($bdays);

Все классы, которые мы рассмотрели сегодня, могут быть расширены для использования с вашими собственными методами. Одно из популярных применений — расширение DateTime методом __toString чтобы вы могли правильно распечатать объект DateTime без вызова format .


  • Один из моих личных подходов к использованию объектов DateTime — это работа со столбцами даты / времени в базах данных. Все даты хранятся как даты часового пояса UTC. Код приложения работает только с объектами DateTime, но перед созданием конечного запроса все даты форматируются в UTC. Этот подход позволил мне легко работать с несколькими входами часового пояса.

    Я могу передать нью-йоркский объект времени и полностью забыть о его форматировании, прежде чем перейти к базе данных. Я могу легко переключаться между метками времени Unix и обычным форматированием даты и времени в моей базе данных в любое время, мой код приложения не заботится, пока он получает объект DateTime.

  • Я также использовал DateInterval для упрощения логики оплаты подписки. Использование объектов DateInterval для определения времени между подпиской значительно упростило задачу. Мне просто нужно применить интервал до последней даты оплаты.

У вас есть хорошие примеры использования даты / времени? Поделитесь ими в комментариях.


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