diff --git a/ext/hook.c b/ext/hook.c index 08f2d79..b1c4166 100644 --- a/ext/hook.c +++ b/ext/hook.c @@ -183,6 +183,7 @@ static inline void apply_interval(timelib_time **time, timelib_rel_time *interva zend_string *format, *_datetime; \ zval *_timezone_object; \ format_flags_t flags; \ + timelib_time *orig, *shifted; \ \ CALL_ORIGINAL_FUNCTION(name); \ if (!return_value || Z_TYPE_P(return_value) == IS_FALSE || !Z_PHPDATE_P(return_value)->time) { \ @@ -198,26 +199,37 @@ static inline void apply_interval(timelib_time **time, timelib_rel_time *interva \ parse_format(ZSTR_VAL(format), &flags); \ \ - timelib_time temp; \ - timelib_rel_time interval; \ - get_shift_interval(&interval); \ - memcpy(&temp, Z_PHPDATE_P(return_value)->time, sizeof(timelib_time)); \ + /* backup original method result */ \ + orig = timelib_time_clone(Z_PHPDATE_P(return_value)->time); \ + shifted = get_shifted_timelib_time(orig->tz_info); \ + \ + /* overwrite current shifted datetime */ \ + Z_PHPDATE_P(return_value)->time->y = shifted->y; \ + Z_PHPDATE_P(return_value)->time->m = shifted->m; \ + Z_PHPDATE_P(return_value)->time->d = shifted->d; \ + Z_PHPDATE_P(return_value)->time->h = shifted->h; \ + Z_PHPDATE_P(return_value)->time->i = shifted->i; \ + Z_PHPDATE_P(return_value)->time->s = shifted->s; \ + Z_PHPDATE_P(return_value)->time->us = shifted->us; \ \ - apply_interval(&Z_PHPDATE_P(return_value)->time, &interval); \ + /* restore original method result if required */ \ if (flags.h || flags.i || flags.s || flags.us) { \ Z_PHPDATE_P(return_value)->time->h = 0; \ Z_PHPDATE_P(return_value)->time->i = 0; \ Z_PHPDATE_P(return_value)->time->s = 0; \ Z_PHPDATE_P(return_value)->time->us = 0; \ } \ - if (flags.y) { Z_PHPDATE_P(return_value)->time->y = temp.y; } \ - if (flags.m) { Z_PHPDATE_P(return_value)->time->m = temp.m; } \ - if (flags.d) { Z_PHPDATE_P(return_value)->time->d = temp.d; } \ - if (flags.h) { Z_PHPDATE_P(return_value)->time->h = temp.h; } \ - if (flags.i) { Z_PHPDATE_P(return_value)->time->i = temp.i; } \ - if (flags.s) { Z_PHPDATE_P(return_value)->time->s = temp.s; } \ - if (flags.us) { Z_PHPDATE_P(return_value)->time->us = temp.us; } \ + if (flags.y) { Z_PHPDATE_P(return_value)->time->y = orig->y; } \ + if (flags.m) { Z_PHPDATE_P(return_value)->time->m = orig->m; } \ + if (flags.d) { Z_PHPDATE_P(return_value)->time->d = orig->d; } \ + if (flags.h) { Z_PHPDATE_P(return_value)->time->h = orig->h; } \ + if (flags.i) { Z_PHPDATE_P(return_value)->time->i = orig->i; } \ + if (flags.s) { Z_PHPDATE_P(return_value)->time->s = orig->s; } \ + if (flags.us) { Z_PHPDATE_P(return_value)->time->us = orig->us; } \ \ + /* release shifted time */ \ + timelib_time_dtor(orig); \ + timelib_time_dtor(shifted); \ timelib_update_ts(Z_PHPDATE_P(return_value)->time, NULL); \ } @@ -303,18 +315,23 @@ static inline bool is_fixed_time_str(zend_string *datetime, zval *timezone) return is_fixed_time_str; } -static inline timelib_time *get_current_timelib_time() +static inline timelib_time *get_current_timelib_time(timelib_tzinfo *tzi) { timelib_time *t = timelib_time_ctor(); - timelib_unixtime2gmt(t, php_time()); + if (tzi != NULL) { + timelib_set_timezone(t, tzi); + timelib_unixtime2local(t, (timelib_sll) php_time()); + } else { + timelib_unixtime2gmt(t, php_time()); + } return t; } -static inline timelib_time *get_shifted_timelib_time() +static inline timelib_time *get_shifted_timelib_time(timelib_tzinfo *tzi) { - timelib_time *t = get_current_timelib_time(); + timelib_time *t = get_current_timelib_time(tzi); timelib_rel_time interval; get_shift_interval(&interval); @@ -323,10 +340,10 @@ static inline timelib_time *get_shifted_timelib_time() return t; } -static inline time_t get_shifted_time() +static inline time_t get_shifted_time(timelib_tzinfo *tzi) { time_t timestamp; - timelib_time *t = get_shifted_timelib_time(); + timelib_time *t = get_shifted_timelib_time(tzi); timestamp = t->sse; @@ -344,7 +361,7 @@ static inline bool pdo_time_apply(pdo_dbh_t *dbh) return false; } - zend_sprintf(buf, "SET @@session.timestamp = %ld;", get_shifted_time()); + zend_sprintf(buf, "SET @@session.timestamp = %ld;", get_shifted_time(NULL)); sql = zend_string_init_fast(buf, strlen(buf)); COLOPL_TS_G(pdo_mysql_orig_methods)->doer(dbh, sql); zend_string_release(sql); @@ -469,7 +486,7 @@ static inline void date_common(INTERNAL_FUNCTION_PARAMETERS, int localtime) ZEND_PARSE_PARAMETERS_END(); if (ts_is_null) { - ts = get_shifted_time(); + ts = get_shifted_time(NULL); } RETVAL_STR(php_format_date(ZSTR_VAL(format), ZSTR_LEN(format), ts, localtime)); @@ -518,7 +535,7 @@ static void hook_time(INTERNAL_FUNCTION_PARAMETERS) CHECK_STATE(time); CALL_ORIGINAL_FUNCTION(time); - RETURN_LONG(get_shifted_time()); + RETURN_LONG(get_shifted_time(NULL)); } static void hook_mktime(INTERNAL_FUNCTION_PARAMETERS) @@ -592,7 +609,7 @@ static void hook_idate(INTERNAL_FUNCTION_PARAMETERS) ZEND_PARSE_PARAMETERS_END(); if (ts_is_null) { - ts = get_shifted_time(); + ts = get_shifted_time(NULL); } RETURN_LONG(php_idate(ZSTR_VAL(format)[0], ts, 0)); @@ -616,7 +633,7 @@ static void hook_getdate(INTERNAL_FUNCTION_PARAMETERS) /* Call original function with timestamp params. */ zval params[1]; - ZVAL_LONG(¶ms[0], get_shifted_time()); + ZVAL_LONG(¶ms[0], get_shifted_time(NULL)); CALL_ORIGINAL_FUNCTION_WITH_PARAMS(getdate, params, 1); } @@ -635,7 +652,7 @@ static void hook_localtime(INTERNAL_FUNCTION_PARAMETERS) /* Call original function with params. */ zval params[2]; - ZVAL_LONG(¶ms[0], get_shifted_time()); + ZVAL_LONG(¶ms[0], get_shifted_time(NULL)); ZVAL_BOOL(¶ms[1], associative); CALL_ORIGINAL_FUNCTION_WITH_PARAMS(localtime, params, 2); } @@ -658,7 +675,7 @@ static void hook_strtotime(INTERNAL_FUNCTION_PARAMETERS) times_lower = zend_string_tolower(times); if (strncmp(ZSTR_VAL(times_lower), "now", 3) == 0) { zend_string_release(times_lower); - RETURN_LONG((zend_long) get_shifted_time()); + RETURN_LONG((zend_long) get_shifted_time(NULL)); } zend_string_release(times_lower); @@ -671,7 +688,7 @@ static void hook_strtotime(INTERNAL_FUNCTION_PARAMETERS) zval *params = NULL; uint32_t param_count = 0; zend_parse_parameters(ZEND_NUM_ARGS(), "+", ¶ms, ¶m_count); - ZVAL_LONG(¶ms[1], get_shifted_time()); + ZVAL_LONG(¶ms[1], get_shifted_time(NULL)); CALL_ORIGINAL_FUNCTION_WITH_PARAMS(strtotime, params, param_count); /* Apply interval. */ diff --git a/ext/tests/gh7.phpt b/ext/tests/gh7.phpt index df60ae6..6f52858 100644 --- a/ext/tests/gh7.phpt +++ b/ext/tests/gh7.phpt @@ -8,15 +8,11 @@ colopl_timeshifter $first = date_create_from_format('Ymd', '19941026'); \Colopl\ColoplTimeShifter\register_hook(new DateInterval('PT1H')); $second = date_create_from_format('Ymd', '19941026'); -/* Sometimes delay */ -if ($first->diff($second)->format('%h%i%s') !== '100' && $first->diff($second)->format('%h%i%s') !== '05959') { - die('fail: ' . $first->diff($second)->format('%h%i%s')); -} echo $first->diff($second)->format('%y-%m-%d %h:%i:%s.%F'), \PHP_EOL; \Colopl\ColoplTimeShifter\unregister_hook(); $first = date_create_from_format('i', '30'); -\Colopl\ColoplTimeShifter\register_hook(new DateInterval('P1MT30S')); +\Colopl\ColoplTimeShifter\register_hook(new DateInterval('P1M')); $second = date_create_from_format('i', '30'); echo $first->diff($second)->format('%y-%m-%d %h:%i:%s.%F'), \PHP_EOL; \Colopl\ColoplTimeShifter\unregister_hook(); diff --git a/ext/tests/gh9.phpt b/ext/tests/gh9.phpt new file mode 100644 index 0000000..6fa399b --- /dev/null +++ b/ext/tests/gh9.phpt @@ -0,0 +1,35 @@ +--TEST-- +Check GitHub PR - #9 (wrong createFromFormat of start of month) +--EXTENSIONS-- +colopl_timeshifter +--SKIPIF-- +getmessage()}"); +} +if ($dt->format('d') !== '01') die('skip not start of month'); +?> +--FILE-- +format('Y-m-d H:i:s.u'), \PHP_EOL; +\Colopl\ColoplTimeShifter\register_hook($interval); +echo (new \DateTime())->format('Y-m-d H:i:s.u'), \PHP_EOL; +$second = date_create_from_format('d', '10'); +echo $second->format('Y-m-d H:i:s.u'), \PHP_EOL; + +?> +--EXPECTF-- +2024-09-01 %d:%d:%d.%d +2024-08-31 %d:%d:%d.%d +2024-08-10 00:00:%d.000000 diff --git a/ext/tests/variables/request_time_float.phpt b/ext/tests/variables/request_time_float.phpt index 3cc5c74..04e599c 100644 --- a/ext/tests/variables/request_time_float.phpt +++ b/ext/tests/variables/request_time_float.phpt @@ -20,10 +20,6 @@ if ($before == $after || $interval->y <= 0 || $interval->invert !== 0) { die('failed'); } -if ($before->format('u') !== $after->format('u')) { - die('failed'); -} - die('success'); ?>