summaryrefslogtreecommitdiff
path: root/lib/parsedate.c
diff options
context:
space:
mode:
authorDaniel Stenberg <daniel@haxx.se>2008-09-23 11:00:01 +0000
committerDaniel Stenberg <daniel@haxx.se>2008-09-23 11:00:01 +0000
commitd369a2b7755d763490575fc18de748def0b3ba77 (patch)
tree7eebd3b352f91fae13a982ac8f30e9a9cceee11e /lib/parsedate.c
parenta5f4cfc6126b5e6085d3972a00f37409de65ad11 (diff)
downloadcurl-d369a2b7755d763490575fc18de748def0b3ba77.tar.gz
- Introducing Jamie Lokier's function for date to epoch conversion used in the
date parser function. This makes our function less dependent on system- provided functions and instead we do all the magic ourselves. We also no longer depend on the TZ environment variable.
Diffstat (limited to 'lib/parsedate.c')
-rw-r--r--lib/parsedate.c72
1 files changed, 40 insertions, 32 deletions
diff --git a/lib/parsedate.c b/lib/parsedate.c
index 64bb2cc41..d1d1fdc82 100644
--- a/lib/parsedate.c
+++ b/lib/parsedate.c
@@ -222,6 +222,38 @@ enum assume {
DATE_TIME
};
+/* struct tm to time since epoch in GMT time zone */
+static time_t my_timegm(struct tm * tm)
+{
+ int month_days_cumulative [12] =
+ { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
+ int month, year, leap_days;
+
+ if(tm->tm_year < 70)
+ /* we don't support years before 1970 as they will cause this function
+ to return a negative value */
+ return -1;
+
+ year = tm->tm_year + 1900;
+ month = tm->tm_mon;
+ if (month < 0) {
+ year += (11 - month) / 12;
+ month = 11 - (11 - month) % 12;
+ }
+ else if (month >= 12) {
+ year -= month / 12;
+ month = month % 12;
+ }
+
+ leap_days = year - (tm->tm_mon <= 1);
+ leap_days = ((leap_days / 4) - (leap_days / 100) + (leap_days / 400)
+ - (1969 / 4) + (1969 / 100) - (1969 / 400));
+
+ return ((((time_t) (year - 1970) * 365
+ + leap_days + month_days_cumulative [month] + tm->tm_mday - 1) * 24
+ + tm->tm_hour) * 60 + tm->tm_min) * 60 + tm->tm_sec;
+}
+
static time_t parsedate(const char *date)
{
time_t t = 0;
@@ -247,7 +279,8 @@ static time_t parsedate(const char *date)
/* a name coming up */
char buf[32]="";
size_t len;
- sscanf(date, "%31[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz]", buf);
+ sscanf(date, "%31[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz]",
+ buf);
len = strlen(buf);
if(wdaynum == -1) {
@@ -374,45 +407,20 @@ static time_t parsedate(const char *date)
tm.tm_yday = 0;
tm.tm_isdst = 0;
- /* mktime() returns a time_t. time_t is often 32 bits, even on many
+ /* 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 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)
+ 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 = mktime(&tm);
+ t = my_timegm(&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));
+ /* 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 */