Code: Select all
#include
#include "./date/date.h"
#include "./date/tz.h"
using UtcTime = std::chrono::time_point;
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 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& tp) -> bool {
std::istringstream is(s);
is >> date::parse(fmt, tp);
return !is.fail();
};
date::sys_time 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(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
Mobile version