銀の光と碧い空

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

.NET CoreでUTCのISO8601形式の時刻文字列から指定のタイムゾーンに変換する

例えば 2020-03-23T12:00:00.000Z というUTCでのISO8601形式の文字列をパースしたうえで、指定したタイムゾーンでの時間に変換したいとします。2020-03-23T12:00:00.000Zであれば、日本標準時(UTC+9)で2020年3月23日21時です。これは次のようなコードで処理できます。

var tokyoStandardTime = TimeZoneInfo.FindSystemTimeZoneById("Tokyo Standard Time");
var dateString = "2020-03-23T12:00:00.000Z";
var convertedDate = TimeZoneInfo.ConvertTime(DateTimeOffset.Parse(dateString), tokyoStandardTime)

.NET Coreの場合、タイムゾーンの情報を含んだ特定の日時はDateTimeOffset構造体を使うのがよいでしょう。

docs.microsoft.com

手元の環境(Windows 10およびmcr.microsoft.com/dotnet/core/sdk のLinuxコンテナ)では、ParseメソッドやTryParseメソッドでISO8601形式が処理できました。厳密に扱いたい場合はフォーマット文字列を指定するのがよいかもしれません。与えた文字列はUTCでの日時を表現しているので、この時点でDateTimeOffsetオブジェクトではUTCである情報がセットされています。これを異なるタイムゾーンでの同じ日時に変換するためにはTimeZoneInfo.ConvertTimeメソッドを使います。もしくは、TimeZoneInfoオブジェクトの生成を経由せずにConvertTimeBySystemTimeZoneIdメソッドも利用できます。

docs.microsoft.com

TimeZoneのID指定についてはWindowsとLinux環境で異なるので昨日の記事も参考にしてください。

tech.tanaka733.net

ちなみに次のようなコードは、環境により実行時例外になります。いくつか試したところ、WindowsやWSLのUbuntuでは動くのですが、mcr.microsoft.com/dotnet/core/sdk のLinuxコンテナではエラーになりました。

var tokyoStandardTime = TimeZoneInfo.FindSystemTimeZoneById("Asia/Tokyo");
var dateString = "2020-03-23T12:00:00.000Z";
var convertedDate = new DateTimeOffset(DateTime.Parse(dateString), tokyoStandardTime.BaseUtcOffset);
Exception has occurred: CLR/System.ArgumentException
型 'System.ArgumentException' のハンドルされていない例外が System.Private.CoreLib.dll で発生しました: 'The UTC Offset of the local dateTime parameter does not match the offset argument.'

素直にドキュメントでも使われているConvertTimeメソッドを使うのが無難なようです。