Format DateInterval as ISO8601

你说的曾经没有我的故事 提交于 2019-12-01 04:33:52

问题


I am currently working on a php project and need to format a DateInterval as ISO8601 (something like this):

P5D

This format can be used to create DateTime and DateInterval objects, but I can't figure out a way to format a DateInterval into this format. Is there any? If not, what might be a lightweight solution to that?


回答1:


Well, if you look at the spec for the format when you construct one:

Y years

M months

D days

W weeks. These get converted into days, so can not be combined with D.

H hours

M minutes

S seconds

Then look at what you have to work with (http://php.net/manual/en/dateinterval.format.php), it seems like what you would do is:

$dateInterval = new DateInterval( /* whatever */ );
$format = $dateInterval->format("P%yY%mM%dD%hH%iM%sS");
//P0Y0M5D0H0M0S
//now, we need to remove anything that is a zero, but make sure to not remove
//something like 10D or 20D
$format = str_replace(["M0S", "H0M", "D0H", "M0D", "Y0M", "P0Y"], ["M", "H", "D", "M", "Y0M", "P"], $format);
echo $format;
//P0M5D

Now, the one thing I did differently is I always include the months, even if it is 0. The reason for this is that minutes and months are both represented by M - if we always include the month, then if there is a minute we know it is minutes. Otherwise we have to do a bunch of logic to see if we need to change the P to PT so it knows that the a M in this instance stands for Minute.

For example:

// For 3 Months
new DateInterval("P3M");
// For 3 Minutes
new DateInterval("PT3M"));

But instead we do:

// For 3 Months
new DateInterval("P3M");
// For 3 Minutes
new DateInterval("P0M3M"));



回答2:


With regards to @dave, I re-implemented his solution in a way that solves some of the problems, specifically the requirement to always leave a month field. From the Wikipedia article on ISO-8601, it doesn't seem like the T designation is optional, even through its completely missing from the above mentioned implementation. By introducing it we can solve most of our problems and make for some cleaner code:

function date_interval_iso_format(DateInterval $interval) {
    list($date,$time) = explode("T",$interval->format("P%yY%mM%dDT%hH%iM%sS"));
    // now, we need to remove anything that is a zero, but make sure to not remove
    // something like 10D or 20D
    $res =
        str_replace([ 'M0D', 'Y0M', 'P0Y' ], [ 'M', 'Y', 'P' ], $date) .
        rtrim(str_replace([ 'M0S', 'H0M', 'T0H'], [ 'M', 'H', 'T' ], "T$time"),"T");
    if ($res == 'P') // edge case - if we remove everything, DateInterval will hate us later
        return 'PT0S';
    return $res;
}

Note that we remove the T if it is not needed, so now both uses of M work fine:

"P5M" == date_interval_iso_format(new DateInterval("P5M")); // => true
"PT5M" == date_interval_iso_format(new DateInterval("PT5M")); // => true


来源:https://stackoverflow.com/questions/33787039/format-dateinterval-as-iso8601

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