Format "hour:minute" duration to ISO 8601 format

Asked

Viewed 182 times

0

I’m trying to turn the string 05:25 for PT05M25S.

I made it this far, change the : for M. But I couldn’t insert the rest that was missing.

$date = "05:25";

$date = preg_replace('/[:\/]/', 'M', $date);

echo $date;

2 answers

1

The problem with your code is that the bars at the beginning and end are regex delimiters. Therefore, when another bar is found in the middle of the expression, PHP thinks that regex is over and gives error. One way to solve is the one you made: escape the bar with \.

Another option is to use a different character as delimiter, since there are several other characters that can be used beyond the bar. Preferably, choose one that is not being used in regex, so you don’t have to worry about the exhaust:

// usando # como delimitador
$duration = preg_replace('#[:/]#', 'M', $duration);

But in this case, I don’t know if you need regex, after all you just want to change the character : for M, then a simple str_replace would already solve:

$duration = "05:25";
echo "PT". str_replace(':', 'M', $duration). "S";

But since you are working with durations (amounts of time), it might be interesting to use a DateInterval:

$duration = "05:25";
$partes = explode(':', $duration);
$d = DateInterval::createFromDateString("{$partes[0]} minutes + {$partes[1]} seconds");
$formatado = "PT";
if ($d->i > 0) {
    $formatado .= "{$d->i}M";
}
if ($d->s > 0) {
    $formatado .= "{$d->s}S";
}

echo $formatado; // PT5M25S

It may seem "worse" just because the code got bigger, but I think it gets a little more robust, because if the string doesn’t have numbers (for example, if it is "ab:xy"), an error will occur when creating the DateInterval. In this case, it would be enough to check if it was created:

$duration = "ab:xy"; // string inválida
$partes = explode(':', $duration);
$d = DateInterval::createFromDateString("{$partes[0]} minutes + {$partes[1]} seconds");
if ($d) {
    // $d foi criado corretamente, formatar o valor usando o código acima
} else {
    echo "erro ao criar o intervalo";
}

Already using replace, no verification is made, and it accepts any string that comes.

I included a check to not put the value in the string when it is zero, so if the string is "00:25" the result will be PT25S. To ISO 8601 standard (which defines this format for durations) says that it is okay to have zeroed values, but that these can be omitted if they are zero. It is up to you to decide whether or not to include.


Obviously it can be improved, because I didn’t check if the array returned by explode has two positions, etc. It is also unclear whether the format is always "minutes:seconds". If it is, another option is use format:

$duration = "05:25";
$partes = explode(':', $duration);
$d = DateInterval::createFromDateString("{$partes[0]} minutes + {$partes[1]} seconds");
echo $d->format('PT%iM%sS'); // PT5M25S

The difference to the previous code is that even when the values are zero they will be included in the string. For example, for "00:25" the result will be PT0M25S.

1

I did it this way:

$duration   = 05:25;

$duration   = preg_replace('/[:\/]/', 'M', $duration);

echo 'PT' . $duration . 'S';

Upshot: PT05M25S

Browser other questions tagged

You are not signed in. Login or sign up in order to post.