PHP: How to convert string duration to ISO 8601 duration format? (ie. “30 minutes” to “PT30M”)

亡梦爱人 提交于 2019-11-29 18:06:43

问题


There are plenty of questions asking how to do this the other way (converting from this format), but I cant find anything on how to output in the ISO 8601 duration format in PHP.

So I have a heap of duration strings in human readable format - I want to convert them into the ISO 8601 format on the fly to print the durations for HTML5 microdata. Below is a sample of some of the strings coming in, and how they should be formatted

"1 hour 30 minutes" --> PT1H30M
"5 minutes" --> PT5M
"2 hours" --> PT2H

You get the idea.

I can push the string into an interval object in PHP:

date_interval_create_from_date_string("1 hour 30 minutes");

but there doesn't seem to be a ISO 8601 output option - how should I approach this?

Thanks all.


回答1:


I'd convert it to a number first, then work with that.

First, use strtotime():

$time = strtotime("1 hour 30 minutes", 0);

Then you can parse it for duration, and output in PnYnMnDTnHnMnS format. I'd use the following method (inspired by 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;
}

The result: http://codepad.org/1fHNlB6e




回答2:


Here is a simplified version of Eric's time_to_iso8601_duration() function. It doesn't loose precision (365 days approximation of a year) and is about 5x faster. The output is less pretty but still ISO 8601 compatible according to this page.

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:


Another approach is to write function based on the DateInterval object. The ISO 8601 duration format is well described.

The advantage of this approach is that it only outputs the relevant (present) representations and it supports empty durations (commonly denoted as 'PT0S' or '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;
}

An example:

echo dateIntervalToISO860Duration(
    date_diff(
        new DateTime('2017-01-25 18:30:22'), 
        new DateTime('2019-03-11 07:12:17')
    )
);

Output: P2Y1M13DT12H41M55S



来源:https://stackoverflow.com/questions/13301142/php-how-to-convert-string-duration-to-iso-8601-duration-format-ie-30-minute

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!