Нормализовать DateInterval в PHP

#php #dateinterval

#php #dateinterval

Вопрос:

Ситуация / проблема

У меня проблема с DateInterval в PHP.

Учитывая следующий код

 $interval = new DateInterval("PT6000S");
echo $interval->h; // 0
echo $interval->i; // 0
echo $interval->s; // 6000
echo $interval->format("%h:%i"); // 0:0
  

Я хочу, чтобы это представляло 1 час и 40 минут, а не 6000 секунд.

Вопрос

Есть ли встроенный способ нормализовать DateInterval? Конкретный способ записи duration строки? Или это то, что должно быть сделано нормально?

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

Я провел свое исследование, но, как ни странно, я не нашел ничего полезного в этой проблеме.

Ответ №1:

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

Один из вариантов, который я использовал ранее, — добавить интервал к новому объекту DateTime, инициализированному эпохой Unix, а затем отформатировать полученное время вместо этого. Это означало бы использование строк стандартного формата даты (so h вместо %h и т.д.)

 echo (new DateTime('@0'))->add(new DateInterval("PT6000S"))->format('h:i');
// 01:40
  

Смотрите https://3v4l.org/OX6JF

Комментарии:

1. Это решение ограничено временем до 24 часов. Если количество секунд больше, результаты будут неверными. Попробуйте 3v4l.org/XLKfTL

Ответ №2:

Решение

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

Я нашел заметку пользователя в документации DateInterval.

Вы должны создать два DateTime (они могут быть любыми датой и временем), добавить свой интервал ко второму и вычесть первый из второго. Это позволит заполнить DateInterval нормализованным способом.

Вот код, написанный пользователем, завернутый в удобную функцию:

 public function createDateInterval(string $duration): DateInterval
{
    $d1 = new DateTime();
    $d2 = new DateTime();
    $d2->add(new DateInterval($duration));
    return $d2->diff($d1);
}
  

(Обратите внимание, что эта функция может выдать исключение, если ваша $duration строка неправильно отформатирована.)

Ответ №3:

Это решение использует DateTime с фиксированным временем. Почему?

DateTime также поддерживает микросекунды. Поэтому существует определенная вероятность того, что 2 вызова new Date() не вернут одно и то же время. Тогда мы можем получить неправильные результаты.

 //360000 Sec = 100 hours = 4 Days   4 hours
$di = new DateInterval("PT360000S");

$diNormalize = date_create('@0')->diff(date_create('@0')->add($di));

var_export($diNormalize);
/*
DateInterval::__set_state(array(
   'y' => 0,
   'm' => 0,
   'd' => 4,
   'h' => 4,
   'i' => 0,
   's' => 0,
   'f' => 0.0,
   'weekday' => 0,
   'weekday_behavior' => 0,
   'first_last_day_of' => 0,
   'invert' => 0,
   'days' => 4,
   'special_type' => 0,
   'special_amount' => 0,
   'have_weekday_relative' => 0,
   'have_special_relative' => 0,
)) 
*/

echo $diNormalize->format('%a days %h hours %i minutes');
//4 days 4 hours 0 minutes 
  

DateInterval имеет специальный метод format для вывода. Это следует использовать здесь, и не следует использовать обходные пути через date, gmdate или DateTime.