| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| #include "config.h" |
| |
| #include <sys/types.h> |
| |
| #include <time.h> |
| #ifdef HAVE_STDLIB_H |
| #include <stdlib.h> |
| #endif |
| #include <stdio.h> |
| |
| #ifdef HAVE_STRING_H |
| #include <string.h> |
| #endif |
| |
| #ifdef WIN32 |
| #include <windows.h> /* for TIME_ZONE_INFORMATION */ |
| #endif |
| |
| #include "ne_alloc.h" |
| #include "ne_dates.h" |
| #include "ne_string.h" |
| |
| |
| |
| |
| #define ISO8601_FORMAT_Z "%04d-%02d-%02dT%02d:%02d:%lfZ" |
| #define ISO8601_FORMAT_M "%04d-%02d-%02dT%02d:%02d:%lf-%02d:%02d" |
| #define ISO8601_FORMAT_P "%04d-%02d-%02dT%02d:%02d:%lf+%02d:%02d" |
| |
| |
| #define RFC1123_FORMAT "%3s, %02d %3s %4d %02d:%02d:%02d GMT" |
| |
| #define RFC1036_FORMAT "%10s %2d-%3s-%2d %2d:%2d:%2d GMT" |
| |
| #define ASCTIME_FORMAT "%3s %3s %2d %2d:%2d:%2d %4d" |
| |
| static const char rfc1123_weekdays[7][4] = { |
| "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" |
| }; |
| static const char short_months[12][4] = { |
| "Jan", "Feb", "Mar", "Apr", "May", "Jun", |
| "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" |
| }; |
| |
| #if defined(HAVE_STRUCT_TM_TM_GMTOFF) |
| #define GMTOFF(t) ((t).tm_gmtoff) |
| #elif defined(HAVE_STRUCT_TM___TM_GMTOFF) |
| #define GMTOFF(t) ((t).__tm_gmtoff) |
| #elif defined(WIN32) |
| #define GMTOFF(t) (gmt_to_local_win32()) |
| #elif defined(HAVE_TIMEZONE) |
| |
| #define GMTOFF(t) (-timezone + ((t).tm_isdst > 0 ? 3600 : 0)) |
| #else |
| |
| #define GMTOFF(t) (0) |
| #endif |
| |
| #ifdef WIN32 |
| time_t gmt_to_local_win32(void) |
| { |
| TIME_ZONE_INFORMATION tzinfo; |
| DWORD dwStandardDaylight; |
| long bias; |
| |
| dwStandardDaylight = GetTimeZoneInformation(&tzinfo); |
| bias = tzinfo.Bias; |
| |
| if (dwStandardDaylight == TIME_ZONE_ID_STANDARD) |
| bias += tzinfo.StandardBias; |
| |
| if (dwStandardDaylight == TIME_ZONE_ID_DAYLIGHT) |
| bias += tzinfo.DaylightBias; |
| |
| return (- bias * 60); |
| } |
| #endif |
| |
| |
| |
| char *ne_rfc1123_date(time_t anytime) { |
| struct tm *gmt; |
| char *ret; |
| gmt = gmtime(&anytime); |
| if (gmt == NULL) |
| return NULL; |
| ret = ne_malloc(29 + 1); |
| |
| ne_snprintf(ret, 30, RFC1123_FORMAT, |
| rfc1123_weekdays[gmt->tm_wday], gmt->tm_mday, |
| short_months[gmt->tm_mon], 1900 + gmt->tm_year, |
| gmt->tm_hour, gmt->tm_min, gmt->tm_sec); |
| |
| return ret; |
| } |
| |
| |
| |
| time_t ne_iso8601_parse(const char *date) |
| { |
| struct tm gmt = {0}; |
| int off_hour, off_min; |
| double sec; |
| off_t fix; |
| int n; |
| time_t result; |
| |
| |
| if ((n = sscanf(date, ISO8601_FORMAT_P, |
| &gmt.tm_year, &gmt.tm_mon, &gmt.tm_mday, |
| &gmt.tm_hour, &gmt.tm_min, &sec, |
| &off_hour, &off_min)) == 8) { |
| gmt.tm_sec = (int)sec; |
| fix = - off_hour * 3600 - off_min * 60; |
| } |
| |
| else if ((n = sscanf(date, ISO8601_FORMAT_M, |
| &gmt.tm_year, &gmt.tm_mon, &gmt.tm_mday, |
| &gmt.tm_hour, &gmt.tm_min, &sec, |
| &off_hour, &off_min)) == 8) { |
| gmt.tm_sec = (int)sec; |
| fix = off_hour * 3600 + off_min * 60; |
| } |
| |
| else if ((n = sscanf(date, ISO8601_FORMAT_Z, |
| &gmt.tm_year, &gmt.tm_mon, &gmt.tm_mday, |
| &gmt.tm_hour, &gmt.tm_min, &sec)) == 6) { |
| gmt.tm_sec = (int)sec; |
| fix = 0; |
| } |
| else { |
| return (time_t)-1; |
| } |
| |
| gmt.tm_year -= 1900; |
| gmt.tm_isdst = -1; |
| gmt.tm_mon--; |
| |
| result = mktime(&gmt) + fix; |
| return result + GMTOFF(gmt); |
| } |
| |
| |
| |
| time_t ne_rfc1123_parse(const char *date) |
| { |
| struct tm gmt = {0}; |
| char wkday[4], mon[4]; |
| int n; |
| time_t result; |
| |
| |
| n = sscanf(date, RFC1123_FORMAT, |
| wkday, &gmt.tm_mday, mon, &gmt.tm_year, &gmt.tm_hour, |
| &gmt.tm_min, &gmt.tm_sec); |
| |
| gmt.tm_year -= 1900; |
| for (n=0; n<12; n++) |
| if (strcmp(mon, short_months[n]) == 0) |
| break; |
| |
| |
| gmt.tm_mon = n; |
| gmt.tm_isdst = -1; |
| result = mktime(&gmt); |
| return result + GMTOFF(gmt); |
| } |
| |
| |
| time_t ne_rfc1036_parse(const char *date) |
| { |
| struct tm gmt = {0}; |
| int n; |
| char wkday[11], mon[4]; |
| time_t result; |
| |
| |
| n = sscanf(date, RFC1036_FORMAT, |
| wkday, &gmt.tm_mday, mon, &gmt.tm_year, |
| &gmt.tm_hour, &gmt.tm_min, &gmt.tm_sec); |
| if (n != 7) { |
| return (time_t)-1; |
| } |
| |
| |
| for (n=0; n<12; n++) |
| if (strcmp(mon, short_months[n]) == 0) |
| break; |
| |
| |
| |
| |
| if (gmt.tm_year < 50) |
| gmt.tm_year += 100; |
| |
| gmt.tm_mon = n; |
| gmt.tm_isdst = -1; |
| result = mktime(&gmt); |
| return result + GMTOFF(gmt); |
| } |
| |
| |
| |
| |
| |
| time_t ne_asctime_parse(const char *date) |
| { |
| struct tm gmt = {0}; |
| int n; |
| char wkday[4], mon[4]; |
| time_t result; |
| |
| n = sscanf(date, ASCTIME_FORMAT, |
| wkday, mon, &gmt.tm_mday, |
| &gmt.tm_hour, &gmt.tm_min, &gmt.tm_sec, |
| &gmt.tm_year); |
| |
| for (n=0; n<12; n++) |
| if (strcmp(mon, short_months[n]) == 0) |
| break; |
| |
| |
| gmt.tm_mon = n; |
| gmt.tm_isdst = -1; |
| result = mktime(&gmt); |
| return result + GMTOFF(gmt); |
| } |
| |
| |
| time_t ne_httpdate_parse(const char *date) |
| { |
| time_t tmp; |
| tmp = ne_rfc1123_parse(date); |
| if (tmp == -1) { |
| tmp = ne_rfc1036_parse(date); |
| if (tmp == -1) |
| tmp = ne_asctime_parse(date); |
| } |
| return tmp; |
| } |