// SPDX-FileCopyrightText: 2024 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only #pragma once #include #include #include #include #include #include #include #include inline std::string time_UTC(const std::chrono::time_point &input) { auto time_ms = std::chrono::duration_cast(input.time_since_epoch()).count(); char buf1[255], buf2[255]; time_t time = time_ms / (1000); std::tm tm_utc{}; #ifdef _WIN32 if (gmtime_s(&tm_utc, &time) != 0) #else if (gmtime_r(&time, &tm_utc) == nullptr) #endif throw std::runtime_error("gmtime failed"); strftime(buf1, sizeof(buf1), "%FT%T", &tm_utc); snprintf(buf2, sizeof(buf2), ".%03d", static_cast(time_ms % 1000)); return std::string(buf1) + std::string(buf2) + "Z"; } inline uint64_t parse_UTC_to_ms(const std::string& utc_string) { static const std::regex re( R"(^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.(\d{1,6}))?Z$)", std::regex::ECMAScript); std::smatch match; if (!std::regex_match(utc_string, match, re)) { throw std::runtime_error("Invalid UTC timestamp format: " + utc_string); } std::tm tm = {}; tm.tm_year = std::stoi(match[1]) - 1900; tm.tm_mon = std::stoi(match[2]) - 1; tm.tm_mday = std::stoi(match[3]); tm.tm_hour = std::stoi(match[4]); tm.tm_min = std::stoi(match[5]); tm.tm_sec = std::stoi(match[6]); int milliseconds = 0; if (match[7].matched) { std::string frac = match[7].str(); if (frac.size() > 3) { frac = frac.substr(0, 3); } else if (frac.size() < 3) { while (frac.size() < 3) frac.push_back('0'); } milliseconds = std::stoi(frac); } #ifdef _WIN32 time_t t = _mkgmtime(&tm); #else time_t t = timegm(&tm); #endif return static_cast(t) * 1000ULL + milliseconds; } inline std::string utc_to_local_human_readable(const std::string& utc_string) { using namespace std::chrono; try { uint64_t ms_since_epoch = parse_UTC_to_ms(utc_string); auto tp = system_clock::time_point(milliseconds(ms_since_epoch)); time_t t = system_clock::to_time_t(tp); std::tm tm_local{}; #ifdef _WIN32 if (localtime_s(&tm_local, &t) != 0) #else if (localtime_r(&t, &tm_local) == nullptr) #endif return ""; static const char* months[] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; std::ostringstream out; out << months[tm_local.tm_mon] << " " << std::setw(2) << std::setfill('0') << tm_local.tm_mday << ", " << (tm_local.tm_year + 1900) << " " << std::setw(2) << std::setfill('0') << tm_local.tm_hour << ":" << std::setw(2) << std::setfill('0') << tm_local.tm_min; return out.str(); } catch (...) { return ""; } }