问题
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