PHP: Как преобразовать длину строки в формат длительности ISO 8601? (т.е. "30 минут" до "PT30M" )
Есть много вопросов, спрашивающих, как это сделать другим способом (преобразование из этого формата), но я не могу найти что-либо о том, как выводить в формате длительности ISO 8601 в PHP.
Итак, у меня есть куча длинных строк в человекообразном формате - я хочу конвертировать их в формат ISO 8601 "на лету", чтобы печатать длительность микроданных HTML5. Ниже приведен пример некоторых входящих строк и их форматирование.
"1 hour 30 minutes" --> PT1H30M
"5 minutes" --> PT5M
"2 hours" --> PT2H
Вы получаете идею.
Я могу вставить строку в объект интервала в PHP:
date_interval_create_from_date_string("1 hour 30 minutes");
но, похоже, не существует опции вывода ISO 8601 - как мне это сделать?
Спасибо всем.
Ответы
Ответ 1
Я сначала преобразую его в число, а затем буду работать с ним.
Сначала используйте strtotime()
:
$time = strtotime("1 hour 30 minutes", 0);
Затем вы можете анализировать его на длительность и выводить в формате PnYnMnDTnHnMnS
. Я бы использовал следующий метод (вдохновленный http://csl.sublevel3.org/php-secs-to-human-text/):
function time_to_iso8601_duration($time) {
$units = array(
"Y" => 365*24*3600,
"D" => 24*3600,
"H" => 3600,
"M" => 60,
"S" => 1,
);
$str = "P";
$istime = false;
foreach ($units as $unitName => &$unit) {
$quot = intval($time / $unit);
$time -= $quot * $unit;
$unit = $quot;
if ($unit > 0) {
if (!$istime && in_array($unitName, array("H", "M", "S"))) { // There may be a better way to do this
$str .= "T";
$istime = true;
}
$str .= strval($unit) . $unitName;
}
}
return $str;
}
Результат: http://codepad.org/1fHNlB6e
Ответ 2
Вот упрощенная версия функции Eric time_to_iso8601_duration()
. Он не теряет точности (365 дней в году) и примерно в 5 раз быстрее. Вывод менее симпатичный, но по-прежнему совместим с ISO 8601 согласно этой странице.
function iso8601_duration($seconds)
{
$days = floor($seconds / 86400);
$seconds = $seconds % 86400;
$hours = floor($seconds / 3600);
$seconds = $seconds % 3600;
$minutes = floor($seconds / 60);
$seconds = $seconds % 60;
return sprintf('P%dDT%dH%dM%dS', $days, $hours, $minutes, $seconds);
}
Ответ 3
Другой подход заключается в написании функции на основе объекта DateInterval. Формат продолжительности ISO 8601 хорошо описан.
Преимущество этого подхода состоит в том, что он выводит только соответствующие (существующие) представления и поддерживает пустые длительности (обычно обозначаемые как 'PT0S'
или 'P0D'
).
function dateIntervalToISO860Duration(\DateInterval $d) {
$duration = 'P';
if (!empty($d->y)) {
$duration .= "{$d->y}Y";
}
if (!empty($d->m)) {
$duration .= "{$d->m}M";
}
if (!empty($d->d)) {
$duration .= "{$d->d}D";
}
if (!empty($d->h) || !empty($d->i) || !empty($d->s)) {
$duration .= 'T';
if (!empty($d->h)) {
$duration .= "{$d->h}H";
}
if (!empty($d->i)) {
$duration .= "{$d->i}M";
}
if (!empty($d->s)) {
$duration .= "{$d->s}S";
}
}
if ($duration === 'P') {
$duration = 'PT0S'; // Empty duration (zero seconds)
}
return $duration;
}
Пример:
echo dateIntervalToISO860Duration(
date_diff(
new DateTime('2017-01-25 18:30:22'),
new DateTime('2019-03-11 07:12:17')
)
);
Выход: P2Y1M13DT12H41M55S