mirror of
https://github.com/php/php-src.git
synced 2024-09-22 02:17:32 +00:00
- Fixed bug #30096 (gmmktime does not return the corrent time).
- Re-implemented mktime and gmmktime with new date time library. - Added testcase for bug #30096, updated test cases for E_STRICT warning of is_dst parameter usage for mktime/gmmktime.
This commit is contained in:
parent
f4b5a51952
commit
ed02f202f0
1
NEWS
1
NEWS
@ -19,6 +19,7 @@ PHP NEWS
|
||||
- Fixed bug #30828 (debug_backtrace() reports incorrect class in overridden
|
||||
methods). (Dmitry)
|
||||
- Fixed bug #30519 (Interface not existing says Class not found). (Dmitry)
|
||||
- Fixed bug #30096 (gmmktime does not return the corrent time). (Derick)
|
||||
- Fixed bug #30052 (Crash on shutdown after odbc_pconnect()). (Edin)
|
||||
- Fixed bug #28377 (debug_backtrace is intermittently passing args). (Dmitry)
|
||||
- Fixed bug #27268 (Bad references accentuated by clone). (Dmitry)
|
||||
|
@ -31,6 +31,8 @@
|
||||
function_entry date_functions[] = {
|
||||
PHP_FE(date, NULL)
|
||||
PHP_FE(gmdate, NULL)
|
||||
PHP_FE(mktime, NULL)
|
||||
PHP_FE(gmmktime, NULL)
|
||||
PHP_FE(strtotime, NULL)
|
||||
PHP_FE(date_timezone_set, NULL)
|
||||
PHP_FE(date_timezone_get, NULL)
|
||||
@ -400,6 +402,105 @@ PHP_FUNCTION(strtotime)
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
PHPAPI static void php_mktime(INTERNAL_FUNCTION_PARAMETERS, int gmt)
|
||||
{
|
||||
long hou, min, sec, mon, day, yea, dst = -1;;
|
||||
timelib_time *now;
|
||||
timelib_tzinfo *tzi;
|
||||
long ts, adjust_seconds = 0;
|
||||
int error;
|
||||
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lllllll", &hou, &min, &sec, &mon, &day, &yea, &dst) == FAILURE) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
/* Initialize structure with current time */
|
||||
now = timelib_time_ctor();
|
||||
if (gmt) {
|
||||
timelib_unixtime2gmt(now, (timelib_sll) time(NULL));
|
||||
} else {
|
||||
tzi = get_timezone_info(TSRMLS_C);
|
||||
timelib_unixtime2local(now, (timelib_sll) time(NULL), tzi);
|
||||
}
|
||||
/* Fill in the new data */
|
||||
switch (ZEND_NUM_ARGS()) {
|
||||
case 7:
|
||||
/* break intentionally missing */
|
||||
case 6:
|
||||
now->y = yea;
|
||||
/* break intentionally missing again */
|
||||
case 5:
|
||||
now->d = day;
|
||||
/* break missing intentionally here too */
|
||||
case 4:
|
||||
now->m = mon;
|
||||
/* and here */
|
||||
case 3:
|
||||
now->s = sec;
|
||||
/* yup, this break isn't here on purpose too */
|
||||
case 2:
|
||||
now->i = min;
|
||||
/* last intentionally missing break */
|
||||
case 1:
|
||||
now->h = hou;
|
||||
break;
|
||||
default:
|
||||
php_error_docref(NULL TSRMLS_CC, E_STRICT, "You should be using the time() function instead.");
|
||||
}
|
||||
/* Update the timestamp */
|
||||
if (gmt) {
|
||||
timelib_update_ts(now, NULL);
|
||||
} else {
|
||||
timelib_update_ts(now, tzi);
|
||||
}
|
||||
/* Support for the deprecated is_dst parameter */
|
||||
if (dst != -1) {
|
||||
php_error_docref(NULL TSRMLS_CC, E_STRICT, "The is_dst parameter is deprecated.");
|
||||
if (gmt) {
|
||||
/* GMT never uses DST */
|
||||
if (dst == 1) {
|
||||
adjust_seconds = -3600;
|
||||
}
|
||||
} else {
|
||||
/* Figure out is_dst for current TS */
|
||||
timelib_time_offset *tmp_offset;
|
||||
tmp_offset = timelib_get_time_zone_info(now->sse, tzi);
|
||||
if (dst == 1 && tmp_offset->is_dst == 0) {
|
||||
adjust_seconds = -3600;
|
||||
}
|
||||
if (dst == 0 && tmp_offset->is_dst == 1) {
|
||||
adjust_seconds = +3600;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Clean up and return */
|
||||
ts = timelib_date_to_int(now, &error);
|
||||
ts += adjust_seconds;
|
||||
|
||||
timelib_time_dtor(now);
|
||||
|
||||
if (error) {
|
||||
RETURN_FALSE;
|
||||
} else {
|
||||
RETURN_LONG(ts);
|
||||
}
|
||||
}
|
||||
|
||||
/* {{{ proto int mktime(int hour, int min, int sec, int mon, int day, int year)
|
||||
Get UNIX timestamp for a date */
|
||||
PHP_FUNCTION(mktime)
|
||||
{
|
||||
php_mktime(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto int gmmktime(int hour, int min, int sec, int mon, int day, int year)
|
||||
Get UNIX timestamp for a GMT date */
|
||||
PHP_FUNCTION(gmmktime)
|
||||
{
|
||||
php_mktime(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
PHP_FUNCTION(date_timezone_set)
|
||||
{
|
||||
char *zone;
|
||||
|
@ -27,6 +27,10 @@ extern zend_module_entry date_module_entry;
|
||||
PHP_FUNCTION(date);
|
||||
PHP_FUNCTION(gmdate);
|
||||
PHP_FUNCTION(strtotime);
|
||||
|
||||
PHP_FUNCTION(mktime);
|
||||
PHP_FUNCTION(gmmktime);
|
||||
|
||||
PHP_FUNCTION(date_timezone_set);
|
||||
PHP_FUNCTION(date_timezone_get);
|
||||
|
||||
@ -49,5 +53,6 @@ ZEND_END_MODULE_GLOBALS(date)
|
||||
|
||||
/* Backwards compability wrapper */
|
||||
signed long php_parse_date(char *string, signed long *now);
|
||||
PHPAPI static void php_mktime(INTERNAL_FUNCTION_PARAMETERS, int gmt);
|
||||
|
||||
#endif /* PHP_DATE_H */
|
||||
|
48
ext/date/tests/bug30096.phpt
Normal file
48
ext/date/tests/bug30096.phpt
Normal file
@ -0,0 +1,48 @@
|
||||
--TEST--
|
||||
Bug #30096 (gmmktime does not return the corrent time)
|
||||
--INI--
|
||||
error_reporting=2047
|
||||
--FILE--
|
||||
<?php
|
||||
echo "no dst --> dst\n";
|
||||
$ts = -1;
|
||||
gm_date_check(01,00,00,03,27,2005);
|
||||
gm_date_check(02,00,00,03,27,2005);
|
||||
gm_date_check(03,00,00,03,27,2005);
|
||||
gm_date_check(04,00,00,03,27,2005);
|
||||
|
||||
echo "\ndst --> no dst\n";
|
||||
$ts = -1;
|
||||
gm_date_check(01,00,00,10,30,2005);
|
||||
gm_date_check(02,00,00,10,30,2005);
|
||||
gm_date_check(03,00,00,10,30,2005);
|
||||
gm_date_check(04,00,00,10,30,2005);
|
||||
|
||||
function gm_date_check($hour, $minute, $second, $month, $day, $year) {
|
||||
global $ts, $tsold;
|
||||
|
||||
echo "gmmktime($hour,$minute,$second,$month,$day,$year): ";
|
||||
|
||||
$tsold = $ts;
|
||||
$ts = gmmktime($hour, $minute, $second, $month, $day, $year);
|
||||
|
||||
echo $ts, " | gmdate('r', $ts):", gmdate('r', $ts);
|
||||
if ($tsold > 0) {
|
||||
echo " | Diff: " . ($ts - $tsold);
|
||||
}
|
||||
echo "\n";
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
no dst --> dst
|
||||
gmmktime(1,0,0,3,27,2005): 1111885200 | gmdate('r', 1111885200):Sun, 27 Mar 2005 01:00:00 +0000
|
||||
gmmktime(2,0,0,3,27,2005): 1111888800 | gmdate('r', 1111888800):Sun, 27 Mar 2005 02:00:00 +0000 | Diff: 3600
|
||||
gmmktime(3,0,0,3,27,2005): 1111892400 | gmdate('r', 1111892400):Sun, 27 Mar 2005 03:00:00 +0000 | Diff: 3600
|
||||
gmmktime(4,0,0,3,27,2005): 1111896000 | gmdate('r', 1111896000):Sun, 27 Mar 2005 04:00:00 +0000 | Diff: 3600
|
||||
|
||||
dst --> no dst
|
||||
gmmktime(1,0,0,10,30,2005): 1130634000 | gmdate('r', 1130634000):Sun, 30 Oct 2005 01:00:00 +0000
|
||||
gmmktime(2,0,0,10,30,2005): 1130637600 | gmdate('r', 1130637600):Sun, 30 Oct 2005 02:00:00 +0000 | Diff: 3600
|
||||
gmmktime(3,0,0,10,30,2005): 1130641200 | gmdate('r', 1130641200):Sun, 30 Oct 2005 03:00:00 +0000 | Diff: 3600
|
||||
gmmktime(4,0,0,10,30,2005): 1130644800 | gmdate('r', 1130644800):Sun, 30 Oct 2005 04:00:00 +0000 | Diff: 3600
|
@ -169,8 +169,6 @@ function_entry basic_functions[] = {
|
||||
PHP_FE(time_sleep_until, NULL)
|
||||
#endif
|
||||
PHP_FE(time, NULL)
|
||||
PHP_FE(mktime, NULL)
|
||||
PHP_FE(gmmktime, NULL)
|
||||
#if HAVE_STRPTIME
|
||||
PHP_FE(strptime, NULL)
|
||||
#endif
|
||||
|
@ -77,210 +77,6 @@ PHP_FUNCTION(time)
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ php_mktime
|
||||
*/
|
||||
PHPAPI void php_mktime(INTERNAL_FUNCTION_PARAMETERS, int gm)
|
||||
{
|
||||
pval **arguments[7];
|
||||
struct tm *ta, tmbuf;
|
||||
time_t t, seconds;
|
||||
int i, gmadjust, arg_count = ZEND_NUM_ARGS();
|
||||
int is_dst = -1, chgsecs = 0;
|
||||
long val;
|
||||
|
||||
if (arg_count > 7 || zend_get_parameters_array_ex(arg_count, arguments) == FAILURE) {
|
||||
WRONG_PARAM_COUNT;
|
||||
}
|
||||
/* convert supplied arguments to longs */
|
||||
for (i = 0; i < arg_count; i++) {
|
||||
convert_to_long_ex(arguments[i]);
|
||||
}
|
||||
t = time(NULL);
|
||||
#ifdef HAVE_TZSET
|
||||
tzset();
|
||||
#endif
|
||||
/*
|
||||
** Set default time parameters with local time values,
|
||||
** EVEN when some GMT time parameters are specified!
|
||||
** This may give strange result, with PHP gmmktime(0, 0, 0),
|
||||
** which is assumed to return GMT midnight time
|
||||
** for today (in localtime), so that the result time may be
|
||||
** AFTER or BEFORE the current time.
|
||||
** May be we should initialize tn using gmtime(), so that
|
||||
** default parameters for PHP gmmktime would be the current
|
||||
** GMT time values...
|
||||
*/
|
||||
ta = php_localtime_r(&t, &tmbuf);
|
||||
|
||||
/* Let DST be unknown. mktime() should compute the right value
|
||||
** and behave correctly. Unless the user overrides this.
|
||||
*/
|
||||
ta->tm_isdst = -1;
|
||||
|
||||
/*
|
||||
** Now change date values with supplied parameters.
|
||||
*/
|
||||
switch(arg_count) {
|
||||
case 7: /* daylight saving time flag */
|
||||
#ifdef PHP_WIN32
|
||||
if (daylight > 0) {
|
||||
ta->tm_isdst = is_dst = Z_LVAL_PP(arguments[6]);
|
||||
} else {
|
||||
ta->tm_isdst = is_dst = 0;
|
||||
}
|
||||
#else
|
||||
ta->tm_isdst = is_dst = Z_LVAL_PP(arguments[6]);
|
||||
#endif
|
||||
/* fall-through */
|
||||
case 6: /* year */
|
||||
/* special case:
|
||||
a zero in year, month and day is considered illegal
|
||||
as it would be interpreted as 30.11.1999 otherwise
|
||||
*/
|
||||
if ( ( Z_LVAL_PP(arguments[5])==0)
|
||||
&&(Z_LVAL_PP(arguments[4])==0)
|
||||
&&(Z_LVAL_PP(arguments[3])==0)
|
||||
) {
|
||||
RETURN_LONG(-1);
|
||||
}
|
||||
|
||||
/*
|
||||
** Accept parameter in range 0..1000 interpreted as 1900..2900
|
||||
** (if 100 is given, it means year 2000)
|
||||
** or in range 1001..9999 interpreted as is (this will store
|
||||
** negative tm_year for years in range 1001..1899)
|
||||
** This function is then Y2K ready, and accepts a wide range of
|
||||
** dates including the whole gregorian calendar.
|
||||
** But it cannot represent ancestral dates prior to year 1001.
|
||||
** Additionally, input parameters of 0..70 are mapped to 100..170
|
||||
*/
|
||||
if (Z_LVAL_PP(arguments[5]) < 70)
|
||||
ta->tm_year = Z_LVAL_PP(arguments[5]) + 100;
|
||||
else
|
||||
ta->tm_year = Z_LVAL_PP(arguments[5])
|
||||
- ((Z_LVAL_PP(arguments[5]) > 1000) ? 1900 : 0);
|
||||
/* fall-through */
|
||||
case 5: /* day in month (1-based) */
|
||||
val = (*arguments[4])->value.lval;
|
||||
if (val < 1) {
|
||||
chgsecs += (1-val) * 60*60*24;
|
||||
val = 1;
|
||||
}
|
||||
ta->tm_mday = val;
|
||||
/* fall-through */
|
||||
case 4: /* month (zero-based) */
|
||||
val = (*arguments[3])->value.lval - 1;
|
||||
while (val < 0) {
|
||||
val += 12; ta->tm_year--;
|
||||
}
|
||||
ta->tm_mon = val;
|
||||
/* fall-through */
|
||||
case 3: /* second */
|
||||
val = (*arguments[2])->value.lval;
|
||||
if (val < 1) {
|
||||
chgsecs += (1-val); val = 1;
|
||||
}
|
||||
ta->tm_sec = val;
|
||||
/* fall-through */
|
||||
case 2: /* minute */
|
||||
val = (*arguments[1])->value.lval;
|
||||
if (val < 1) {
|
||||
chgsecs += (1-val) * 60; val = 1;
|
||||
}
|
||||
ta->tm_min = val;
|
||||
/* fall-through */
|
||||
case 1: /* hour */
|
||||
val = (*arguments[0])->value.lval;
|
||||
/*
|
||||
We avoid midnight and a couple of hours after midnight here to work around
|
||||
various OS-level bugs in mktime and specifically daylight savings time issues
|
||||
in many mktime implementation.
|
||||
See bugs #27533 and #27719 for more info.
|
||||
*/
|
||||
if (val < 4) {
|
||||
chgsecs += (4-val) * 60*60; val = 4;
|
||||
}
|
||||
ta->tm_hour = val;
|
||||
/* fall-through */
|
||||
case 0:
|
||||
break;
|
||||
}
|
||||
|
||||
t = mktime(ta);
|
||||
|
||||
#ifdef PHP_WIN32
|
||||
if (t - chgsecs < 0) {
|
||||
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Windows does not support negative values for this function");
|
||||
RETURN_LONG(-1);
|
||||
}
|
||||
#endif
|
||||
|
||||
seconds = t - chgsecs;
|
||||
|
||||
/*
|
||||
Here we check to see if the chgsecs fuzz factor we applied caused us to
|
||||
move from dst to non-dst or vice-versa. If so we adjust accordingly to
|
||||
avoid being off by an hour on the dst changeover date.
|
||||
*/
|
||||
if (is_dst == -1) {
|
||||
struct tm t1, t2;
|
||||
t1 = *localtime(&t);
|
||||
t2 = *localtime(&seconds);
|
||||
|
||||
if (t1.tm_isdst != t2.tm_isdst) {
|
||||
seconds += (t1.tm_isdst == 1) ? 3600 : -3600;
|
||||
ta = localtime(&seconds);
|
||||
}
|
||||
|
||||
/*
|
||||
If the user didn't specify whether the timestamp passed in was dst or not
|
||||
then we fill it in based on the dst setting at the evaluated timestamp
|
||||
at the current TZ
|
||||
*/
|
||||
is_dst = ta->tm_isdst;
|
||||
}
|
||||
|
||||
if (gm) {
|
||||
#if HAVE_TM_GMTOFF
|
||||
/*
|
||||
** mktime(ta) very nicely just filled ta->tm_gmtoff with
|
||||
** the exactly right value for adjustment if we want GMT.
|
||||
*/
|
||||
gmadjust = ta->tm_gmtoff;
|
||||
#else
|
||||
/*
|
||||
** If correcting for daylight savings time, we set the adjustment to
|
||||
** the value of timezone - 3600 seconds.
|
||||
*/
|
||||
#ifdef __CYGWIN__
|
||||
gmadjust = -(is_dst ? _timezone - 3600 : _timezone);
|
||||
#else
|
||||
gmadjust = -(is_dst ? timezone - 3600 : timezone);
|
||||
#endif
|
||||
#endif
|
||||
seconds += gmadjust;
|
||||
}
|
||||
|
||||
RETURN_LONG(seconds);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto int mktime(int hour, int min, int sec, int mon, int day, int year)
|
||||
Get UNIX timestamp for a date */
|
||||
PHP_FUNCTION(mktime)
|
||||
{
|
||||
php_mktime(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto int gmmktime(int hour, int min, int sec, int mon, int day, int year)
|
||||
Get UNIX timestamp for a GMT date */
|
||||
PHP_FUNCTION(gmmktime)
|
||||
{
|
||||
php_mktime(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ php_idate
|
||||
*/
|
||||
PHPAPI int php_idate(char format, int timestamp, int gm)
|
||||
|
@ -23,8 +23,6 @@
|
||||
#define DATETIME_H
|
||||
|
||||
PHP_FUNCTION(time);
|
||||
PHP_FUNCTION(mktime);
|
||||
PHP_FUNCTION(gmmktime);
|
||||
PHP_FUNCTION(idate);
|
||||
PHP_FUNCTION(localtime);
|
||||
PHP_FUNCTION(getdate);
|
||||
@ -39,7 +37,6 @@ PHP_FUNCTION(gmstrftime);
|
||||
|
||||
PHPAPI int php_idate(char format, int timestamp, int gm);
|
||||
PHPAPI char *php_std_date(time_t t TSRMLS_DC);
|
||||
PHPAPI void php_mktime(INTERNAL_FUNCTION_PARAMETERS, int gm);
|
||||
#if HAVE_STRFTIME
|
||||
PHPAPI void _php_strftime(INTERNAL_FUNCTION_PARAMETERS, int gm);
|
||||
#endif
|
||||
|
@ -1,5 +1,7 @@
|
||||
--TEST--
|
||||
Check for mktime with out-of-range parameters
|
||||
--INI--
|
||||
error_reporting=2047
|
||||
--FILE--
|
||||
<?php
|
||||
# MacOS/X libc implementation doesn't treat out-of-range values
|
||||
|
@ -1,5 +1,7 @@
|
||||
--TEST--
|
||||
Bug #27719: mktime returns incorrect timestamp for dst days
|
||||
--INI--
|
||||
error_reporting=2047
|
||||
--FILE--
|
||||
<?php /* $Id$ */
|
||||
putenv("TZ=EST"); // No DST
|
||||
|
@ -1,5 +1,7 @@
|
||||
--TEST--
|
||||
mktime()
|
||||
--INI--
|
||||
error_reporting=2047
|
||||
--FILE--
|
||||
<?php /* $Id$ */
|
||||
$timezones = array(
|
||||
|
Loading…
Reference in New Issue
Block a user