I would like to somehow enumerate what time zones are available, and if possible, where my current time zone fits in this enumeration, with portable C++.
This is not possible (portably) in C++ prior to C++20. But it becomes trivial to do in C++20.
To start, in C++20 there is a type std::chrono::time_zone
which encapsulates a geographic area, and its rules for UTC offsets over the years. In general the rule is a function of the year. These time zones model the IANA time zone database.
Additionally there are std::chrono::time_zone_link
. A time_zone_link
is like a type alias, but for time_zone
. It is nothing more than an alternative name for another time_zone
. You can use the name of either a time_zone
, or a time_zone_link
in a call to std::chrono::locate_zone("continent/city")
which when successful, will return a time_zone const*
.
Below is code which iterates over all available time_zone
s, all available time_zone_link
s, and identifies your current time_zone
:
#include <chrono>
#include <iostream>
int
main()
{
using namespace std;
using namespace chrono;
cout << "All available time zones:\n";
for (auto& tz : get_tzdb().zones)
cout << tz.name() << '\n';
cout << "\nAll time zone links:\n";
for (auto& tz : get_tzdb().links)
cout << tz.name() << '\n';
cout << "\nMy time zone:\n";
cout << current_zone()->name() << '\n';
}
Head of output:
All available time zones:
Africa/Abidjan
Africa/Algiers
Africa/Bissau
Africa/Cairo
Africa/Casablanca
Africa/Ceuta
...
Any of these names can be used with locate_zone
and that can be used to translate between UTC and the local time, in either direction. For example:
#include <chrono>
#include <format>
#include <iostream>
int
main()
{
auto tz = std::chrono::locate_zone("Australia/Sydney");
auto now_utc = std::chrono::system_clock::now();
auto now_syd = std::chrono::zoned_time{tz, now_utc};
std::cout << std::format("{:%F %T %Z}", now_utc) << '\n';
std::cout << std::format("{:%F %T %Z}", now_syd) << '\n';
std::cout << std::format("{:%F %T %Z}", now_syd.get_sys_time()) << '\n';
}
Example output:
2023-09-27 04:00:11.408252895 UTC
2023-09-27 14:00:11.408252895 AEST
2023-09-27 04:00:11.408252895 UTC
Finally note that if this isn't the precision you're looking for, you can change to your desired precision in one place, and all of the subsequent arithmetic, conversions, and formatting automatically adjust:
#include <chrono>
#include <format>
#include <iostream>
int
main()
{
auto tz = std::chrono::locate_zone("Australia/Sydney");
auto now_utc = std::chrono::floor<std::chrono::seconds>
(std::chrono::system_clock::now());
auto now_syd = std::chrono::zoned_time{tz, now_utc};
std::cout << std::format("{:%F %T %Z}", now_utc) << '\n';
std::cout << std::format("{:%F %T %Z}", now_syd) << '\n';
std::cout << std::format("{:%F %T %Z}", now_syd.get_sys_time()) << '\n';
}
Example output:
2023-09-27 04:00:11 UTC
2023-09-27 14:00:11 AEST
2023-09-27 04:00:11 UTC