Search code examples
phpdateinterval

DateInterval doesn't accept ISO 8601 timeperiod with milliseconds


I have this ISO 8601 time period string: P0Y0M0DT3H5M0.000S and PHP7.4 fails to construct a DateInterval with it.

<?php
$d = new \DateInterval('P0Y0M0DT3H5M0.000S');
var_dump($d);

Fatal error: Uncaught Exception: DateInterval::__construct(): Unknown or bad format (P0Y0M0DT3H5M1.33S) in [...][...]:2

It fails for the milliseconds. When I omit the milliseconds -P0Y0M0DT3H5M0S- it works fine.

With milliseconds it should be a valid ISO 8601 string afaik.
According to Wikipedia this is the format:

[Start]P[JY][MM][WW][TD][T[hH][mM][s[.f]S]]
https://de.wikipedia.org/wiki/ISO_8601#Zeitspannen

Why doesnt PHP accept this format and how can I work around this?


Solution

  • You can use DateInterval::createFromDateString.

    $d = DateInterval::createFromDateString('3 Hours 5 Minutes 500000 microseconds');
    
    echo $d->format('%h Hours %m Minutes %s.%F Seconds');
    //3 Hours 0 Minutes 0.500000 Seconds
    

    The following function can be used as a workaround if an expression like P0Y0M0DT3H5M7.520S is specified.

    function createDateInterval($interval_spec){
      $f = 0.0;
      if(preg_match('~\.\d+~',$interval_spec,$match)){
        $interval_spec = str_replace($match[0], "", $interval_spec);
        $f = (float)$match[0];
      }
      $di = new \Dateinterval($interval_spec);
      $di->f= $f;
      return $di;
    }
    
    $d = createDateInterval('P0Y0M0DT3H5M7.520S');
    echo '<pre>';
    var_export($d);
    

    Result:

    DateInterval::__set_state(array(
       'y' => 0,
       'm' => 0,
       'd' => 0,
       'h' => 3,
       'i' => 5,
       's' => 7,
       'f' => 0.52,
       'weekday' => 0,
       'weekday_behavior' => 0,
       'first_last_day_of' => 0,
       'invert' => 0,
       'days' => false,
       'special_type' => 0,
       'special_amount' => 0,
       'have_weekday_relative' => 0,
       'have_special_relative' => 0,
    ))