Skip to content

Commit

Permalink
Fixed GH-11368: Date modify returns invalid datetime
Browse files Browse the repository at this point in the history
  • Loading branch information
derickr committed Jun 22, 2023
1 parent f160eff commit 0747616
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 14 deletions.
3 changes: 3 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ PHP NEWS
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
?? ??? ????, PHP 8.1.22

- Date:
. Fixed bug GH-11368 (Date modify returns invalid datetime). (Derick)

- PCRE:
. Mangle PCRE regex cache key with JIT option. (mvorisek)

Expand Down
2 changes: 1 addition & 1 deletion ext/date/lib/timelib.h
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,7 @@ typedef struct _timelib_tzdb {
#define TIMELIB_OVERRIDE_TIME 0x01
#define TIMELIB_NO_CLONE 0x02

#define TIMELIB_UNSET -99999
#define TIMELIB_UNSET -9999999

/* An entry for each of these error codes is also in the
* timelib_error_messages array in timelib.c.
Expand Down
26 changes: 13 additions & 13 deletions ext/date/php_date.c
Original file line number Diff line number Diff line change
Expand Up @@ -2100,7 +2100,7 @@ static HashTable *date_object_get_properties_interval(zend_object *object) /* {{
PHP_DATE_INTERVAL_ADD_PROPERTY("weekday_behavior", weekday_behavior);
PHP_DATE_INTERVAL_ADD_PROPERTY("first_last_day_of", first_last_day_of);
PHP_DATE_INTERVAL_ADD_PROPERTY("invert", invert);
if (intervalobj->diff->days != -99999) {
if (intervalobj->diff->days != TIMELIB_UNSET) {
PHP_DATE_INTERVAL_ADD_PROPERTY("days", days);
} else {
ZVAL_FALSE(&zv);
Expand Down Expand Up @@ -2733,7 +2733,7 @@ void php_date_do_return_parsed_time(INTERNAL_FUNCTION_PARAMETERS, timelib_time *

array_init(return_value);
#define PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(name, elem) \
if (parsed_time->elem == -99999) { \
if (parsed_time->elem == TIMELIB_UNSET) { \
add_assoc_bool(return_value, #name, 0); \
} else { \
add_assoc_long(return_value, #name, parsed_time->elem); \
Expand All @@ -2745,7 +2745,7 @@ void php_date_do_return_parsed_time(INTERNAL_FUNCTION_PARAMETERS, timelib_time *
PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(minute, i);
PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(second, s);

if (parsed_time->us == -99999) {
if (parsed_time->us == TIMELIB_UNSET) {
add_assoc_bool(return_value, "fraction", 0);
} else {
add_assoc_double(return_value, "fraction", (double)parsed_time->us / 1000000.0);
Expand Down Expand Up @@ -2880,21 +2880,21 @@ static int php_date_modify(zval *object, char *modify, size_t modify_len) /* {{{
dateobj->time->have_relative = tmp_time->have_relative;
dateobj->time->sse_uptodate = 0;

if (tmp_time->y != -99999) {
if (tmp_time->y != TIMELIB_UNSET) {
dateobj->time->y = tmp_time->y;
}
if (tmp_time->m != -99999) {
if (tmp_time->m != TIMELIB_UNSET) {
dateobj->time->m = tmp_time->m;
}
if (tmp_time->d != -99999) {
if (tmp_time->d != TIMELIB_UNSET) {
dateobj->time->d = tmp_time->d;
}

if (tmp_time->h != -99999) {
if (tmp_time->h != TIMELIB_UNSET) {
dateobj->time->h = tmp_time->h;
if (tmp_time->i != -99999) {
if (tmp_time->i != TIMELIB_UNSET) {
dateobj->time->i = tmp_time->i;
if (tmp_time->s != -99999) {
if (tmp_time->s != TIMELIB_UNSET) {
dateobj->time->s = tmp_time->s;
} else {
dateobj->time->s = 0;
Expand All @@ -2905,7 +2905,7 @@ static int php_date_modify(zval *object, char *modify, size_t modify_len) /* {{{
}
}

if (tmp_time->us != -99999) {
if (tmp_time->us != TIMELIB_UNSET) {
dateobj->time->us = tmp_time->us;
}

Expand Down Expand Up @@ -3914,7 +3914,7 @@ static zval *date_interval_read_property(zend_object *object, zend_string *name,

if (fvalue != -1) {
ZVAL_DOUBLE(retval, fvalue);
} else if (value != -99999) {
} else if (value != TIMELIB_UNSET) {
ZVAL_LONG(retval, value);
} else {
ZVAL_FALSE(retval);
Expand Down Expand Up @@ -4039,7 +4039,7 @@ static int php_date_interval_initialize_from_hash(zval **return_value, php_inter
do { \
zval *z_arg = zend_hash_str_find(myht, "days", sizeof("days") - 1); \
if (z_arg && Z_TYPE_P(z_arg) == IS_FALSE) { \
(*intobj)->diff->member = -99999; \
(*intobj)->diff->member = TIMELIB_UNSET; \
} else if (z_arg && Z_TYPE_P(z_arg) <= IS_STRING) { \
zend_string *str = zval_get_string(z_arg); \
DATE_A64I((*intobj)->diff->member, ZSTR_VAL(str)); \
Expand Down Expand Up @@ -4199,7 +4199,7 @@ static zend_string *date_interval_format(char *format, size_t format_len, timeli
case 'f': length = slprintf(buffer, sizeof(buffer), ZEND_LONG_FMT, (zend_long) t->us); break;

case 'a': {
if ((int) t->days != -99999) {
if ((int) t->days != TIMELIB_UNSET) {
length = slprintf(buffer, sizeof(buffer), "%d", (int) t->days);
} else {
length = slprintf(buffer, sizeof(buffer), "(unknown)");
Expand Down
33 changes: 33 additions & 0 deletions ext/date/tests/bug-gh11368.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
--TEST--
Bug GH-11368: Date modify returns invalid datetime
--INI--
date.timezone=UTC
--FILE--
<?php

$datetime = date_create('2023-06-04');

$datetime->setTime(1,1,1,1 /* If set to any other number, it works fine */);
var_dump($datetime);

$datetime->modify('-100 ms');
var_dump($datetime);

?>
--EXPECTF--
object(DateTime)#1 (3) {
["date"]=>
string(26) "2023-06-04 01:01:01.000001"
["timezone_type"]=>
int(3)
["timezone"]=>
string(3) "UTC"
}
object(DateTime)#1 (3) {
["date"]=>
string(26) "2023-06-04 01:01:00.900001"
["timezone_type"]=>
int(3)
["timezone"]=>
string(3) "UTC"
}

0 comments on commit 0747616

Please sign in to comment.