IANA タイムゾーンIDとWindowsタイムゾーンIDの変換 (.NET 6)

このエントリは2021/10/26現在の情報に基づいています。将来の機能追加や変更に伴い、記載内容との乖離が発生する可能性があります(.NET 6は日本時間2021/11/09 GAしました。GA版で動作確認済みです)。

問い合わせ

以下のような問い合わせをもらった。

IANA Timezone IDとWindows Timezone IDを相互変換できる仕組みがあるか?具体的には、Asia/Tokyoを指定したら、Tokyo Standard Timeが出てくるような感じ。

もろにWindowsの世界ではあるが、調べてみた。

APIの有無

変換に使えるデータは以下のようにCLDRのwindowsZones.xmlにある。

windowsZones.xml
https://github.com/unicode-org/cldr/blob/main/common/supplemental/windowsZones.xml

.NET 5まで

この要求をズバリ満たすAPIは存在しないため、何らかの形で実装する必要がある。原始的なのは、上記ファイルを読み込んでおき、それを使うというものだが、いかんせんそれではパフォーマンスも出なければ通信が必要なのでレイテンシが大きくなりすぎる。そのため、3rd partyのTimeZoneConverterというNuGetパッケージを使うのが一番簡単そう。

TimeZoneConverter
https://github.com/mattjohnsonpint/TimeZoneConverter

.NET 6

そのあたりの対応が.NET 6では追加されており、以下のAPIが利用できる。

TimeZoneInfo.TryConvertIanaIdToWindowsId(String, String)
https://docs.microsoft.com/dotnet/api/system.timezoneinfo.tryconvertianaidtowindowsid?view=net-6.0
TimeZoneInfo.TryConvertWindowsIdToIanaId
https://docs.microsoft.com/ja-jp/dotnet/api/system.timezoneinfo.tryconvertwindowsidtoianaid?view=net-6.0

前者はIANA Timezone IDを入力引数として渡すと、対応するWindows Timezone IDが存在すれば戻り値としてtrue、出力引数としてWindows Timezone IDを、なければ戻り値としてfalse、出力引数としてnullを返す。後者はWindows Timezone ID(とリージョン)を入力引数として渡すと、対応するIANA Timezone IDが存在すれば戻り値としてtrue、出力引数としてIANA Timezone IDを、なければ戻り値としてfalse、出力引数としてnullを返す。

以下はAzure FunctionsでREST APIを作成したときのコードスニペット。コードはこちら

[Function("timezone-conversion")]
public static HttpResponseData tz2iana([HttpTrigger(AuthorizationLevel.Anonymous, "get")] HttpRequestData req,
    FunctionContext executionContext)
{
    ...
    string tz_win;
    string tz_iana;
    ...

    // IANA -> Windows
    if(TimeZoneInfo.TryConvertIanaIdToWindowsId(tz_iana, out tz_win)) {
        tz.description = $"Windows timezone mapped to IANA timezone {tz_iana} is {tz_win}.";
        tz.iana = tz_iana;
        tz.win = tz_win;
        return CreateResponse(req, tz, HttpStatusCode.OK);
    }

    // Windows -> IANA
    if(TimeZoneInfo.TryConvertWindowsIdToIanaId(tz_win, out tz_iana)) {
        tz.win = tz_win;
        tz.iana = tz_iana;
        tz.description = $"IANA timezone mapped to Windows timezone {tz_win} is {tz_iana}.";
        return CreateResponse(req, tz, HttpStatusCode.OK);
    }
    ...
}

public class TimeZoneData
{
    public TimeZoneData() {
        iana = null;
        win = null;
        description = null;
    }

    public string iana { get; set; }
    public string win { get; set; }
    public string description { get; set; }
}

例えば、TimeZoneInfo.TryConvertIanaIdToWindowsId は以下のような感じ。

string tz_iana = "Asia/Tokyo";
string tz_win;
TimeZoneInfo.TryConvertIanaIdToWindowsId(tz_iana, out tz_win); // tz_win = "Tokyo Standard Time"

対して、TimeZoneInfo.TryConvertWindowsIdToIanaId は以下のような感じ。

string tz_iana; 
string tz_win = "Tokyo Standard Time";
TimeZoneInfo.TryConvertWindowsIdToIanaId(tz_win, out tz_iana); // tz_iana = "Asia/Tokyo"

なお、TimeZoneInfo.TryConvertWindowsIdToIanaId には引数を3個(入力引数2個、出力引数1個)持つメソッドもあり、こちらだと以下のような感じ。

string tz_iana; 
string region = "Japan";
string tz_win = "Tokyo Standard Time";
TimeZoneInfo.TryConvertWindowsIdToIanaId(tz_win, region, out tz_iana); // tz_iana = "Asia/Tokyo"

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト /  変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト /  変更 )

%s と連携中