質問

Say I have this object instance of DateInterval:

$obj=new DateInterval("P1Y12D");

Now I can do few pretty things with that $obj instance, but say I want to get out that "P1Y12D" string from the object, is it straight possible without the need to override the class?

I do not find a method for this, maybe you do.

役に立ちましたか?

解決

Here's my version of @Yaslaw's code.

It is improved according to a current PHP community and PSR requirements. I've also tried to make it more readable and straight-forward.

/**
 * @param \DateInterval $interval
 *
 * @return string
 */
function dateIntervalToString(\DateInterval $interval) {

    // Reading all non-zero date parts.
    $date = array_filter(array(
        'Y' => $interval->y,
        'M' => $interval->m,
        'D' => $interval->d
    ));

    // Reading all non-zero time parts.
    $time = array_filter(array(
        'H' => $interval->h,
        'M' => $interval->i,
        'S' => $interval->s
    ));

    $specString = 'P';

    // Adding each part to the spec-string.
    foreach ($date as $key => $value) {
        $specString .= $value . $key;
    }
    if (count($time) > 0) {
        $specString .= 'T';
        foreach ($time as $key => $value) {
            $specString .= $value . $key;
        }
    }

    return $specString;
}

And here's the extension to the initial \DateInterval class:

class CustomDateInterval extends \DateInterval
{
    public function __toString()
    {
        // Reading all non-zero date parts.
        $date = array_filter(array(
            'Y' => $this->y,
            'M' => $this->m,
            'D' => $this->d
        ));

        // Reading all non-zero time parts.
        $time = array_filter(array(
            'H' => $this->h,
            'M' => $this->i,
            'S' => $this->s
        ));

        $specString = 'P';

        // Adding each part to the spec-string.
        foreach ($date as $key => $value) {
            $specString .= $value . $key;
        }
        if (count($time) > 0) {
            $specString .= 'T';
            foreach ($time as $key => $value) {
                $specString .= $value . $key;
            }
        }

        return $specString;
    }
}

It can be used like this:

$interval = new CustomDateInterval('P1Y2M3DT4H5M6S');

// Prints "P1Y2M3DT4H5M6S".
print $interval . PHP_EOL;

I hope it will help someone, cheers!

他のヒント

You can work with the format() function:

echo $obj->format('P%yY%mM%dDT%hH%iM%sS');

Or a better readable Version (without Zero-Values in the String):

function getSpecString(DateInterval $delta){
    //Read all date-parts there are not 0
    $date = array_filter(array('Y' => $delta->y, 'M' => $delta->m, 'D' => $delta->d));
    //Read all time-parts there are not 0
    $time = array_filter(array('H' => $delta->h, 'M' => $delta->i, 'S' => $delta->s));

    //Convert each part to spec-Strings
    foreach($date as $key => &$value) $value = $value.$key;
    foreach($time as $key => &$value) $value = $value.$key;

    //Create date spec-string
    $spec = 'P' . implode('', $date);            
    //add time spec-string
    if(count($time)>0) $spec .= 'T' . implode('', $time);
    return $spec;        
}   

I'm not a C guru but in the source code of the constructor function the value does not seem to be stored at all:

/* {{{ proto DateInterval::__construct([string interval_spec])
   Creates new DateInterval object.
*/
PHP_METHOD(DateInterval, __construct)
{
    char *interval_string = NULL;
    int   interval_string_length;
    php_interval_obj *diobj;
    timelib_rel_time *reltime;
    zend_error_handling error_handling;

    zend_replace_error_handling(EH_THROW, NULL, &error_handling TSRMLS_CC);
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &interval_string, &interval_string_length) == SUCCESS) {
        if (date_interval_initialize(&reltime, interval_string, interval_string_length TSRMLS_CC) == SUCCESS) {
            diobj = zend_object_store_get_object(getThis() TSRMLS_CC);
            diobj->diff = reltime;
            diobj->initialized = 1;
        } else {
            ZVAL_NULL(getThis());
        }
    }
    zend_restore_error_handling(&error_handling TSRMLS_CC);
}
/* }}} */

Neither seem to do the date_interval_initialize() function:

static int date_interval_initialize(timelib_rel_time **rt, /*const*/ char *format, int format_length TSRMLS_DC)
{
    timelib_time     *b = NULL, *e = NULL;
    timelib_rel_time *p = NULL;
    int               r = 0;
    int               retval = 0;
    struct timelib_error_container *errors;

    timelib_strtointerval(format, format_length, &b, &e, &p, &r, &errors);

    if (errors->error_count > 0) {
        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown or bad format (%s)", format);
        retval = FAILURE;
    } else {
        if(p) {
            *rt = p;
            retval = SUCCESS;
        } else {
            if(b && e) {
                timelib_update_ts(b, NULL);
                timelib_update_ts(e, NULL);
                *rt = timelib_diff(b, e);
                retval = SUCCESS;
            } else {
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to parse interval (%s)", format);
                retval = FAILURE;
            }
        }
    }
    timelib_error_container_dtor(errors);
    return retval;
}

There is no built in function to do that, you have to create one by yourself. If you do not want to override DateInterval, try to use static methods :

class DateIntervalUtils{
    public static function getSpecString(DateInterval $i){
         $stat ="P";
         foreach($i as $key=>$value){
            if($key !=="days"){
               if($key=="h"){
                  $stat.="T";
               }
               $stat.=$value.upper($key);
             }
          }
          return $stat;
      }
  }

If you want to add functions (comparison etc.) you can add to it.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top