- struct tm Tm;
- setlocale (LC_ALL,"C");
- bool const invalid =
- // Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123
- (strptime(str, "%a, %d %b %Y %H:%M:%S %Z", &Tm) == NULL &&
- // Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036
- strptime(str, "%A, %d-%b-%y %H:%M:%S %Z", &Tm) == NULL &&
- // Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format
- strptime(str, "%a %b %d %H:%M:%S %Y", &Tm) == NULL);
- setlocale (LC_ALL,"");
- if (invalid == true)
+ struct tm t;
+ auto const &posix = std::locale("C.UTF-8");
+ auto const parse_time = [&](char const * const s, bool const has_timezone) {
+ std::istringstream ss(str);
+ ss.imbue(posix);
+ ss >> std::get_time(&t, s);
+ if (has_timezone && ss.fail() == false)
+ {
+ std::string timezone;
+ ss >> timezone;
+ if (timezone.empty())
+ return false;
+ if (timezone != "GMT" && timezone != "UTC" && timezone != "Z") // RFC 822
+ {
+ // numeric timezones as a should of RFC 1123 and generally preferred
+ try {
+ size_t pos;
+ auto const zone = std::stoi(timezone, &pos);
+ if (zone != 0 || pos != timezone.length())
+ return false;
+ } catch (...) {
+ return false;
+ }
+ }
+ }
+ t.tm_isdst = 0;
+ return ss.fail() == false;
+ };
+
+ bool const good =
+ // Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123
+ parse_time("%a, %d %b %Y %H:%M:%S", true) ||
+ // Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036
+ parse_time("%A, %d-%b-%y %H:%M:%S", true) ||
+ // Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format
+ parse_time("%c", false); // "%a %b %d %H:%M:%S %Y"
+ if (good == false)