/* Scan an ISO timestamp and return an Epoch based timestamp. The only supported format is "yyyymmddThhmmss" delimited by white space, nul, a colon or a comma. Returns (time_t)(-1) for an invalid string. */ #if 0 /* Not yet used. */ static time_t isotime2epoch (const char *string) { int year, month, day, hour, minu, sec; struct tm tmbuf; if (!isotime_p (string)) return (time_t)(-1); year = atoi_4 (string); month = atoi_2 (string + 4); day = atoi_2 (string + 6); hour = atoi_2 (string + 9); minu = atoi_2 (string + 11); sec = atoi_2 (string + 13); /* Basic checks. */ if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 || hour > 23 || minu > 59 || sec > 61 ) return (time_t)(-1); memset (&tmbuf, 0, sizeof tmbuf); tmbuf.tm_sec = sec; tmbuf.tm_min = minu; tmbuf.tm_hour = hour; tmbuf.tm_mday = day; tmbuf.tm_mon = month-1; tmbuf.tm_year = year - 1900; tmbuf.tm_isdst = -1; return timegm (&tmbuf); }
/* Parse the string TIMESTAMP into a time_t. The string may either be seconds since Epoch or in the ISO 8601 format like "20390815T143012". Returns 0 for an empty string or seconds since Epoch. Leading spaces are skipped. If ENDP is not NULL, it will point to the next non-parsed character in TIMESTRING. */ time_t _gpgme_parse_timestamp (const char *timestamp, char **endp) { /* Need to skip leading spaces, because that is what strtoul does but not our ISO 8601 checking code. */ while (*timestamp && *timestamp== ' ') timestamp++; if (!*timestamp) return 0; if (strlen (timestamp) >= 15 && timestamp[8] == 'T') { struct tm buf; int year; year = atoi_4 (timestamp); if (year < 1900) return (time_t)(-1); if (endp) *endp = (char*)(timestamp + 15); /* Fixme: We would better use a configure test to see whether mktime can handle dates beyond 2038. */ if (sizeof (time_t) <= 4 && year >= 2038) return (time_t)2145914603; /* 2037-12-31 23:23:23 */ memset (&buf, 0, sizeof buf); buf.tm_year = year - 1900; buf.tm_mon = atoi_2 (timestamp+4) - 1; buf.tm_mday = atoi_2 (timestamp+6); buf.tm_hour = atoi_2 (timestamp+9); buf.tm_min = atoi_2 (timestamp+11); buf.tm_sec = atoi_2 (timestamp+13); #ifdef HAVE_W32_SYSTEM return _gpgme_timegm (&buf); #else #ifdef HAVE_TIMEGM return timegm (&buf); #else { time_t tim; putenv ("TZ=UTC"); tim = mktime (&buf); #ifdef __GNUC__ #warning fixme: we must somehow reset TZ here. It is not threadsafe anyway. #endif return tim; } #endif /* !HAVE_TIMEGM */ #endif /* !HAVE_W32_SYSTEM */ } else return (time_t)strtoul (timestamp, endp, 10); }
/* Parse the string TIMESTAMP into a time_t. The string may either be seconds since Epoch or in the ISO 8601 format like "20390815T143012". Returns 0 for an empty string or seconds since Epoch. Leading spaces are skipped. If ENDP is not NULL, it will point to the next non-parsed character in TIMESTRING. */ static time_t parse_timestamp (const char *timestamp, char **endp) { /* Need to skip leading spaces, because that is what strtoul does but not our ISO 8601 checking code. */ while (*timestamp && *timestamp== ' ') timestamp++; if (!*timestamp) return 0; if (strlen (timestamp) >= 15 && timestamp[8] == 'T') { struct tm buf; int year; year = atoi_4 (timestamp); if (year < 1900) return (time_t)(-1); /* Fixme: We would better use a configure test to see whether mktime can handle dates beyond 2038. */ if (sizeof (time_t) <= 4 && year >= 2038) return (time_t)2145914603; /* 2037-12-31 23:23:23 */ memset (&buf, 0, sizeof buf); buf.tm_year = year - 1900; buf.tm_mon = atoi_2 (timestamp+4) - 1; buf.tm_mday = atoi_2 (timestamp+6); buf.tm_hour = atoi_2 (timestamp+9); buf.tm_min = atoi_2 (timestamp+11); buf.tm_sec = atoi_2 (timestamp+13); if (endp) *endp = (char*)(timestamp + 15); #ifdef HAVE_TIMEGM return timegm (&buf); #else /* FIXME: Need to set TZ to UTC, but that is not thread-safe. */ return mktime (&buf); #endif } else return (time_t)strtoul (timestamp, endp, 10); }
/* Add SECONDS to ATIME. SECONDS may not be negative and is limited to about the equivalent of 62 years which should be more then enough for our purposes. Returns 0 on success. */ static int add_seconds_to_isotime (my_isotime_t atime, int nseconds) { int year, month, day, hour, minute, sec, ndays; unsigned long jd; if (check_isotime (atime)) return 1; if (nseconds < 0 || nseconds >= (0x7fffffff - 61) ) return 1; year = atoi_4 (atime+0); month = atoi_2 (atime+4); day = atoi_2 (atime+6); hour = atoi_2 (atime+9); minute= atoi_2 (atime+11); sec = atoi_2 (atime+13); /* The julian date functions don't support this. */ if (year < 1582 || (year == 1582 && month < 10) || (year == 1582 && month == 10 && day < 15)) return 1; sec += nseconds; minute += sec/60; sec %= 60; hour += minute/60; minute %= 60; ndays = hour/24; hour %= 24; jd = date2jd (year, month, day) + ndays; jd2date (jd, &year, &month, &day); if (year > 9999 || month > 12 || day > 31 || year < 0 || month < 1 || day < 1) return 1; snprintf (atime, ISOTIME_SIZE, "%04d%02d%02dT%02d%02d%02d", year, month, day, hour, minute, sec); return 0; }
/* Add NYEARS to ATIME. Returns 0 on success. */ static int add_years_to_isotime (my_isotime_t atime, int nyears) { int year, month, day, hour, minute, sec; unsigned long jd; if (check_isotime (atime)) return 1; if (nyears < 0 || nyears >= 9999 ) return 1; year = atoi_4 (atime+0); month = atoi_2 (atime+4); day = atoi_2 (atime+6); hour = atoi_2 (atime+9); minute= atoi_2 (atime+11); sec = atoi_2 (atime+13); /* The julian date functions don't support this. */ if (year < 1582 || (year == 1582 && month < 10) || (year == 1582 && month == 10 && day < 15)) return 1; jd = date2jd (year + nyears, month, day); jd2date (jd, &year, &month, &day); if (year > 9999 || month > 12 || day > 31 || year < 0 || month < 1 || day < 1) return 1; snprintf (atime, ISOTIME_SIZE, "%04d%02d%02dT%02d%02d%02d", year, month, day, hour, minute, sec); return 0; }