151 lines
4.1 KiB
C++
151 lines
4.1 KiB
C++
#include "timezone_helper.h"
|
|
#include <cstdlib>
|
|
#include <ctime>
|
|
#include <iomanip>
|
|
#include <mutex>
|
|
#include <sstream>
|
|
|
|
namespace radiantwave::timezone {
|
|
|
|
namespace {
|
|
|
|
static std::mutex g_tz_mutex;
|
|
|
|
const std::vector<CountryTimeZones> G_COUNTRIES = {
|
|
{
|
|
"United States",
|
|
{
|
|
{"Eastern Time (New York, Miami)", "America/New_York"},
|
|
{"Central Time (Chicago, Dallas)", "America/Chicago"},
|
|
{"Mountain Time (Denver)", "America/Denver"},
|
|
{"Pacific Time (Los Angeles, Seattle)", "America/Los_Angeles"},
|
|
{"Alaska Time (Anchorage)", "America/Anchorage"},
|
|
{"Hawaii Time (Honolulu)", "Pacific/Honolulu"},
|
|
{"Arizona (No DST)", "America/Phoenix"},
|
|
{"Indiana (Indianapolis)", "America/Indiana/Indianapolis"}
|
|
}
|
|
},
|
|
{
|
|
"Canada",
|
|
{
|
|
{"Eastern Time (Toronto)", "America/Toronto"},
|
|
{"Central Time (Winnipeg)", "America/Winnipeg"},
|
|
{"Mountain Time (Edmonton)", "America/Edmonton"},
|
|
{"Pacific Time (Vancouver)", "America/Vancouver"},
|
|
{"Atlantic Time (Halifax)", "America/Halifax"},
|
|
{"Newfoundland Time (St. Johns)", "America/St_Johns"}
|
|
}
|
|
},
|
|
{
|
|
"United Kingdom & Ireland",
|
|
{
|
|
{"London / Dublin (GMT/BST)", "Europe/London"}
|
|
}
|
|
},
|
|
{
|
|
"Australia",
|
|
{
|
|
{"Eastern Time (Sydney, Melbourne)", "Australia/Sydney"},
|
|
{"Central Time (Adelaide)", "Australia/Adelaide"},
|
|
{"Western Time (Perth)", "Australia/Perth"},
|
|
{"Queensland (Brisbane)", "Australia/Brisbane"},
|
|
{"Northern Territory (Darwin)", "Australia/Darwin"}
|
|
}
|
|
},
|
|
{
|
|
"Europe (Mainland)",
|
|
{
|
|
{"Central European Time (Berlin, Paris, Rome)", "Europe/Berlin"},
|
|
{"Western European Time (Lisbon, Amsterdam)", "Europe/Paris"},
|
|
{"Eastern European Time (Athens, Helsinki)", "Europe/Helsinki"}
|
|
}
|
|
},
|
|
{
|
|
"Japan & East Asia",
|
|
{
|
|
{"Japan Standard Time (Tokyo)", "Asia/Tokyo"},
|
|
{"China Standard Time (Beijing, Shanghai)", "Asia/Shanghai"},
|
|
{"Hong Kong Time", "Asia/Hong_Kong"},
|
|
{"Korea Standard Time (Seoul)", "Asia/Seoul"},
|
|
{"Singapore Time", "Asia/Singapore"}
|
|
}
|
|
},
|
|
{
|
|
"India & South Asia",
|
|
{
|
|
{"India Standard Time (Kolkata, Mumbai)", "Asia/Kolkata"}
|
|
}
|
|
},
|
|
{
|
|
"Latin America",
|
|
{
|
|
{"Brazil (Sao Paulo)", "America/Sao_Paulo"},
|
|
{"Mexico (Mexico City)", "America/Mexico_City"},
|
|
{"Argentina (Buenos Aires)", "America/Argentina/Buenos_Aires"}
|
|
}
|
|
},
|
|
{
|
|
"Coordinated Universal Time",
|
|
{
|
|
{"UTC (Universal Time)", "UTC"}
|
|
}
|
|
}
|
|
};
|
|
|
|
} // anonymous namespace
|
|
|
|
const std::vector<CountryTimeZones>& getStandardTimeZones() {
|
|
return G_COUNTRIES;
|
|
}
|
|
|
|
std::string formatUtcToTimezone(time_t utc_time, const std::string& iana_code, const std::string& format) {
|
|
std::lock_guard<std::mutex> lock(g_tz_mutex);
|
|
|
|
const char* old_tz = std::getenv("TZ");
|
|
std::string old_tz_str = old_tz ? old_tz : "";
|
|
|
|
// Set target timezone temporarily
|
|
if (!iana_code.empty()) {
|
|
setenv("TZ", iana_code.c_str(), 1);
|
|
} else {
|
|
setenv("TZ", "UTC", 1);
|
|
}
|
|
tzset();
|
|
|
|
struct tm tm_buf;
|
|
#if defined(_WIN32)
|
|
localtime_s(&tm_buf, &utc_time);
|
|
#else
|
|
localtime_r(&utc_time, &tm_buf);
|
|
#endif
|
|
|
|
char buf[128];
|
|
std::strftime(buf, sizeof(buf), format.c_str(), &tm_buf);
|
|
|
|
// Restore original process TZ
|
|
if (!old_tz_str.empty()) {
|
|
setenv("TZ", old_tz_str.c_str(), 1);
|
|
} else {
|
|
unsetenv("TZ");
|
|
}
|
|
tzset();
|
|
|
|
return std::string(buf);
|
|
}
|
|
|
|
std::string getUtcTimestampIso() {
|
|
time_t now = std::time(nullptr);
|
|
struct tm gmt_buf;
|
|
#if defined(_WIN32)
|
|
gmtime_s(&gmt_buf, &now);
|
|
#else
|
|
gmtime_r(&now, &gmt_buf);
|
|
#endif
|
|
|
|
char buf[64];
|
|
std::strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S UTC", &gmt_buf);
|
|
return std::string(buf);
|
|
}
|
|
|
|
} // namespace radiantwave::timezone
|