]> granicus.if.org Git - php/commitdiff
fix for bug #10616 -> mktime() with negative date offsets not working on MacOSX
authorHartmut Holzgraefe <hholzgra@php.net>
Wed, 12 Jun 2002 15:35:27 +0000 (15:35 +0000)
committerHartmut Holzgraefe <hholzgra@php.net>
Wed, 12 Jun 2002 15:35:27 +0000 (15:35 +0000)
ext/standard/datetime.c
ext/standard/tests/time/003.phpt [new file with mode: 0644]

index d7fc392dcdfb11d459168beed5a70ef99b3654cd..4993d25d4674b8c54387852e019ffd8c8d91f6f6 100644 (file)
@@ -80,10 +80,10 @@ PHP_FUNCTION(time)
 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;
@@ -118,10 +118,10 @@ void php_mktime(INTERNAL_FUNCTION_PARAMETERS, int gm)
        ** 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
@@ -149,29 +149,64 @@ void php_mktime(INTERNAL_FUNCTION_PARAMETERS, int gm)
                        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
            /*
diff --git a/ext/standard/tests/time/003.phpt b/ext/standard/tests/time/003.phpt
new file mode 100644 (file)
index 0000000..0722b8b
--- /dev/null
@@ -0,0 +1,44 @@
+--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