int Curl_parsedate(const char *date, time_t *output) { time_t t = 0; int wdaynum=-1; /* day of the week number, 0-6 (mon-sun) */ int monnum=-1; /* month of the year number, 0-11 */ int mdaynum=-1; /* day of month, 1 - 31 */ int hournum=-1; int minnum=-1; int secnum=-1; int yearnum=-1; int tzoff=-1; struct my_tm tm; enum assume dignext = DATE_MDAY; const char *indate = date; /* save the original pointer */ int part = 0; /* max 6 parts */ while(*date && (part < 6)) { bool found=FALSE; skip(&date); if(ISALPHA(*date)) { /* a name coming up */ char buf[32]=""; size_t len; sscanf(date, "%31[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz]", buf); len = strlen(buf); if(wdaynum == -1) { wdaynum = checkday(buf, len); if(wdaynum != -1) found = TRUE; } if(!found && (monnum == -1)) { monnum = checkmonth(buf); if(monnum != -1) found = TRUE; } if(!found && (tzoff == -1)) { /* this just must be a time zone string */ tzoff = checktz(buf); if(tzoff != -1) found = TRUE; } if(!found) return PARSEDATE_FAIL; /* bad string */ date += len; } else if(ISDIGIT(*date)) { /* a digit */ int val; char *end; if((secnum == -1) && (3 == sscanf(date, "%02d:%02d:%02d", &hournum, &minnum, &secnum))) { /* time stamp! */ date += 8; } else if((secnum == -1) && (2 == sscanf(date, "%02d:%02d", &hournum, &minnum))) { /* time stamp without seconds */ date += 5; secnum = 0; } else { val = curlx_sltosi(strtol(date, &end, 10)); if((tzoff == -1) && ((end - date) == 4) && (val <= 1400) && (indate< date) && ((date[-1] == '+' || date[-1] == '-'))) { /* four digits and a value less than or equal to 1400 (to take into account all sorts of funny time zone diffs) and it is preceeded with a plus or minus. This is a time zone indication. 1400 is picked since +1300 is frequently used and +1400 is mentioned as an edge number in the document "ISO C 200X Proposal: Timezone Functions" at http://david.tribble.com/text/c0xtimezone.html If anyone has a more authoritative source for the exact maximum time zone offsets, please speak up! */ found = TRUE; tzoff = (val/100 * 60 + val%100)*60; /* the + and - prefix indicates the local time compared to GMT, this we need ther reversed math to get what we want */ tzoff = date[-1]=='+'?-tzoff:tzoff; } if(((end - date) == 8) && (yearnum == -1) && (monnum == -1) && (mdaynum == -1)) { /* 8 digits, no year, month or day yet. This is YYYYMMDD */ found = TRUE; yearnum = val/10000; monnum = (val%10000)/100-1; /* month is 0 - 11 */ mdaynum = val%100; } if(!found && (dignext == DATE_MDAY) && (mdaynum == -1)) { if((val > 0) && (val<32)) { mdaynum = val; found = TRUE; } dignext = DATE_YEAR; } if(!found && (dignext == DATE_YEAR) && (yearnum == -1)) { yearnum = val; found = TRUE; if(yearnum < 1900) { if(yearnum > 70) yearnum += 1900; else yearnum += 2000; } if(mdaynum == -1) dignext = DATE_MDAY; } if(!found) return PARSEDATE_FAIL; date = end; } } part++; } if(-1 == secnum) secnum = minnum = hournum = 0; /* no time, make it zero */ if((-1 == mdaynum) || (-1 == monnum) || (-1 == yearnum)) /* lacks vital info, fail */ return PARSEDATE_FAIL; #if SIZEOF_TIME_T < 5 /* 32 bit time_t can only hold dates to the beginning of 2038 */ if(yearnum > 2037) { *output = 0x7fffffff; return PARSEDATE_LATER; } #endif if(yearnum < 1970) { *output = 0; return PARSEDATE_SOONER; } tm.tm_sec = secnum; tm.tm_min = minnum; tm.tm_hour = hournum; tm.tm_mday = mdaynum; tm.tm_mon = monnum; tm.tm_year = yearnum - 1900; /* my_timegm() returns a time_t. time_t is often 32 bits, even on many architectures that feature 64 bit 'long'. Some systems have 64 bit time_t and deal with years beyond 2038. However, even on some of the systems with 64 bit time_t mktime() returns -1 for dates beyond 03:14:07 UTC, January 19, 2038. (Such as AIX 5100-06) */ t = my_timegm(&tm); /* time zone adjust (cast t to int to compare to negative one) */ if(-1 != (int)t) { /* Add the time zone diff between local time zone and GMT. */ long delta = (long)(tzoff!=-1?tzoff:0); if((delta>0) && (t + delta < t)) return -1; /* time_t overflow */ t += delta; } *output = t; return PARSEDATE_OK; }
time_t strtotime(const char *string){ int sec = -1; /* seconds */ int min = -1; /* minutes */ int hour = -1; /* hours */ int mday = -1; /* day of the month */ int mon = -1; /* month */ int year = -1; /* year */ int wday = -1; /* day of the week */ int tzoff = -1; /* time zone offset */ int part = 0; time_t t = 0; time_t now = 0; struct tm tm; const char *date; const char *indate = string; /* original pointer */ enum assume dignext = DATE_MDAY; BOOLEAN found = FALSE; /* * Make sure we have a string to parse. */ if(!(string && *string)) return(0); date = string; /** * this parser was more or less stolen form libcurl. * Copyright (C) 1998 - 2006, Daniel Stenberg, <*****@*****.**>, et al. * http://curl.haxx.se/ */ while(*date && (part < 6)) { found=FALSE; skip(&date); if(isalpha((unsigned char)*date)) { /* a name coming up */ char buf[32]=""; size_t len; sscanf(date, "%31[A-Za-z]", buf); len = strlen(buf); if(wday == -1) { wday = checkday(buf, len); if(wday != -1) found = TRUE; } if(!found && (mon == -1)) { mon = checkmonth(buf); if(mon != -1) found = TRUE; } if(!found && (tzoff == -1)) { /* this just must be a time zone string */ tzoff = checktz(buf); if(tzoff != -1) found = TRUE; } if(!found) return -1; /* bad string */ date += len; } else if(isdigit((unsigned char)*date)) { /* a digit */ int val; char *end; if((sec == -1) && (3 == sscanf(date, "%02d:%02d:%02d", &hour, &min, &sec))) { /* time stamp! */ date += 8; found = TRUE; } else { val = (int)strtol(date, &end, 10); if((tzoff == -1) && ((end - date) == 4) && (val < 1300) && (indate< date) && ((date[-1] == '+' || date[-1] == '-'))) { /* four digits and a value less than 1300 and it is preceeded with a plus or minus. This is a time zone indication. */ found = TRUE; tzoff = (val/100 * 60 + val%100)*60; /* the + and - prefix indicates the local time compared to GMT, this we need ther reversed math to get what we want */ tzoff = date[-1]=='+'?-tzoff:tzoff; } if(((end - date) == 8) && (year == -1) && (mon == -1) && (mday == -1)) { /* 8 digits, no year, month or day yet. This is YYYYMMDD */ found = TRUE; year = val/10000; mon = (val%10000)/100-1; /* month is 0 - 11 */ mday = val%100; } if(!found && (dignext == DATE_MDAY) && (mday == -1)) { if((val > 0) && (val<32)) { mday = val; found = TRUE; } dignext = DATE_YEAR; } if(!found && (dignext == DATE_YEAR) && (year == -1)) { year = val; found = TRUE; if(year < 1900) { if (year > 70) year += 1900; else year += 2000; } if(mday == -1) dignext = DATE_MDAY; } if(!found) return -1; date = end; } } part++; } if(-1 == sec) sec = min = hour = 0; /* no time, make it zero */ if((-1 == mday) || (-1 == mon) || (-1 == year)) /* lacks vital info, fail */ return -1; /* Y238 'bug' */ if(year > 2037) return 0x7fffffff; tm.tm_sec = sec; tm.tm_min = min; tm.tm_hour = hour; tm.tm_mday = mday; tm.tm_mon = mon; tm.tm_year = year - 1900; tm.tm_wday = 0; tm.tm_yday = 0; tm.tm_isdst = 0; t = mktime(&tm); /* time zone adjust (cast t to int to compare to negative one) */ if(-1 != (int)t) { struct tm *gmt; long delta; time_t t2; #ifdef HAVE_GMTIME_R /* thread-safe version */ struct tm keeptime2; gmt = (struct tm *)gmtime_r(&t, &keeptime2); if(!gmt) return -1; /* illegal date/time */ t2 = mktime(gmt); #else /* It seems that at least the MSVC version of mktime() doesn't work properly if it gets the 'gmt' pointer passed in (which is a pointer returned from gmtime() pointing to static memory), so instead we copy the tm struct to a local struct and pass a pointer to that struct as input to mktime(). */ struct tm gmt2; gmt = gmtime(&t); /* use gmtime_r() if available */ if(!gmt) return -1; /* illegal date/time */ gmt2 = *gmt; t2 = mktime(&gmt2); #endif /* Add the time zone diff (between the given timezone and GMT) and the diff between the local time zone and GMT. */ delta = (long)((tzoff!=-1?tzoff:0) + (t - t2)); if((delta>0) && (t + delta < t)) return -1; /* time_t overflow */ t += delta; } now = time(NULL); return t; }
static int parsedate(const char *date, time_t *output) { time_t t = 0; int wdaynum = -1; /* day of the week number, 0-6 (mon-sun) */ int monnum = -1; /* month of the year number, 0-11 */ int mdaynum = -1; /* day of month, 1 - 31 */ int hournum = -1; int minnum = -1; int secnum = -1; int yearnum = -1; int tzoff = -1; struct my_tm tm; enum assume dignext = DATE_MDAY; const char *indate = date; /* save the original pointer */ int part = 0; /* max 6 parts */ while(*date && (part < 6)) { bool found = FALSE; skip(&date); if(ISALPHA(*date)) { /* a name coming up */ char buf[32]=""; size_t len; if(sscanf(date, "%31[ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz]", buf)) len = strlen(buf); else len = 0; if(wdaynum == -1) { wdaynum = checkday(buf, len); if(wdaynum != -1) found = TRUE; } if(!found && (monnum == -1)) { monnum = checkmonth(buf); if(monnum != -1) found = TRUE; } if(!found && (tzoff == -1)) { /* this just must be a time zone string */ tzoff = checktz(buf); if(tzoff != -1) found = TRUE; } if(!found) return PARSEDATE_FAIL; /* bad string */ date += len; } else if(ISDIGIT(*date)) { /* a digit */ int val; char *end; int len = 0; if((secnum == -1) && (3 == sscanf(date, "%02d:%02d:%02d%n", &hournum, &minnum, &secnum, &len))) { /* time stamp! */ date += len; } else if((secnum == -1) && (2 == sscanf(date, "%02d:%02d%n", &hournum, &minnum, &len))) { /* time stamp without seconds */ date += len; secnum = 0; } else { long lval; int error; int old_errno; old_errno = errno; errno = 0; lval = strtol(date, &end, 10); error = errno; if(errno != old_errno) errno = old_errno; if(error) return PARSEDATE_FAIL; #if LONG_MAX != INT_MAX if((lval > (long)INT_MAX) || (lval < (long)INT_MIN)) return PARSEDATE_FAIL; #endif val = curlx_sltosi(lval); if((tzoff == -1) && ((end - date) == 4) && (val <= 1400) && (indate< date) && ((date[-1] == '+' || date[-1] == '-'))) { /* four digits and a value less than or equal to 1400 (to take into account all sorts of funny time zone diffs) and it is preceded with a plus or minus. This is a time zone indication. 1400 is picked since +1300 is frequently used and +1400 is mentioned as an edge number in the document "ISO C 200X Proposal: Timezone Functions" at http://david.tribble.com/text/c0xtimezone.html If anyone has a more authoritative source for the exact maximum time zone offsets, please speak up! */ found = TRUE; tzoff = (val/100 * 60 + val%100)*60; /* the + and - prefix indicates the local time compared to GMT, this we need their reversed math to get what we want */ tzoff = date[-1]=='+'?-tzoff:tzoff; } if(((end - date) == 8) && (yearnum == -1) && (monnum == -1) && (mdaynum == -1)) { /* 8 digits, no year, month or day yet. This is YYYYMMDD */ found = TRUE; yearnum = val/10000; monnum = (val%10000)/100-1; /* month is 0 - 11 */ mdaynum = val%100; } if(!found && (dignext == DATE_MDAY) && (mdaynum == -1)) { if((val > 0) && (val<32)) { mdaynum = val; found = TRUE; } dignext = DATE_YEAR; } if(!found && (dignext == DATE_YEAR) && (yearnum == -1)) { yearnum = val; found = TRUE; if(yearnum < 100) { if(yearnum > 70) yearnum += 1900; else yearnum += 2000; } if(mdaynum == -1) dignext = DATE_MDAY; } if(!found) return PARSEDATE_FAIL; date = end; } } part++; } if(-1 == secnum) secnum = minnum = hournum = 0; /* no time, make it zero */ if((-1 == mdaynum) || (-1 == monnum) || (-1 == yearnum)) /* lacks vital info, fail */ return PARSEDATE_FAIL; #ifdef HAVE_TIME_T_UNSIGNED if(yearnum < 1970) { /* only positive numbers cannot return earlier */ *output = TIME_T_MIN; return PARSEDATE_SOONER; } #endif #if (SIZEOF_TIME_T < 5) #ifdef HAVE_TIME_T_UNSIGNED /* an unsigned 32 bit time_t can only hold dates to 2106 */ if(yearnum > 2105) { *output = TIME_T_MAX; return PARSEDATE_LATER; } #else /* a signed 32 bit time_t can only hold dates to the beginning of 2038 */ if(yearnum > 2037) { *output = TIME_T_MAX; return PARSEDATE_LATER; } if(yearnum < 1903) { *output = TIME_T_MIN; return PARSEDATE_SOONER; } #endif #else /* The Gregorian calendar was introduced 1582 */ if(yearnum < 1583) return PARSEDATE_FAIL; #endif if((mdaynum > 31) || (monnum > 11) || (hournum > 23) || (minnum > 59) || (secnum > 60)) return PARSEDATE_FAIL; /* clearly an illegal date */ tm.tm_sec = secnum; tm.tm_min = minnum; tm.tm_hour = hournum; tm.tm_mday = mdaynum; tm.tm_mon = monnum; tm.tm_year = yearnum; /* my_timegm() returns a time_t. time_t is often 32 bits, sometimes even on architectures that feature 64 bit 'long' but ultimately time_t is the correct data type to use. */ my_timegm(&tm, &t); /* Add the time zone diff between local time zone and GMT. */ if(tzoff == -1) tzoff = 0; if((tzoff > 0) && (t > TIME_T_MAX - tzoff)) { *output = TIME_T_MAX; return PARSEDATE_LATER; /* time_t overflow */ } t += tzoff; *output = t; return PARSEDATE_OK; }
static time_t Curl_parsedate(const char *date) { time_t t = 0; int wdaynum=-1; /* day of the week number, 0-6 (mon-sun) */ int monnum=-1; /* month of the year number, 0-11 */ int mdaynum=-1; /* day of month, 1 - 31 */ int hournum=-1; int minnum=-1; int secnum=-1; int yearnum=-1; int tzoff=-1; struct tm tm; enum assume dignext = DATE_MDAY; const char *indate = date; /* save the original pointer */ int part = 0; /* max 6 parts */ #ifdef WIN32 /* * On Windows, we need an odd work-around for the case when no TZ variable * is set. If it isn't set and "automatic DST adjustment" is enabled, the * time functions below will return values one hour off! As reported and * investigated in bug report #1230118. */ const char *env = getenv("TZ"); if(!env) putenv("TZ=GMT"); #endif while(*date && (part < 6)) { int found=FALSE; skip(&date); if(isalpha((int)*date)) { /* a name coming up */ char buf[32]=""; size_t len; sscanf(date, "%31[A-Za-z]", buf); len = strlen(buf); if(wdaynum == -1) { wdaynum = checkday(buf, len); if(wdaynum != -1) found = TRUE; } if(!found && (monnum == -1)) { monnum = checkmonth(buf); if(monnum != -1) found = TRUE; } if(!found && (tzoff == -1)) { /* this just must be a time zone string */ tzoff = checktz(buf); if(tzoff != -1) found = TRUE; } if(!found) return -1; /* bad string */ date += len; } else if(isdigit((int)*date)) { /* a digit */ int val; char *end; if((secnum == -1) && (3 == sscanf(date, "%02d:%02d:%02d", &hournum, &minnum, &secnum))) { /* time stamp! */ date += 8; found = TRUE; } else { val = (int)strtol(date, &end, 10); if((tzoff == -1) && ((end - date) == 4) && (val < 1300) && (indate< date) && ((date[-1] == '+' || date[-1] == '-'))) { /* four digits and a value less than 1300 and it is preceeded with a plus or minus. This is a time zone indication. */ found = TRUE; tzoff = (val/100 * 60 + val%100)*60; /* the + and - prefix indicates the local time compared to GMT, this we need ther reversed math to get what we want */ tzoff = date[-1]=='+'?-tzoff:tzoff; } if(((end - date) == 8) && (yearnum == -1) && (monnum == -1) && (mdaynum == -1)) { /* 8 digits, no year, month or day yet. This is YYYYMMDD */ found = TRUE; yearnum = val/10000; monnum = (val%10000)/100-1; /* month is 0 - 11 */ mdaynum = val%100; } if(!found && (dignext == DATE_MDAY) && (mdaynum == -1)) { if((val > 0) && (val<32)) { mdaynum = val; found = TRUE; } dignext = DATE_YEAR; } if(!found && (dignext == DATE_YEAR) && (yearnum == -1)) { yearnum = val; found = TRUE; if(yearnum < 1900) { if (yearnum > 70) yearnum += 1900; else yearnum += 2000; } if(mdaynum == -1) dignext = DATE_MDAY; } if(!found) return -1; date = end; } } part++; } if(-1 == secnum) secnum = minnum = hournum = 0; /* no time, make it zero */ if((-1 == mdaynum) || (-1 == monnum) || (-1 == yearnum)) /* lacks vital info, fail */ return -1; #if SIZEOF_TIME_T < 5 /* 32 bit time_t can only hold dates to the beginning of 2038 */ if(yearnum > 2037) return 0x7fffffff; #endif tm.tm_sec = secnum; tm.tm_min = minnum; tm.tm_hour = hournum; tm.tm_mday = mdaynum; tm.tm_mon = monnum; tm.tm_year = yearnum - 1900; tm.tm_wday = 0; tm.tm_yday = 0; tm.tm_isdst = 0; /* mktime() returns a time_t. time_t is often 32 bits, even on many architectures that feature 64 bit 'long'. Some systems have 64 bit time_t and deal with years beyond 2038. However, even some of the systems with 64 bit time_t returns -1 for dates beyond 03:14:07 UTC, January 19, 2038. (Such as AIX 5100-06) */ t = mktime(&tm); /* time zone adjust (cast t to int to compare to negative one) */ if(-1 != (int)t) { struct tm *gmt; long delta; time_t t2; #ifdef HAVE_GMTIME_R /* thread-safe version */ struct tm keeptime2; gmt = (struct tm *)gmtime_r(&t, &keeptime2); #else gmt = gmtime(&t); /* use gmtime_r() if available */ #endif if(!gmt) return -1; /* illegal date/time */ t2 = mktime(gmt); /* Add the time zone diff (between the given timezone and GMT) and the diff between the local time zone and GMT. */ delta = (long)((tzoff!=-1?tzoff:0) + (t - t2)); if((delta>0) && (t + delta < t)) return -1; /* time_t overflow */ t += delta; } return t; }
static time_t parsedate(const char *date) { time_t t = 0; int wdaynum=-1; /* day of the week number, 0-6 (mon-sun) */ int monnum=-1; /* month of the year number, 0-11 */ int mdaynum=-1; /* day of month, 1 - 31 */ int hournum=-1; int minnum=-1; int secnum=-1; int yearnum=-1; int tzoff=-1; struct tm tm; enum assume dignext = DATE_MDAY; const char *indate = date; /* save the original pointer */ int part = 0; /* max 6 parts */ while(*date && (part < 6)) { bool found=FALSE; skip(&date); if(ISALPHA(*date)) { /* a name coming up */ char buf[32]=""; size_t len; sscanf(date, "%31[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz]", buf); len = strlen(buf); if(wdaynum == -1) { wdaynum = checkday(buf, len); if(wdaynum != -1) found = TRUE; } if(!found && (monnum == -1)) { monnum = checkmonth(buf); if(monnum != -1) found = TRUE; } if(!found && (tzoff == -1)) { /* this just must be a time zone string */ tzoff = checktz(buf); if(tzoff != -1) found = TRUE; } if(!found) return -1; /* bad string */ date += len; } else if(ISDIGIT(*date)) { /* a digit */ int val; char *end; if((secnum == -1) && (3 == sscanf(date, "%02d:%02d:%02d", &hournum, &minnum, &secnum))) { /* time stamp! */ date += 8; found = TRUE; } else { val = (int)strtol(date, &end, 10); if((tzoff == -1) && ((end - date) == 4) && (val <= 1400) && (indate< date) && ((date[-1] == '+' || date[-1] == '-'))) { /* four digits and a value less than or equal to 1400 (to take into account all sorts of funny time zone diffs) and it is preceeded with a plus or minus. This is a time zone indication. 1400 is picked since +1300 is frequently used and +1400 is mentioned as an edge number in the document "ISO C 200X Proposal: Timezone Functions" at http://david.tribble.com/text/c0xtimezone.html If anyone has a more authoritative source for the exact maximum time zone offsets, please speak up! */ found = TRUE; tzoff = (val/100 * 60 + val%100)*60; /* the + and - prefix indicates the local time compared to GMT, this we need ther reversed math to get what we want */ tzoff = date[-1]=='+'?-tzoff:tzoff; } if(((end - date) == 8) && (yearnum == -1) && (monnum == -1) && (mdaynum == -1)) { /* 8 digits, no year, month or day yet. This is YYYYMMDD */ found = TRUE; yearnum = val/10000; monnum = (val%10000)/100-1; /* month is 0 - 11 */ mdaynum = val%100; } if(!found && (dignext == DATE_MDAY) && (mdaynum == -1)) { if((val > 0) && (val<32)) { mdaynum = val; found = TRUE; } dignext = DATE_YEAR; } if(!found && (dignext == DATE_YEAR) && (yearnum == -1)) { yearnum = val; found = TRUE; if(yearnum < 1900) { if(yearnum > 70) yearnum += 1900; else yearnum += 2000; } if(mdaynum == -1) dignext = DATE_MDAY; } if(!found) return -1; date = end; } } part++; } if(-1 == secnum) secnum = minnum = hournum = 0; /* no time, make it zero */ if((-1 == mdaynum) || (-1 == monnum) || (-1 == yearnum)) /* lacks vital info, fail */ return -1; #if SIZEOF_TIME_T < 5 /* 32 bit time_t can only hold dates to the beginning of 2038 */ if(yearnum > 2037) return 0x7fffffff; #endif tm.tm_sec = secnum; tm.tm_min = minnum; tm.tm_hour = hournum; tm.tm_mday = mdaynum; tm.tm_mon = monnum; tm.tm_year = yearnum - 1900; tm.tm_wday = 0; tm.tm_yday = 0; tm.tm_isdst = 0; /* mktime() returns a time_t. time_t is often 32 bits, even on many architectures that feature 64 bit 'long'. Some systems have 64 bit time_t and deal with years beyond 2038. However, even some of the systems with 64 bit time_t returns -1 for dates beyond 03:14:07 UTC, January 19, 2038. (Such as AIX 5100-06) */ t = mktime(&tm); /* time zone adjust (cast t to int to compare to negative one) */ if(-1 != (int)t) { struct tm *gmt; long delta; time_t t2; #ifdef HAVE_GMTIME_R /* thread-safe version */ struct tm keeptime2; gmt = (struct tm *)gmtime_r(&t, &keeptime2); if(!gmt) return -1; /* illegal date/time */ t2 = mktime(gmt); #else /* It seems that at least the MSVC version of mktime() doesn't work properly if it gets the 'gmt' pointer passed in (which is a pointer returned from gmtime() pointing to static memory), so instead we copy the tm struct to a local struct and pass a pointer to that struct as input to mktime(). */ struct tm gmt2; gmt = gmtime(&t); /* use gmtime_r() if available */ if(!gmt) return -1; /* illegal date/time */ gmt2 = *gmt; t2 = mktime(&gmt2); #endif /* Add the time zone diff (between the given timezone and GMT) and the diff between the local time zone and GMT. */ delta = (long)((tzoff!=-1?tzoff:0) + (t - t2)); if((delta>0) && (t + delta < t)) return -1; /* time_t overflow */ t += delta; } return t; }