如何将字符串时长转换为ISO 8601时长格式?(例如,将“30分钟”转换为“PT30M”)

20

有很多问题都在问如何将时间格式从其它格式转换 ISO 8601,但我找不到关于如何在 PHP 中以 ISO 8601 时间段格式输出的任何信息。

所以我有一堆以人类可读格式表示的时间段字符串 - 我想要在线将它们转换为 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 的输出选项。

我应该如何处理这个问题?

3个回答

19

我建议先将其转换为数字,然后再进行处理。

首先,使用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

12

这是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);
}

2
另一种方法是基于DateInterval对象编写函数。ISO 8601 duration format有很好的描述。
这种方法的优点是它只输出相关(当前)的表示,并支持空持续时间(通常表示为'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')
    )
);

输出:2年1个月13天12小时41分钟55秒


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接