Skip to content

Commit

Permalink
Fix start of month in date_create_form_format() (#9)
Browse files Browse the repository at this point in the history
Closes: #4
  • Loading branch information
zeriyoshi authored Sep 12, 2024
1 parent d3721af commit e39d9c8
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 35 deletions.
69 changes: 43 additions & 26 deletions ext/hook.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) { \
Expand All @@ -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); \
}

Expand Down Expand Up @@ -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);
Expand All @@ -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;

Expand All @@ -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);
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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));
Expand All @@ -616,7 +633,7 @@ static void hook_getdate(INTERNAL_FUNCTION_PARAMETERS)

/* Call original function with timestamp params. */
zval params[1];
ZVAL_LONG(&params[0], get_shifted_time());
ZVAL_LONG(&params[0], get_shifted_time(NULL));
CALL_ORIGINAL_FUNCTION_WITH_PARAMS(getdate, params, 1);
}

Expand All @@ -635,7 +652,7 @@ static void hook_localtime(INTERNAL_FUNCTION_PARAMETERS)

/* Call original function with params. */
zval params[2];
ZVAL_LONG(&params[0], get_shifted_time());
ZVAL_LONG(&params[0], get_shifted_time(NULL));
ZVAL_BOOL(&params[1], associative);
CALL_ORIGINAL_FUNCTION_WITH_PARAMS(localtime, params, 2);
}
Expand All @@ -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);

Expand All @@ -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(), "+", &params, &param_count);
ZVAL_LONG(&params[1], get_shifted_time());
ZVAL_LONG(&params[1], get_shifted_time(NULL));
CALL_ORIGINAL_FUNCTION_WITH_PARAMS(strtotime, params, param_count);

/* Apply interval. */
Expand Down
6 changes: 1 addition & 5 deletions ext/tests/gh7.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
35 changes: 35 additions & 0 deletions ext/tests/gh9.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
--TEST--
Check GitHub PR - #9 (wrong createFromFormat of start of month)
--EXTENSIONS--
colopl_timeshifter
--SKIPIF--
<?php
if (posix_getuid() !== 0) die('skip require root');
if (! is_string(($result = shell_exec('date -s "2024-09-01"')))) die ('skip cannot set current date');
try {
$dt = new \DateTimeImmutable($result);
if (!($dt instanceof \DateTimeImmutable)) {
throw new Exception("construction failed: {$result}");
}
} catch (\Exception $e) {
die("skip {$e->getmessage()}");
}
if ($dt->format('d') !== '01') die('skip not start of month');
?>
--FILE--
<?php

$interval = new DateInterval('P1D');

$first = new \DateTime();
echo $first->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
4 changes: 0 additions & 4 deletions ext/tests/variables/request_time_float.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -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');

?>
Expand Down

0 comments on commit e39d9c8

Please sign in to comment.