#include <chrono>
#include <format>
#include <fstream>
#include <cassert>
#include "filesystem_test_helper.h"
#include "assert_macros.h"
#include "concat_macros.h"
constexpr std::chrono::year first{1800};
constexpr std::chrono::year last{sizeof(time_t) == 8 ? 2100 : 2037};
struct sys_info : public std::chrono::sys_info {
sys_info(std::string_view name_, std::chrono::sys_info info) : std::chrono::sys_info{info}, name{name_} {}
std::string name;
};
template <>
struct std::formatter<sys_info, char> {
template <class ParseContext>
constexpr typename ParseContext::iterator parse(ParseContext& ctx) {
return ctx.begin();
}
template <class FormatContext>
typename FormatContext::iterator format(const sys_info& info, FormatContext& ctx) const {
using namespace std::literals::chrono_literals;
if (info.begin != std::chrono::sys_seconds::min())
ctx.advance_to(std::format_to(
ctx.out(),
"{} {:%a %b %e %H:%M:%S %Y} UT = {:%a %b %e %H:%M:%S %Y} {} isdst={:d} gmtoff={:%Q}\n",
info.name,
info.begin,
info.begin + info.offset,
info.abbrev,
info.save != 0s,
info.offset));
if (info.end != std::chrono::sys_seconds::max())
ctx.advance_to(std::format_to(
ctx.out(),
"{} {:%a %b %e %H:%M:%S %Y} UT = {:%a %b %e %H:%M:%S %Y} {} isdst={:d} gmtoff={:%Q}\n",
info.name,
info.end - 1s,
info.end - 1s + info.offset,
info.abbrev,
info.save != 0s,
info.offset));
return ctx.out();
}
};
void process(std::ostream& stream, const std::chrono::time_zone& zone) {
using namespace std::literals::chrono_literals;
constexpr auto begin = std::chrono::time_point_cast<std::chrono::seconds>(
static_cast<std::chrono::sys_days>(std::chrono::year_month_day{first, std::chrono::January, 1d}));
constexpr auto end = std::chrono::time_point_cast<std::chrono::seconds>(
static_cast<std::chrono::sys_days>(std::chrono::year_month_day{last, std::chrono::January, 1d}));
std::chrono::sys_seconds s = begin;
do {
sys_info info{zone.name(), zone.get_info(s)};
if (info.end >= end)
info.end = std::chrono::sys_seconds::max();
stream << std::format("{}", info);
s = info.end;
} while (s != std::chrono::sys_seconds::max());
}
int main(int, const char**) {
scoped_test_env env;
const std::string file = env.create_file("zdump.txt");
const std::chrono::tzdb& tzdb = std::chrono::get_tzdb();
for (const auto& zone : tzdb.zones) {
std::stringstream libcxx;
process(libcxx, zone);
int result = std::system(std::format("zdump -V -c{},{} {} > {}", first, last, zone.name(), file).c_str());
assert(result == 0);
std::stringstream zdump;
zdump << std::ifstream(file).rdbuf();
TEST_REQUIRE(
libcxx.str() == zdump.str(),
TEST_WRITE_CONCATENATED("\nTZ=", zone.name(), "\nlibc++\n", libcxx.str(), "|\n\nzdump\n", zdump.str(), "|"));
}
return 0;
}