3

I want to extend the DateInterval class to add my own methods. For this I want to create an instance of the DateIntervalEx extension class from a DateInterval object. Example:

$dateInterval = date_create('yesterday')->diff(date_create('today 13:24'));

$diEx = new DateIntervalEx($dateInterval);

My attempt for the class:

class DateIntervalEx extends Dateinterval{
  public function __construct(DateInterval $interval){
    parent::__construct('P0D');

    foreach($interval as $prop => $value){
      $this->$prop = $value;
    }
  }
}

The diff() method returns a DateInterval with $days == 1

DateInterval::__set_state(array(
   'y' => 0,
   'm' => 0,
   'd' => 1,
   'h' => 13,
   'i' => 24,
   's' => 0,
   'f' => 0.0,
   'weekday' => 0,
   'weekday_behavior' => 0,
   'first_last_day_of' => 0,
   'invert' => 0,
   'days' => 1,
   'special_type' => 0,
   'special_amount' => 0,
   'have_weekday_relative' => 0,
   'have_special_relative' => 0,
))

But my extension class returns days => false.

DateIntervalEx::__set_state(array(
   'weekday' => 0,
   'weekday_behavior' => 0,
   'first_last_day_of' => 0,
   'days' => false,
   'special_type' => 0,
   'special_amount' => 0,
   'have_weekday_relative' => 0,
   'have_special_relative' => 0,
   'y' => 0,
   'm' => 0,
   'd' => 1,
   'h' => 13,
   'i' => 24,
   's' => 0,
   'f' => 0.0,
   'invert' => 0,
))

How can I set the days property to the correct value?

yivi
  • 42,438
  • 18
  • 116
  • 138
jspit
  • 7,276
  • 1
  • 9
  • 17
  • 2
    Not sure if that is possible. https://www.php.net/manual/en/class.dateinterval.php#dateinterval.props.days: _“[days] If the DateInterval object was created by DateTime::diff(), then this is the total number of days between the start and end dates. Otherwise, days will be FALSE.”_ – CBroe May 05 '20 at 07:29
  • Even if I replace the content of your constructor function with just `parent::__construct($interval->format('P%yY%mM%dDT%hH%iM%sS'));`, the result stays the same - `days` in the resulting object is false. – CBroe May 05 '20 at 07:31

1 Answers1

2

It's not possible to do on PHP.

The $days property is set by the PHP runtime if the DateInterval was created using DateTime::diff(), as you probably saw on the docs:

days

If the DateInterval object was created by DateTime::diff(), then this is the total number of days between the start and end dates. Otherwise, days will be FALSE.

Before PHP 5.4.20/5.5.4 instead of FALSE you will receive -99999 upon accessing the property.

Check how two important DateTime extension projects deal with this (e.g. they don't):

Chronos (ChronosInterval extends DateTimeInterval):

/**
 * Create a ChronosInterval instance from a DateInterval one.  Can not instance
 * DateInterval objects created from DateTime::diff() as you can't externally
 * set the $days field.
 *
 * @param \DateInterval $di The DateInterval instance to copy.
 * @throws \InvalidArgumentException
 * @return static
 */
public static function instance(DateInterval $di): self
{
   if (static::wasCreatedFromDiff($di)) {
       throw new InvalidArgumentException(
           "Can not instance a DateInterval object created from DateTime::diff()."
       );
}
// ...

Carbon (CarbonInterval extends from DateTimeInterval)

/**
 * Create a CarbonInterval instance from a DateInterval one.  Can not instance
 * DateInterval objects created from DateTime::diff() as you can't externally
 * set the $days field.
 *
 * @param DateInterval $interval
 *
 * @return static
 */
public static function instance(DateInterval $interval)
{
    return self::castIntervalToClass($interval, static::class);
}

You can check the relevant C code here.

yivi
  • 42,438
  • 18
  • 116
  • 138