/* Gr. strptime is crap for this; it doesn't have a way to require RFC2822 (i.e. English) day/month names, and it doesn't work correctly with %z. */ int parse_date_basic(const char *date, unsigned long *timestamp, int *offset) { struct tm tm; int tm_gmt; unsigned long dummy_timestamp; int dummy_offset; if (!timestamp) timestamp = &dummy_timestamp; if (!offset) offset = &dummy_offset; memset(&tm, 0, sizeof(tm)); tm.tm_year = -1; tm.tm_mon = -1; tm.tm_mday = -1; tm.tm_isdst = -1; tm.tm_hour = -1; tm.tm_min = -1; tm.tm_sec = -1; *offset = -1; tm_gmt = 0; for (;;) { int match = 0; unsigned char c = *date; /* Stop at end of string or newline */ if (!c || c == '\n') break; if (isalpha(c)) match = match_alpha(date, &tm, offset); else if (isdigit(c)) match = match_digit(date, &tm, offset, &tm_gmt); else if ((c == '-' || c == '+') && isdigit(date[1])) match = match_tz(date, offset); if (!match) { /* BAD CRAP */ match = 1; } date += match; } /* mktime uses local timezone */ *timestamp = tm_to_time_t(&tm); if (*offset == -1) *offset = ((time_t)*timestamp - mktime(&tm)) / 60; if (*timestamp == -1) return -1; if (!tm_gmt) *timestamp -= *offset * 60; return 0; /* success */ }
/* Gr. strptime is crap for this; it doesn't have a way to require RFC2822 (i.e. English) day/month names, and it doesn't work correctly with %z. */ int parse_date(const char *date, char *result, int maxlen) { struct tm tm; int offset, tm_gmt; time_t then; memset(&tm, 0, sizeof(tm)); tm.tm_year = -1; tm.tm_mon = -1; tm.tm_mday = -1; tm.tm_isdst = -1; offset = -1; tm_gmt = 0; for (;;) { int match = 0; unsigned char c = *date; /* Stop at end of string or newline */ if (!c || c == '\n') break; if (isalpha(c)) match = match_alpha(date, &tm, &offset); else if (isdigit(c)) match = match_digit(date, &tm, &offset, &tm_gmt); else if ((c == '-' || c == '+') && isdigit(date[1])) match = match_tz(date, &offset); if (!match) { /* BAD CRAP */ match = 1; } date += match; } /* mktime uses local timezone */ then = tm_to_time_t(&tm); if (offset == -1) offset = (then - mktime(&tm)) / 60; if (then == -1) return -1; if (!tm_gmt) then -= offset * 60; return date_string(then, offset, result, maxlen); }
/* Gr. strptime is crap for this; it doesn't have a way to require RFC2822 (i.e. English) day/month names, and it doesn't work correctly with %z. */ int parse_date_basic(const char *date, timestamp_t *timestamp, int *offset) { struct tm tm; int tm_gmt; timestamp_t dummy_timestamp; int dummy_offset; if (!timestamp) timestamp = &dummy_timestamp; if (!offset) offset = &dummy_offset; memset(&tm, 0, sizeof(tm)); tm.tm_year = -1; tm.tm_mon = -1; tm.tm_mday = -1; tm.tm_isdst = -1; tm.tm_hour = -1; tm.tm_min = -1; tm.tm_sec = -1; *offset = -1; tm_gmt = 0; if (*date == '@' && !match_object_header_date(date + 1, timestamp, offset)) return 0; /* success */ for (;;) { int match = 0; unsigned char c = *date; /* Stop at end of string or newline */ if (!c || c == '\n') break; if (isalpha(c)) match = match_alpha(date, &tm, offset); else if (isdigit(c)) match = match_digit(date, &tm, offset, &tm_gmt); else if ((c == '-' || c == '+') && isdigit(date[1])) match = match_tz(date, offset); if (!match) { /* BAD CRAP */ match = 1; } date += match; } /* do not use mktime(), which uses local timezone, here */ *timestamp = tm_to_time_t(&tm); if (*timestamp == -1) return -1; if (*offset == -1) { time_t temp_time; /* gmtime_r() in match_digit() may have clobbered it */ tm.tm_isdst = -1; temp_time = mktime(&tm); if ((time_t)*timestamp > temp_time) { *offset = ((time_t)*timestamp - temp_time) / 60; } else { *offset = -(int)((temp_time - (time_t)*timestamp) / 60); } } if (!tm_gmt) *timestamp -= *offset * 60; return 0; /* success */ }
/* Gr. strptime is crap for this; it doesn't have a way to require RFC2822 (i.e. English) day/month names, and it doesn't work correctly with %z. */ int parse_date_basic(const char *date, struct timeval *tv, int *offset) { struct atm tm; int tm_gmt; int dummy_offset; if (!offset) offset = &dummy_offset; tm.tm_year = -1; tm.tm_mon = -1; tm.tm_mday = -1; tm.tm_isdst = -1; tm.tm_hour = -1; tm.tm_min = -1; tm.tm_sec = -1; tm.tm_usec = 0; *offset = -1; tm_gmt = 0; if (*date == '@' && !match_object_header_date(date + 1, tv, offset)) return 0; /* success */ for (;;) { int match = 0; unsigned char c = *date; /* Stop at end of string or newline */ if (!c || c == '\n') break; if (isalpha(c)) match = match_alpha(date, &tm, offset); else if (isdigit(c)) match = match_digit(date, &tm, offset, &tm_gmt); else if ((c == '-' || c == '+') && isdigit(date[1])) match = match_tz(date, offset); if (!match) { /* BAD CRAP */ match = 1; } date += match; } // mktime() is larger than struct atm, so it can clobber usec tv->tv_usec = tm.tm_usec; /* mktime uses local timezone */ tv->tv_sec = tm_to_time_t(&tm); if (*offset == -1) *offset = (((time_t)tv->tv_sec) - mktime((struct tm*)&tm)) / 60; if (tv->tv_sec == -1) return -1; if (!tm_gmt) tv->tv_sec -= *offset * 60; return 0; /* success */ }