diff --git a/ext/date/php_date.c b/ext/date/php_date.c index 02236d6676ea7..93f8c51d9948f 100644 --- a/ext/date/php_date.c +++ b/ext/date/php_date.c @@ -3844,12 +3844,74 @@ PHP_METHOD(DateTimeImmutable, setTimestamp) } /* }}} */ +/* {{{ */ +PHP_METHOD(DateTimeImmutable, setMicroseconds) +{ + zval *object, new_object; + php_date_obj *dateobj, *new_dateobj; + zend_long us; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &us) == FAILURE) { + RETURN_THROWS(); + } + + if (UNEXPECTED(us < 0 || us > 999999)) { + zend_throw_error( + date_ce_date_range_error, + "Microseconds must be between 0 and 999999, "ZEND_LONG_FMT" given", + us + ); + RETURN_THROWS(); + } + + object = ZEND_THIS; + dateobj = Z_PHPDATE_P(object); + DATE_CHECK_INITIALIZED(dateobj->time, Z_OBJCE_P(object)); + + date_clone_immutable(object, &new_object); + new_dateobj = Z_PHPDATE_P(&new_object); + + php_date_set_time_fraction(new_dateobj->time, (int)us); + + RETURN_OBJ(Z_OBJ(new_object)); +} +/* }}} */ + +/* {{{ */ +PHP_METHOD(DateTime, setMicroseconds) +{ + zval *object; + php_date_obj *dateobj; + zend_long us; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &us) == FAILURE) { + RETURN_THROWS(); + } + + if (UNEXPECTED(us < 0 || us > 999999)) { + zend_throw_error( + date_ce_date_range_error, + "Microseconds must be between 0 and 999999, "ZEND_LONG_FMT" given", + us + ); + RETURN_THROWS(); + } + + object = ZEND_THIS; + dateobj = Z_PHPDATE_P(object); + DATE_CHECK_INITIALIZED(dateobj->time, Z_OBJCE_P(object)); + php_date_set_time_fraction(dateobj->time, (int)us); + + RETURN_OBJ_COPY(Z_OBJ_P(object)); +} +/* }}} */ + /* {{{ Gets the Unix timestamp. */ PHP_FUNCTION(date_timestamp_get) { zval *object; php_date_obj *dateobj; - zend_long timestamp; + zend_long timestamp; int epoch_does_not_fit_in_zend_long; if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &object, date_ce_interface) == FAILURE) { @@ -3873,6 +3935,21 @@ PHP_FUNCTION(date_timestamp_get) } /* }}} */ +PHP_METHOD(DateTime, getMicroseconds) /* {{{ */ +{ + zval *object; + php_date_obj *dateobj; + + ZEND_PARSE_PARAMETERS_NONE(); + + object = ZEND_THIS; + dateobj = Z_PHPDATE_P(object); + DATE_CHECK_INITIALIZED(dateobj->time, Z_OBJCE_P(object)); + + RETURN_LONG((zend_long)dateobj->time->us); +} +/* }}} */ + /* {{{ Returns the difference between two DateTime objects. */ PHP_FUNCTION(date_diff) { diff --git a/ext/date/php_date.stub.php b/ext/date/php_date.stub.php index 7ba05b8b6e062..888e6bc8fab2b 100644 --- a/ext/date/php_date.stub.php +++ b/ext/date/php_date.stub.php @@ -412,6 +412,9 @@ public function setTimezone(DateTimeZone $timezone): DateTime {} */ public function getOffset(): int {} + /** @tentative-return-type */ + public function getMicroseconds(): int {} + /** * @tentative-return-type * @alias date_time_set @@ -436,6 +439,9 @@ public function setISODate(int $year, int $week, int $dayOfWeek = 1): DateTime { */ public function setTimestamp(int $timestamp): DateTime {} + /** @tentative-return-type */ + public function setMicroseconds(int $microseconds): static {} + /** * @tentative-return-type * @alias date_timestamp_get @@ -503,6 +509,12 @@ public function getOffset(): int {} */ public function getTimestamp(): int {} + /** + * @alias DateTime::getMicroseconds + * @tentative-return-type + */ + public function getMicroseconds(): int {} + /** * @tentative-return-type * @alias date_diff @@ -533,6 +545,9 @@ public function setISODate(int $year, int $week, int $dayOfWeek = 1): DateTimeIm /** @tentative-return-type */ public function setTimestamp(int $timestamp): DateTimeImmutable {} + /** @tentative-return-type */ + public function setMicroseconds(int $microseconds): static {} + /** @tentative-return-type */ public static function createFromMutable(DateTime $object): static {} diff --git a/ext/date/php_date_arginfo.h b/ext/date/php_date_arginfo.h index 027bec67cb08d..22692a819e06c 100644 --- a/ext/date/php_date_arginfo.h +++ b/ext/date/php_date_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 1445f6053da5ca9dc7bb618f2eadc4a8ea56a15f */ + * Stub hash: 6fb121a5992ae96d12dea6055d1b0f0d6534cf21 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_strtotime, 0, 1, MAY_BE_LONG|MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, datetime, IS_STRING, 0) @@ -307,6 +307,8 @@ ZEND_END_ARG_INFO() #define arginfo_class_DateTime_getOffset arginfo_class_DateTimeInterface_getOffset +#define arginfo_class_DateTime_getMicroseconds arginfo_class_DateTimeInterface_getOffset + ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_OBJ_INFO_EX(arginfo_class_DateTime_setTime, 0, 2, DateTime, 0) ZEND_ARG_TYPE_INFO(0, hour, IS_LONG, 0) ZEND_ARG_TYPE_INFO(0, minute, IS_LONG, 0) @@ -330,6 +332,10 @@ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_OBJ_INFO_EX(arginfo_class_DateTime_setTimes ZEND_ARG_TYPE_INFO(0, timestamp, IS_LONG, 0) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_DateTime_setMicroseconds, 0, 1, IS_STATIC, 0) + ZEND_ARG_TYPE_INFO(0, microseconds, IS_LONG, 0) +ZEND_END_ARG_INFO() + #define arginfo_class_DateTime_getTimestamp arginfo_class_DateTimeInterface_getOffset #define arginfo_class_DateTime_diff arginfo_class_DateTimeInterface_diff @@ -364,6 +370,8 @@ ZEND_END_ARG_INFO() #define arginfo_class_DateTimeImmutable_getTimestamp arginfo_class_DateTimeInterface_getOffset +#define arginfo_class_DateTimeImmutable_getMicroseconds arginfo_class_DateTimeInterface_getOffset + #define arginfo_class_DateTimeImmutable_diff arginfo_class_DateTimeInterface_diff ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_DateTimeImmutable_modify, 0, 1, DateTimeImmutable, MAY_BE_FALSE) @@ -403,6 +411,8 @@ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_OBJ_INFO_EX(arginfo_class_DateTimeImmutable ZEND_ARG_TYPE_INFO(0, timestamp, IS_LONG, 0) ZEND_END_ARG_INFO() +#define arginfo_class_DateTimeImmutable_setMicroseconds arginfo_class_DateTime_setMicroseconds + ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_DateTimeImmutable_createFromMutable, 0, 1, IS_STATIC, 0) ZEND_ARG_OBJ_INFO(0, object, DateTime, 0) ZEND_END_ARG_INFO() @@ -563,6 +573,8 @@ ZEND_METHOD(DateTime, createFromInterface); ZEND_METHOD(DateTime, createFromTimestamp); ZEND_METHOD(DateTime, modify); ZEND_METHOD(DateTime, sub); +ZEND_METHOD(DateTime, getMicroseconds); +ZEND_METHOD(DateTime, setMicroseconds); ZEND_METHOD(DateTimeImmutable, __construct); ZEND_METHOD(DateTimeImmutable, __serialize); ZEND_METHOD(DateTimeImmutable, __unserialize); @@ -577,6 +589,7 @@ ZEND_METHOD(DateTimeImmutable, setTime); ZEND_METHOD(DateTimeImmutable, setDate); ZEND_METHOD(DateTimeImmutable, setISODate); ZEND_METHOD(DateTimeImmutable, setTimestamp); +ZEND_METHOD(DateTimeImmutable, setMicroseconds); ZEND_METHOD(DateTimeImmutable, createFromMutable); ZEND_METHOD(DateTimeImmutable, createFromInterface); ZEND_METHOD(DateTimeZone, __construct); @@ -687,10 +700,12 @@ static const zend_function_entry class_DateTime_methods[] = { ZEND_ME_MAPPING(getTimezone, date_timezone_get, arginfo_class_DateTime_getTimezone, ZEND_ACC_PUBLIC) ZEND_ME_MAPPING(setTimezone, date_timezone_set, arginfo_class_DateTime_setTimezone, ZEND_ACC_PUBLIC) ZEND_ME_MAPPING(getOffset, date_offset_get, arginfo_class_DateTime_getOffset, ZEND_ACC_PUBLIC) + ZEND_ME(DateTime, getMicroseconds, arginfo_class_DateTime_getMicroseconds, ZEND_ACC_PUBLIC) ZEND_ME_MAPPING(setTime, date_time_set, arginfo_class_DateTime_setTime, ZEND_ACC_PUBLIC) ZEND_ME_MAPPING(setDate, date_date_set, arginfo_class_DateTime_setDate, ZEND_ACC_PUBLIC) ZEND_ME_MAPPING(setISODate, date_isodate_set, arginfo_class_DateTime_setISODate, ZEND_ACC_PUBLIC) ZEND_ME_MAPPING(setTimestamp, date_timestamp_set, arginfo_class_DateTime_setTimestamp, ZEND_ACC_PUBLIC) + ZEND_ME(DateTime, setMicroseconds, arginfo_class_DateTime_setMicroseconds, ZEND_ACC_PUBLIC) ZEND_ME_MAPPING(getTimestamp, date_timestamp_get, arginfo_class_DateTime_getTimestamp, ZEND_ACC_PUBLIC) ZEND_ME_MAPPING(diff, date_diff, arginfo_class_DateTime_diff, ZEND_ACC_PUBLIC) ZEND_FE_END @@ -710,6 +725,7 @@ static const zend_function_entry class_DateTimeImmutable_methods[] = { ZEND_ME_MAPPING(getTimezone, date_timezone_get, arginfo_class_DateTimeImmutable_getTimezone, ZEND_ACC_PUBLIC) ZEND_ME_MAPPING(getOffset, date_offset_get, arginfo_class_DateTimeImmutable_getOffset, ZEND_ACC_PUBLIC) ZEND_ME_MAPPING(getTimestamp, date_timestamp_get, arginfo_class_DateTimeImmutable_getTimestamp, ZEND_ACC_PUBLIC) + ZEND_MALIAS(DateTime, getMicroseconds, getMicroseconds, arginfo_class_DateTimeImmutable_getMicroseconds, ZEND_ACC_PUBLIC) ZEND_ME_MAPPING(diff, date_diff, arginfo_class_DateTimeImmutable_diff, ZEND_ACC_PUBLIC) ZEND_ME(DateTimeImmutable, modify, arginfo_class_DateTimeImmutable_modify, ZEND_ACC_PUBLIC) ZEND_ME(DateTimeImmutable, add, arginfo_class_DateTimeImmutable_add, ZEND_ACC_PUBLIC) @@ -719,6 +735,7 @@ static const zend_function_entry class_DateTimeImmutable_methods[] = { ZEND_ME(DateTimeImmutable, setDate, arginfo_class_DateTimeImmutable_setDate, ZEND_ACC_PUBLIC) ZEND_ME(DateTimeImmutable, setISODate, arginfo_class_DateTimeImmutable_setISODate, ZEND_ACC_PUBLIC) ZEND_ME(DateTimeImmutable, setTimestamp, arginfo_class_DateTimeImmutable_setTimestamp, ZEND_ACC_PUBLIC) + ZEND_ME(DateTimeImmutable, setMicroseconds, arginfo_class_DateTimeImmutable_setMicroseconds, ZEND_ACC_PUBLIC) ZEND_ME(DateTimeImmutable, createFromMutable, arginfo_class_DateTimeImmutable_createFromMutable, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) ZEND_ME(DateTimeImmutable, createFromInterface, arginfo_class_DateTimeImmutable_createFromInterface, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) ZEND_FE_END diff --git a/ext/date/tests/getSetMicroseconds.phpt b/ext/date/tests/getSetMicroseconds.phpt new file mode 100644 index 0000000000000..07ca8eb11e834 --- /dev/null +++ b/ext/date/tests/getSetMicroseconds.phpt @@ -0,0 +1,197 @@ +--TEST-- +Tests for DateTime[Immutable]::[get|set]Microseconds +--FILE-- +getMicroseconds(), true) . "\n"; +var_dump($dt); + +echo 'DateTimeImmutable::getMicroseconds(): ' . var_export($dti->getMicroseconds(), true) . "\n"; +var_dump($dti); + +echo 'MyDateTime::getMicroseconds(): ' . var_export($myDt->getMicroseconds(), true) . "\n"; +var_dump($myDt); + +echo 'MyDateTimeImmutable::getMicroseconds(): ' . var_export($myDti->getMicroseconds(), true) . "\n"; +var_dump($myDti); + +foreach ($microsecondsList as $microseconds) { + echo "##################################\n"; + + echo 'DateTime::setMicroseconds('.var_export($microseconds, true).'):'; + try { + var_dump($dt->setMicroseconds($microseconds)); + } catch (Throwable $e) { + echo get_class($e) . ' ' . $e->getMessage() . "\n"; + } + echo 'DateTime::getMicroseconds(): ' . var_export($dt->getMicroseconds(), true) . "\n"; + + echo 'DateTimeImmutable::setMicroseconds('.var_export($microseconds, true).'):'; + try { + var_dump($dti->setMicroseconds($microseconds)); + } catch (Throwable $e) { + echo get_class($e) . ' ' . $e->getMessage() . "\n"; + } + echo 'DateTimeImmutable::getMicroseconds(): ' . var_export($dti->getMicroseconds(), true) . "\n"; + + echo 'MyDateTime::setMicroseconds('.var_export($microseconds, true).'):'; + try { + var_dump($myDt->setMicroseconds($microseconds)); + } catch (Throwable $e) { + echo get_class($e) . ' ' . $e->getMessage() . "\n"; + } + echo 'MyDateTime::getMicroseconds(): ' . var_export($myDt->getMicroseconds(), true) . "\n"; + + echo 'MyDateTimeImmutable::setMicroseconds('.var_export($microseconds, true).'):'; + try { + var_dump($myDti->setMicroseconds($microseconds)); + } catch (Throwable $e) { + echo get_class($e) . ' ' . $e->getMessage() . "\n"; + } + echo 'MyDateTimeImmutable::getMicroseconds(): ' . var_export($myDti->getMicroseconds(), true) . "\n"; +} +?> +--EXPECTF-- +DateTime::getMicroseconds(): 901234 +object(DateTime)#%d (3) { + ["date"]=> + string(26) "2023-04-05 06:07:08.901234" + ["timezone_type"]=> + int(1) + ["timezone"]=> + string(6) "+00:00" +} +DateTimeImmutable::getMicroseconds(): 901234 +object(DateTimeImmutable)#%d (3) { + ["date"]=> + string(26) "2023-04-05 06:07:08.901234" + ["timezone_type"]=> + int(1) + ["timezone"]=> + string(6) "+00:00" +} +MyDateTime::getMicroseconds(): 901234 +object(MyDateTime)#%d (3) { + ["date"]=> + string(26) "2023-04-05 06:07:08.901234" + ["timezone_type"]=> + int(1) + ["timezone"]=> + string(6) "+00:00" +} +MyDateTimeImmutable::getMicroseconds(): 901234 +object(MyDateTimeImmutable)#%d (3) { + ["date"]=> + string(26) "2023-04-05 06:07:08.901234" + ["timezone_type"]=> + int(1) + ["timezone"]=> + string(6) "+00:00" +} +################################## +DateTime::setMicroseconds(0):object(DateTime)#%d (3) { + ["date"]=> + string(26) "2023-04-05 06:07:08.000000" + ["timezone_type"]=> + int(1) + ["timezone"]=> + string(6) "+00:00" +} +DateTime::getMicroseconds(): 0 +DateTimeImmutable::setMicroseconds(0):object(DateTimeImmutable)#%d (3) { + ["date"]=> + string(26) "2023-04-05 06:07:08.000000" + ["timezone_type"]=> + int(1) + ["timezone"]=> + string(6) "+00:00" +} +DateTimeImmutable::getMicroseconds(): 901234 +MyDateTime::setMicroseconds(0):object(MyDateTime)#%d (3) { + ["date"]=> + string(26) "2023-04-05 06:07:08.000000" + ["timezone_type"]=> + int(1) + ["timezone"]=> + string(6) "+00:00" +} +MyDateTime::getMicroseconds(): 0 +MyDateTimeImmutable::setMicroseconds(0):object(MyDateTimeImmutable)#%d (3) { + ["date"]=> + string(26) "2023-04-05 06:07:08.000000" + ["timezone_type"]=> + int(1) + ["timezone"]=> + string(6) "+00:00" +} +MyDateTimeImmutable::getMicroseconds(): 901234 +################################## +DateTime::setMicroseconds(999999):object(DateTime)#%d (3) { + ["date"]=> + string(26) "2023-04-05 06:07:08.999999" + ["timezone_type"]=> + int(1) + ["timezone"]=> + string(6) "+00:00" +} +DateTime::getMicroseconds(): 999999 +DateTimeImmutable::setMicroseconds(999999):object(DateTimeImmutable)#%d (3) { + ["date"]=> + string(26) "2023-04-05 06:07:08.999999" + ["timezone_type"]=> + int(1) + ["timezone"]=> + string(6) "+00:00" +} +DateTimeImmutable::getMicroseconds(): 901234 +MyDateTime::setMicroseconds(999999):object(MyDateTime)#%d (3) { + ["date"]=> + string(26) "2023-04-05 06:07:08.999999" + ["timezone_type"]=> + int(1) + ["timezone"]=> + string(6) "+00:00" +} +MyDateTime::getMicroseconds(): 999999 +MyDateTimeImmutable::setMicroseconds(999999):object(MyDateTimeImmutable)#%d (3) { + ["date"]=> + string(26) "2023-04-05 06:07:08.999999" + ["timezone_type"]=> + int(1) + ["timezone"]=> + string(6) "+00:00" +} +MyDateTimeImmutable::getMicroseconds(): 901234 +################################## +DateTime::setMicroseconds(-1):DateRangeError Microseconds must be between 0 and 999999, -1 given +DateTime::getMicroseconds(): 999999 +DateTimeImmutable::setMicroseconds(-1):DateRangeError Microseconds must be between 0 and 999999, -1 given +DateTimeImmutable::getMicroseconds(): 901234 +MyDateTime::setMicroseconds(-1):DateRangeError Microseconds must be between 0 and 999999, -1 given +MyDateTime::getMicroseconds(): 999999 +MyDateTimeImmutable::setMicroseconds(-1):DateRangeError Microseconds must be between 0 and 999999, -1 given +MyDateTimeImmutable::getMicroseconds(): 901234 +################################## +DateTime::setMicroseconds(1000000):DateRangeError Microseconds must be between 0 and 999999, 1000000 given +DateTime::getMicroseconds(): 999999 +DateTimeImmutable::setMicroseconds(1000000):DateRangeError Microseconds must be between 0 and 999999, 1000000 given +DateTimeImmutable::getMicroseconds(): 901234 +MyDateTime::setMicroseconds(1000000):DateRangeError Microseconds must be between 0 and 999999, 1000000 given +MyDateTime::getMicroseconds(): 999999 +MyDateTimeImmutable::setMicroseconds(1000000):DateRangeError Microseconds must be between 0 and 999999, 1000000 given +MyDateTimeImmutable::getMicroseconds(): 901234