How to convert string duration to ISO 8601 duration format? (e.g. "30 minutes" to "PT30M")

Chris picture Chris · Nov 9, 2012 · Viewed 18.5k times · Source

There are plenty of questions asking how to do this the other way (converting from this format), but I can't 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

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?

Answer

Eric picture Eric · Nov 9, 2012

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