From 7885264b293c1909b07f9aa08896337c85c2e432 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 13 Sep 2004 07:45:19 +0000 Subject: [PATCH] Since many users probably already use local time strings as input, I now made it deal with named time zones as well as mail-style +0200 ones. Seems to work fine. I'm comparing with GNU date command: date -d [date] -u +%s --- lib/parsedate.c | 115 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 92 insertions(+), 23 deletions(-) diff --git a/lib/parsedate.c b/lib/parsedate.c index 00498a013..fe2cd1ea1 100644 --- a/lib/parsedate.c +++ b/lib/parsedate.c @@ -78,7 +78,58 @@ static const char *weekday[] = { "Monday", "Tuesday", "Wednesday", "Thursday", const char *Curl_month[]= { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; -static const char *tz[]= { "GMT", "UTC", "MET" }; +struct tzinfo { + const char *name; + int offset; /* +/- in minutes */ +}; + +/* Here's a bunch of frequently used time zone names. These were supported + by the old getdate parser. */ +static const struct tzinfo tz[]= { + {"GMT", 0}, /* Greenwich Mean */ + {"UTC", 0}, /* Universal (Coordinated) */ + {"WET", 0}, /* Western European */ + {"BST", 0}, /* British Summer */ + {"WAT", 60}, /* West Africa */ + {"AST", 240}, /* Atlantic Standard */ + {"ADT", 240}, /* Atlantic Daylight */ + {"EST", 300}, /* Eastern Standard */ + {"EDT", 300}, /* Eastern Daylight */ + {"CST", 360}, /* Central Standard */ + {"CDT", 360}, /* Central Daylight */ + {"MST", 420}, /* Mountain Standard */ + {"MDT", 420}, /* Mountain Daylight */ + {"PST", 480}, /* Pacific Standard */ + {"PDT", 480}, /* Pacific Daylight */ + {"YST", 540}, /* Yukon Standard */ + {"YDT", 540}, /* Yukon Daylight */ + {"HST", 600}, /* Hawaii Standard */ + {"HDT", 600}, /* Hawaii Daylight */ + {"CAT", 600}, /* Central Alaska */ + {"AHST", 600}, /* Alaska-Hawaii Standard */ + {"NT", 660}, /* Nome */ + {"IDLW", 720}, /* International Date Line West */ + {"CET", -60}, /* Central European */ + {"MET", -60}, /* Middle European */ + {"MEWT", -60}, /* Middle European Winter */ + {"MEST", -120}, /* Middle European Summer */ + {"CEST", -120}, /* Central European Summer */ + {"MESZ", -60}, /* Middle European Summer */ + {"FWT", -60}, /* French Winter */ + {"FST", -60}, /* French Summer */ + {"EET", -120}, /* Eastern Europe, USSR Zone 1 */ + {"WAST", -420}, /* West Australian Standard */ + {"WADT", -420}, /* West Australian Daylight */ + {"CCT", -480}, /* China Coast, USSR Zone 7 */ + {"JST", -540}, /* Japan Standard, USSR Zone 8 */ + {"EAST", -600}, /* Eastern Australian Standard */ + {"EADT", -600}, /* Eastern Australian Daylight */ + {"GST", -600}, /* Guam Standard, USSR Zone 9 */ + {"NZT", -720}, /* New Zealand */ + {"NZST", -720}, /* New Zealand Standard */ + {"NZDT", -720}, /* New Zealand Daylight */ + {"IDLE", -720}, /* International Date Line East */ +}; /* returns: -1 no day @@ -118,24 +169,27 @@ static int checkmonth(char *check) } what++; } - return found?i:-1; + return found?i:-1; /* return the offset or -1, no real offset is -1 */ } +/* return the time zone offset between GMT and the input one, in number + of seconds or -1 if the timezone wasn't found/legal */ + static int checktz(char *check) { - int i; - const char **what; + unsigned int i; + const struct tzinfo *what; bool found= FALSE; - what = &tz[0]; - for(i=0; i<2; i++) { - if(curl_strequal(check, what[0])) { + what = tz; + for(i=0; i< sizeof(tz)/sizeof(tz[0]); i++) { + if(curl_strequal(check, what->name)) { found=TRUE; break; } what++; } - return found?i:-1; + return found?what->offset*60:-1; } static void skip(const char **date) @@ -156,17 +210,17 @@ difftm (struct tm *a, struct tm *b) int by = b->tm_year + (TM_YEAR_ORIGIN - 1); long days = ( /* difference in day of year */ - a->tm_yday - b->tm_yday + a->tm_yday - b->tm_yday /* + intervening leap days */ - + ((ay >> 2) - (by >> 2)) - - (ay / 100 - by / 100) - + ((ay / 100 >> 2) - (by / 100 >> 2)) + + ((ay >> 2) - (by >> 2)) + - (ay / 100 - by / 100) + + ((ay / 100 >> 2) - (by / 100 >> 2)) /* + difference in years * 365 */ - + (long) (ay - by) * 365 + + (long) (ay - by) * 365 ); return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour)) - + (a->tm_min - b->tm_min)) - + (a->tm_sec - b->tm_sec)); + + (a->tm_min - b->tm_min)) + + (a->tm_sec - b->tm_sec)); } #endif @@ -186,9 +240,10 @@ time_t Curl_parsedate(const char *date) int minnum=-1; int secnum=-1; long yearnum=-1; - int tznum=-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 */ @@ -215,10 +270,10 @@ time_t Curl_parsedate(const char *date) found = TRUE; } - if(!found && (tznum == -1)) { + if(!found && (tzoff == -1)) { /* this just must be a time zone string */ - tznum = checktz(buf); - if(tznum != -1) + tzoff = checktz(buf); + if(tzoff != -1) found = TRUE; } @@ -240,6 +295,20 @@ time_t Curl_parsedate(const char *date) else { val = strtol(date, &end, 10); + if( ((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((dignext == DATE_MDAY) && (mdaynum == -1)) { if((val > 0) && (val<32)) { mdaynum = val; @@ -311,12 +380,12 @@ time_t Curl_parsedate(const char *date) #endif t2 = mktime(gmt); - delta = t - t2; - /* if we would like to adjust to a different input time zone than GMT, - we would add that to the delta value right here */ + /* Add the time zone diff (between the given timezone and GMT) and the + diff between the local time zone and GMT. */ + delta = (tzoff!=-1?tzoff:0) + (t - t2); - if(t + delta < t) + if((delta>0) && (t + delta < t)) return -1; /* time_t overflow */ t += delta;