MRが楽しい

MRやVRについて学習したことを書き残す

DateTimeOffset型をDateTime型に変換する

本日は.NETの小ネタ枠です。
DateTimeOffset型をDateTime型に変換する方法についてです。

DateTime型とDateTimeOffset型

DateTime型は特定の時刻と世界協定時刻(UTC)またはローカル(Local)かの種別情報を保持します。
一方でDateTimeOffset型は特定のUTC時刻とタイムゾーンのオフセットを保持します。
learn.microsoft.com
learn.microsoft.com

DateTime型からDateTimeOffset型への変換

DateTimeOffsetコンストラクタまたは暗黙的な変換が可能です。
本変換ではDateTime型の種別に応じた適切なUTC時刻とオフセットがDateTimeOffsetに引き継がれます。

DateTime date1 = new DateTime(2010, 1, 1, 8, 0, 15, System.DateTimeKind.Local);
DateTimeOffset dateOffset1 = new DateTimeOffset(date1);

または

DateTime date1 = new DateTime(2010, 1, 1, 8, 0, 15, System.DateTimeKind.Local);
DateTimeOffset dateOffset1 = date1;

DateTimeOffset型からDateTime型への変換

DateTimeOffset.DateTimeプロパティが利用できますが、UTCかLocalかの種別情報が失われる点に注意が必要です。
変換後のDateTime型に種別情報を設定するにはDateTimeOffset.UtcDateTimeプロパティまたはDateTimeOffset.LocalDateTimeプロパティを利用します。
以下はDateTimeOffset型が保持しているオフセットからUTC時刻、Local時刻、それ以外を判定して変換を行う一例です。

DateTime ConvertFromDateTimeOffset(DateTimeOffset dateTime)
{
   if (dateTime.Offset.Equals(TimeSpan.Zero))
      return dateTime.UtcDateTime;
   else if (dateTime.Offset.Equals(TimeZoneInfo.Local.GetUtcOffset(dateTime.DateTime)))
      return DateTime.SpecifyKind(dateTime.DateTime, DateTimeKind.Local);
   else
      return dateTime.DateTime;
}

サンプルスクリプト

以下のDateTime型からDateTimeOffset型の変換と逆変換を行い、ログ出力するサンプルスクリプトを作成して結果を確認してみました。

void Main()
    {
        // 1. Local時刻とUTC時刻のDateTimeを作成
        System.DateTime date1 = new System.DateTime(2010, 1, 1, 8, 0, 15, System.DateTimeKind.Local);
        System.DateTime date2 = new System.DateTime(2010, 1, 1, 8, 0, 15, System.DateTimeKind.Utc);
        Debug.Log($"date1: {date1}, Kind: {date1.Kind}");
        Debug.Log($"date2: {date2}, Kind: {date2.Kind}");
        
        // 2. DateTime型をDateTimeOffset型に変換
        System.DateTimeOffset dateOffset1 = new System.DateTimeOffset(date1);
        System.DateTimeOffset dateOffset2 = new System.DateTimeOffset(date2);
        Debug.Log($"dateOffset1: {dateOffset1}");
        Debug.Log($"dateOffset2: {dateOffset2}");

        // 3. DateTimeOffset型をDateTime型に変換
        // DateTimeOffset.DateTimeプロパティを利用した場合、KindプロパティがUnspecifiedになり情報が失われる
        System.DateTime date3 = dateOffset1.DateTime;
        System.DateTime date4 = dateOffset2.DateTime;
        Debug.Log($"date3: {date3}, Kind: {date3.Kind}");
        Debug.Log($"date4: {date4}, Kind: {date4.Kind}");
        
        // 4. DateTimeOffset.UtcDateTimeまたはDateTimeOffset.LocalDateTimeプロパティを利用してKindプロパティを保持して変換する
        // 以下の処理ではDateTimeOffset.OffsetプロパティがTimeSpan.Zeroの場合はUTC時刻、
        // ローカル時刻のオフセットが一致すればLocal時刻、それ以外の場合はUnspecifiedとして変換している
        System.DateTime date5 = ConvertFromDateTimeOffset(dateOffset1);
        System.DateTime date6 = ConvertFromDateTimeOffset(dateOffset2);
        Debug.Log($"date5: {date5}, Kind: {date5.Kind}");
        Debug.Log($"date6: {date6}, Kind: {date6.Kind}");
    }

DateTime ConvertFromDateTimeOffset(DateTimeOffset dateTime)
    {
        if (dateTime.Offset.Equals(TimeSpan.Zero))
            return dateTime.UtcDateTime;
        else if (dateTime.Offset.Equals(TimeZoneInfo.Local.GetUtcOffset(dateTime.DateTime)))
            return DateTime.SpecifyKind(dateTime.DateTime, DateTimeKind.Local);
        else
            return dateTime.DateTime;
    }

出力結果は以下の通りです。

date1: 2010/01/01 8:00:15, Kind: Local
date2: 2010/01/01 8:00:15, Kind: Utc

dateOffset1: 2010/01/01 8:00:15 +09:00
dateOffset2: 2010/01/01 8:00:15 +00:00

date3: 2010/01/01 8:00:15, Kind: Unspecified
date4: 2010/01/01 8:00:15, Kind: Unspecified

date5: 2010/01/01 8:00:15, Kind: Local
date6: 2010/01/01 8:00:15, Kind: Utc

参考ページ

learn.microsoft.com