結論から言うと ICUが提供するucal_getWindowsTimeZoneID
を用いれば良い。ただし注意点として、tzdatabseのタイムゾーン名とWindowsが独自に持つタイムゾーン名は全射ではないので、やむにやまれず利用するくらいで。
#include <iostream>
#include <string>
#include <string_view>
#include <optional>
#include <icu.h>
std::pair<std::optional<std::u16string>, std::optional<UErrorCode>> getWindowsTimeZoneID(std::u16string_view inna_tz_name)
{
UErrorCode _{};
const auto ret = ucal_getWindowsTimeZoneID(inna_tz_name.data(), inna_tz_name.size(), nullptr, -1, &_);
std::u16string buf;
buf.resize(ret);
UErrorCode ec{};
if (const auto ret2 = ucal_getWindowsTimeZoneID(inna_tz_name.data(), inna_tz_name.size(), buf.data(), buf.size() + 1, &ec); U_FAILURE(ec) || ret2 == 0) {
return { std::nullopt, ec };
}
return { buf, std::nullopt };
}
int main()
{
std::wcout.imbue(std::locale());
for (auto&& name : { u"America/Los_Angeles", u"Asia/Tokyo"}) {
auto&& [val, stat] = getWindowsTimeZoneID(name);
if (val) {
std::wcout << reinterpret_cast<const wchar_t*>(val->c_str()) << std::endl;
}
if (stat) {
std::cerr << u_errorName(*stat) << std::endl;
}
}
}
以下の2つのライブラリとリンクが必要である。
- icuuc.lib
- icuin.lib
https://qiita.com/x768/items/ba4059986bea178c5133
Windowsのタイムゾーン名とtz databaseのタイムゾーン名の変換は、以下の表を使うとよいが、一対一の対応になっていないことに注意。
こうすると表を自分で持たなくてもなんとかなる。
注意点
ucal_getWindowsTimeZoneID
で最後の引数に渡しているエラーコード変数へのポインタについて注意しなければならない。どういうわけかこの関数はエラーコードをセットする前に中身を読み取っている様子があるのだ。
- 1回めの呼び出し時に油断して
nullptr
を渡すともれなくヌルポするからnullptr
を渡してはいけない - 初期化されているエラーコード変数へのポインタである必要がある。エラーコードをセットする前に中身を読み取っているということは、未初期化で渡すとUBになるということである
- 1回目と2回目で渡すエラーコード変数へのポインタは別のものでなければならない。