C++ hinnant date lib - not parsing string to date under Linux, works on Windows

2 weeks ago 13
ARTICLE AD BOX

If I do:

#include <chrono> #include "./date/date.h" #include "./date/tz.h" using UtcTime = std::chrono::time_point<std::chrono::system_clock>; UtcTime xParseRfc822(const char* strTime) { std::string s = (strTime ? std::string(strTime) : std::string()); if (s.empty()) { return UtcTime(); } // Common timezone abbreviations -> minutes offset (RFC 822/1123 + a few practical ones) static const std::unordered_map<std::string, int> tz_abbr = { {"UT",0},{"UTC",0},{"GMT",0},{"Z",0}, {"WET",0},{"WEST",60},{"CET",60},{"CEST",120},{"EET",120},{"EEST",180}, {"MSK",180},{"MSD",240}, {"AST",-240},{"ADT",-180},{"EST",-300},{"EDT",-240},{"CST",-360},{"CDT",-300}, {"MST",-420},{"MDT",-360},{"PST",-480},{"PDT",-420}, {"AKST",-540},{"AKDT",-480},{"HST",-600},{"HDT",-540}, {"AEST",600},{"AEDT",660},{"ACST",570},{"ACDT",630},{"AWST",480}, {"IST",330},{"JST",540},{"KST",540},{"CST-PRC",480} }; auto to_upper = [](std::string v) { std::transform(v.begin(), v.end(), v.begin(), [](unsigned char c) { return std::toupper(c); }); return v; }; auto replace_range_with_offset = [&](size_t from, size_t to_exclusive, int mins) { char buf[16]; std::snprintf(buf, sizeof(buf), "%+03d%02d", mins / 60, std::abs(mins % 60)); s.replace(from, to_exclusive - from, buf); }; // Case 1: trailing "(TZ)" block -> convert to numeric offset if (!s.empty() && s.back() == ')') { size_t lp = s.find_last_of('('); if (lp != std::string::npos && lp + 2 < s.size() && s[s.size() - 1] == ')') { std::string inside = s.substr(lp + 1, s.size() - lp - 2); auto it = tz_abbr.find(to_upper(inside)); if (it != tz_abbr.end()) { // Remove the whole " (TZ)" or "(TZ)" block and append space + offset std::string prefix = s.substr(0, lp); char buf[8]; std::snprintf(buf, sizeof(buf), " %+03d%02d", it->second / 60, std::abs(it->second % 60)); s = prefix + buf; } } } else { // Case 2: trailing token "TZ" -> convert in place without trimming const char* ws = " \t\r\n"; size_t end = s.find_last_not_of(ws); if (end != std::string::npos) { size_t start_ws = s.find_last_of(ws, end); size_t tok_start = (start_ws == std::string::npos) ? 0 : start_ws + 1; std::string last = s.substr(tok_start, end - tok_start + 1); auto it = tz_abbr.find(to_upper(last)); if (it != tz_abbr.end()) { replace_range_with_offset(tok_start, end + 1, it->second); } } } auto try_parse = [&](const char* fmt, chronoExt::sys_time<std::chrono::nanoseconds>& tp) -> bool { std::istringstream is(s); is >> date::parse(fmt, tp); return !is.fail(); }; date::sys_time<std::chrono::nanoseconds> tp; bool parsed = false; // RFC 1123 / 2822 variants (numeric offset) if (!parsed && try_parse("%a, %d %b %Y %T %z", tp)) parsed = true; if (!parsed && try_parse("%a, %e %b %Y %T %z", tp)) parsed = true; if (!parsed && try_parse("%d %b %Y %T %z", tp)) parsed = true; // RFC 1123 with %Z (works if tzdb is available) if (!parsed && try_parse("%a, %d %b %Y %T %Z", tp)) parsed = true; if (!parsed && try_parse("%a, %e %b %Y %T %Z", tp)) parsed = true; // RFC 850 if (!parsed && try_parse("%A, %d-%b-%y %T %z", tp)) parsed = true; if (!parsed && try_parse("%A, %d-%b-%y %T %Z", tp)) parsed = true; // asctime() if (!parsed && try_parse("%a %b %e %T %Y", tp)) parsed = true; // Fallbacks (no seconds) if (!parsed && try_parse("%a, %d %b %Y %R %z", tp)) parsed = true; if (!parsed && try_parse("%a, %e %b %Y %R %z", tp)) parsed = true; // Date-only / ISO-like fallbacks if (!parsed && try_parse("%d %b %Y %z", tp)) parsed = true; if (!parsed && try_parse("%F %z", tp)) parsed = true; if (!parsed && try_parse("%F", tp)) parsed = true; if (!parsed) { return UtcTime(); } UtcTime tUtc = std::chrono::time_point_cast<std::chrono::system_clock::duration>(tp); return tUtc; } int main(int argc, char** argv) { auto t = "Thu, 08 Jan 2026 16:08:00 GMT"; auto utc = xParseRfc822(t);; std::cout << ut << std::endl; return 0; }

It works under Visual Studio 2022 (C++20). However, when I build the same code on Linux with g++ (GCC) 15.1.1 20250521, I got incorrect output.

Windows: 2026-01-08 16:08:00.0000000 Linux: 1970-01-01 00:00:00.000000000

I am using https://github.com/HowardHinnant/date/tree/master date library

Read Entire Article