| 
        php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login | 
  [2001-01-21 08:06 UTC] dieter at fiebelkorn dot net
 On PHP documantation:
mktime(hour,min,sec, year,0,mon) refers the last day of 
month 'mon-1'. On MacOS X this failed, there it refers 
the first day of month 'mon' and mktime(hour,min,sec, 
year,-1,mon) refers the last day of month 'mon-1'.
See the test:
[aragorn:~/Downloads] dieter% cat A.c
#include <stdio.h>
#include <time.h>
main()
{
        struct tm mytm;
        int i;
        mytm.tm_sec = 0; mytm.tm_min = 0;
        mytm.tm_hour = 0; mytm.tm_year = 101;
        mytm.tm_wday = 0; mytm.tm_yday = 0;
        mytm.tm_isdst = 0; mytm.tm_gmtoff = 0;
        mytm.tm_zone = 0;
        for (i = 2; i >= -2; i--)
        {
                mytm.tm_mday = i;
                mytm.tm_mon = 2;
                printf ("%02d.%02d ",
                           mytm.tm_mday, mytm.tm_mon+1);
                printf (" --> %ld", mktime(&mytm));
                printf (" --> %02d.%02d\n",
                           mytm.tm_mday, mytm.tm_mon+1);
        }
}
[aragorn:~/Downloads] dieter% cc -o A A.c
[aragorn:~/Downloads] dieter% ./A
02.03  --> 983487600 --> 02.03
01.03  --> 983401200 --> 01.03
00.03  --> 983401200 --> 01.03
-1.03  --> 983314800 --> 28.02
-2.03  --> 983228400 --> 27.02
[aragorn:~/Downloads] dieter% 
PatchesPull RequestsHistoryAllCommentsChangesGit/SVN commits             
             | 
    |||||||||||||||||||||||||||
            
                 
                Copyright © 2001-2025 The PHP GroupAll rights reserved.  | 
        Last updated: Tue Nov 04 13:00:02 2025 UTC | 
I have send a bug report to darwin-developers and apple, too, but i have check some UNIX-systems and i haven't found any man-page, where is describe what should be happend on "tm_mday" <= 0. IMHO this is a undocumented feature, which is used by PHP. man mktime (Linux 2.2.13) ------------------------------------ tm_mday The day of the month, in the range 1 to 31. Sun Release 4.1 ---------------------- int tm_mday; /* day of month (1 - 31) */ SunOS 5.5 --------------- int tm_mday; /* day of the month - [1, 31] */ HP-UX Release 10.20 ------------------------------ int tm_mday; /* day of month - [1,31] */ HP-UX Release 11.00 ------------------------------- int tm_mday; /* day of month - [1,31] */ AIX 4.3.2 ------------ int tm_mday; /* Day of month (1 - 31) */ Darwin 1.0.2 ----------------- int tm_mday; /* day of month (1 - 31) */ I think i should by much better to check mktime() on configure and set a #define for compilation. Only on "datetime.c" must be made a patch to support MacOS X's / Darwin's mktime()-systemcall, i think!This actually is part of the Ansi C standard. Solaris 8 manpage ----------------------- The original values of the components may be either greater than or less than the specified range. For example, a tm_hour of -1 means 1 hour before midnight, tm_mday of 0 means the day preceding the current month, and tm_mon of -2 means 2 months before January of tm_year --------------------------------------- Alg from c standard ---------------------------------------- #define QUOT(a,b) ((a)>0 ? (a)/(b) : -(((b)-(a)-1)/(b))) #define REM(a,b) ((a)-(b)*QUOT(a,b)) SS = tm_hour*3600 + tm_min*60 + tm_sec + (tm_leapsecs == _NO_LEAP_SECONDS ? X1 : tm_leapsecs) - (tm_zone == _LOCALTIME ? X2 : tm_zone) * 60; // X1 is the appropriate number of leap seconds, determined by // the implementation, or 0 if it cannot be determined. // X2 is the appropriate offset from local time to UTC, // determined by the implementation, or // (tm_isdst >= 0 ? tm_isdst : 0) // if the offset cannot be determined M = REM(tm_mon, 12); Y = tm_year + 1900 + QUOT(tm_mon, 12); Z = Y - (M < 2 ? 1 : 0); D = Y*365 + (Z/400)*97 + (Z%400)/4 + M[(int []){0,31,59,90,120,151,181,212,243,273, 304,335}] + tm_mday + QUOT(SS, 86400); S = REM(SS, 86400); ------------------------------------------------------ Mac OS X is not following this standard -JasonFIRST patch to make php_mktime() more compatible [i think it is not complete for the whole PHP4-project]. It includes a time correction for values less then 1 on "mday", "hour", "min", "sec". NOT on "mon"!! *** ext/standard/datetime.c.orig Fri Dec 8 12:38:02 2000 --- ext/standard/datetime.c Sun Apr 15 16:42:37 2001 *************** *** 81,87 **** struct tm *ta, tmbuf; time_t t; int i, gmadjust, seconds, arg_count = ZEND_NUM_ARGS(); ! int is_dst = -1; if (arg_count > 7 || zend_get_parameters_array_ex(arg_count,arguments) == FAILURE) { WRONG_PARAM_COUNT; --- 81,87 ---- struct tm *ta, tmbuf; time_t t; int i, gmadjust, seconds, 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; *************** *** 148,172 **** - (((*arguments[5])->value.lval > 1000) ? 1900 : 0); /* fall-through */ case 5: ! ta->tm_mday = (*arguments[4])->value.lval; /* fall-through */ case 4: ta->tm_mon = (*arguments[3])->value.lval - 1; /* fall-through */ case 3: ! ta->tm_sec = (*arguments[2])->value.lval; /* fall-through */ case 2: ! ta->tm_min = (*arguments[1])->value.lval; /* fall-through */ case 1: ! ta->tm_hour = (*arguments[0])->value.lval; /* fall-through */ case 0: break; } ! seconds = mktime(ta); if (is_dst == -1) is_dst = ta->tm_isdst; --- 148,180 ---- - (((*arguments[5])->value.lval > 1000) ? 1900 : 0); /* fall-through */ case 5: ! val = (*arguments[4])->value.lval; ! if (val < 1) { chgsecs += (1-val) * 60*60*24; val = 1; } ! ta->tm_mday = val; /* fall-through */ case 4: ta->tm_mon = (*arguments[3])->value.lval - 1; /* fall-through */ case 3: ! val = (*arguments[2])->value.lval; ! if (val < 1) { chgsecs += (1-val); val = 1; } ! ta->tm_sec = val; /* fall-through */ case 2: ! val = (*arguments[1])->value.lval; ! if (val < 1) { chgsecs += (1-val) * 60; val = 1; } ! ta->tm_min = val; /* fall-through */ case 1: ! val = (*arguments[0])->value.lval; ! if (val < 1) { chgsecs += (1-val) * 60*60; val = 1; } ! ta->tm_hour = val; /* fall-through */ case 0: break; } ! seconds = mktime(ta) - chgsecs; if (is_dst == -1) is_dst = ta->tm_isdst;Now for tm_mon < 0, too: *** ext/standard/datetime.c.orig Fri Dec 8 12:38:02 2000 --- ext/standard/datetime.c Sun Apr 15 17:28:46 2001 *************** *** 81,87 **** struct tm *ta, tmbuf; time_t t; int i, gmadjust, seconds, arg_count = ZEND_NUM_ARGS(); ! int is_dst = -1; if (arg_count > 7 || zend_get_parameters_array_ex(arg_count,arguments) == FAILURE) { WRONG_PARAM_COUNT; --- 81,87 ---- struct tm *ta, tmbuf; time_t t; int i, gmadjust, seconds, 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; *************** *** 148,172 **** - (((*arguments[5])->value.lval > 1000) ? 1900 : 0); /* fall-through */ case 5: ! ta->tm_mday = (*arguments[4])->value.lval; /* fall-through */ case 4: ! ta->tm_mon = (*arguments[3])->value.lval - 1; /* fall-through */ case 3: ! ta->tm_sec = (*arguments[2])->value.lval; /* fall-through */ case 2: ! ta->tm_min = (*arguments[1])->value.lval; /* fall-through */ case 1: ! ta->tm_hour = (*arguments[0])->value.lval; /* fall-through */ case 0: break; } ! seconds = mktime(ta); if (is_dst == -1) is_dst = ta->tm_isdst; --- 148,182 ---- - (((*arguments[5])->value.lval > 1000) ? 1900 : 0); /* fall-through */ case 5: ! val = (*arguments[4])->value.lval; ! if (val < 1) { chgsecs += (1-val) * 60*60*24; val = 1; } ! ta->tm_mday = val; /* fall-through */ case 4: ! val = (*arguments[3])->value.lval - 1; ! while (val < 0) { val += 12; ta->tm_year--; } ! ta->tm_mon = val; /* fall-through */ case 3: ! val = (*arguments[2])->value.lval; ! if (val < 1) { chgsecs += (1-val); val = 1; } ! ta->tm_sec = val; /* fall-through */ case 2: ! val = (*arguments[1])->value.lval; ! if (val < 1) { chgsecs += (1-val) * 60; val = 1; } ! ta->tm_min = val; /* fall-through */ case 1: ! val = (*arguments[0])->value.lval; ! if (val < 1) { chgsecs += (1-val) * 60*60; val = 1; } ! ta->tm_hour = val; /* fall-through */ case 0: break; } ! seconds = mktime(ta) - chgsecs; if (is_dst == -1) is_dst = ta->tm_isdst;