void php_mktime(INTERNAL_FUNCTION_PARAMETERS, int gm)
{
pval **arguments[7];
- struct tm *ta, tmbuf;
- time_t t;
- int i, gmadjust, seconds, arg_count = ZEND_NUM_ARGS();
- int is_dst = -1;
+ struct tm *ta, tmbuf, *t1, *t2;
+ time_t t, seconds;
+ int i, gmadjust, arg_count = ZEND_NUM_ARGS();
+ int is_dst = -1, val, chgsecs = 0;
if (arg_count > 7 || zend_get_parameters_array_ex(arg_count, arguments) == FAILURE) {
WRONG_PARAM_COUNT;
** Now change date values with supplied parameters.
*/
switch(arg_count) {
- case 7:
+ case 7: /* daylight saving time flag */
ta->tm_isdst = is_dst = Z_LVAL_PP(arguments[6]);
/* fall-through */
- case 6:
+ 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
ta->tm_year = Z_LVAL_PP(arguments[5])
- ((Z_LVAL_PP(arguments[5]) > 1000) ? 1900 : 0);
/* fall-through */
- case 5:
- ta->tm_mday = Z_LVAL_PP(arguments[4]);
- /* fall-through */
- case 4:
- ta->tm_mon = Z_LVAL_PP(arguments[3]) - 1;
- /* fall-through */
- case 3:
- ta->tm_sec = Z_LVAL_PP(arguments[2]);
- /* fall-through */
- case 2:
- ta->tm_min = Z_LVAL_PP(arguments[1]);
- /* fall-through */
- case 1:
- ta->tm_hour = Z_LVAL_PP(arguments[0]);
- /* fall-through */
- case 0:
- break;
- }
+ case 5: /* day in month (1-baesd) */
+ 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;
+ if (val < 1) {
+ chgsecs += (1-val) * 60*60; val = 1;
+ }
+ ta->tm_hour = val;
+ /* fall-through */
+ case 0:
+ break;
+ }
+
+ t = mktime(ta);
+ seconds = t - chgsecs;
+
+
- seconds = mktime(ta);
- if (is_dst == -1)
- is_dst = ta->tm_isdst;
+ 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);
+ }
+
+ is_dst = ta->tm_isdst;
+ }
+
if (gm) {
#if HAVE_TM_GMTOFF
/*
--- /dev/null
+--TEST--
+Check for mktime with out-of-range parameters
+--SKIPIF--
+--POST--
+--GET--
+--FILE--
+<?php
+ # MacOS/X libc implementation doesn't treat out-of-range values
+ # the same way other unices do (Bug# 10686) so some extra code
+ # was added to datetime.c to take care of this
+ echo date("Y-m-d", mktime( 12, 0, 0, 3, 0, 2000)) ."\n";
+ echo date("Y-m-d", mktime( 12, 0, 0, 3, -1, 2000)) ."\n";
+ echo date("Y-m-d", mktime( 12, 0, 0, 2, 29, 2000)) ."\n";
+ echo date("Y-m-d", mktime( 12, 0, 0, 3, 0, 2001)) ."\n";
+ echo date("Y-m-d", mktime( 12, 0, 0, 2, 29, 2001)) ."\n";
+ echo date("Y-m-d", mktime( 12, 0, 0, 0, 0, 2000)) ."\n";
+
+ putenv("TZ=CET");
+ echo date("Y-m-d H:i:s", mktime(12,0,0,3,+90,2000,-1))."\n";
+ echo date("Y-m-d H:i:s", mktime(12,0,0,3,+90,2000,0))."\n";
+ echo date("Y-m-d H:i:s", mktime(12,0,0,3,+90,2000,1))."\n";
+ echo date("Y-m-d H:i:s", mktime(12,0,0,5,-90,2000,-1))."\n";
+ echo date("Y-m-d H:i:s", mktime(12,0,0,5,-90,2000,0))."\n";
+ echo date("Y-m-d H:i:s", mktime(12,0,0,5,-90,2000,1))."\n";
+ echo date("Y-m-d H:i:s", mktime(12,0,0,5,-1,2000,-1))."\n";
+ echo date("Y-m-d H:i:s", mktime(12,0,0,5,-1,2000,0))."\n";
+ echo date("Y-m-d H:i:s", mktime(12,0,0,5,-1,2000,1))."\n";
+?>
+--EXPECT--
+2000-02-29
+2000-02-28
+2000-02-29
+2001-02-28
+2001-03-01
+1999-11-30
+2000-05-29 12:00:00
+2000-05-29 13:00:00
+2000-05-29 12:00:00
+2000-01-31 12:00:00
+2000-01-31 12:00:00
+2000-01-31 11:00:00
+2000-04-29 12:00:00
+2000-04-29 13:00:00
+2000-04-29 12:00:00