銀の光と碧い空

クラウドなインフラとC#なアプリ開発の狭間にいるエンジニアの日々

.NET CoreでWindowsとLinuxでタイムゾーンを識別するID表記が異なるという話

最近、ASP.NET CoreでTimeZoneまわりのコード書いてて遭遇しました。以前このブログ読んだ記憶はあるのですが、すっかり忘れていました。そして、.NET Core 3でもそのままなんだなというのがわかりました。

devblogs.microsoft.com

.NET Coreで特定のTimeZoneを取得する場合、Windowsな人はこのようなコードを書くと思います。

System.TimeZoneInfo.FindSystemTimeZoneById("Tokyo Standard Time");

当然Windowsでは動くのですが、Unix系システムの上(多いと思われるのがLinuxコンテナ上)で動かすとこんなエラーが発生します。

Exception has occurred: CLR/System.TimeZoneNotFoundException
An unhandled exception of type 'System.TimeZoneNotFoundException' occurred in System.Private.CoreLib.dll: 'The time zone ID 'Tokyo Standard Time' was not found on the local computer.'

これはTimZoneを識別するIDがプラットフォームで異なるという問題によるものです。ブログにある通り、Windowsでは次のように管理されている一方

docs.microsoft.com

LinuxではIANAで公開されているもので管理されています。

www.iana.org

ようは、.NET Coreの内部で情報をもたずにOS(というべきか基本パッケージ・ライブラリとよぶべきか)の持っている情報へのプロキシとして動いている状況です。このあたりは日本の元号の扱いと似たような感じかもしれません。

さて、Linuxで動かすためには次のように書けばOKです。

System.TimeZoneInfo.FindSystemTimeZoneById("Asia/Tokyo");

ただし、当然のように、このコードはWindows上では動きません。そこで最初に紹介したブログではTimeZoneConverterというNuGetライブラリを紹介しています。

github.com

これを使えば次のどちらで書いても動作します。

TimeZoneConverter.TZConvert.GetTimeZoneInfo("Tokyo Standard Time");
TimeZoneConverter.TZConvert.GetTimeZoneInfo("Asia/Tokyo");

また、タイムゾーンの情報を扱う場合、最新の変更はWindowsであればWindows Update、Linuxであればtzdataパッケージの更新などで配布されます。そのため、クライアントアプリなど実行環境が管理できない場合、かならずしも実行結果が一致しない可能性があることに加え、TimeZoneConverterは.NET Core SDKのライブラリではないため別途更新が必要となります。TimeZoneConverterは、TimeZoneの情報そのものを格納しているわけではなく、プラットフォームで異なるIDのマッピングを管理しているだけのようですので、このライブラリを使う場合は、かならずライブラリの更新とOS側の更新が必要になると思われます。