.NET FrameworkでUNIX時間を扱う方法、またUNIX時間とDateTime型DateTimeOffset型を相互に変換する方法について。

.NET Framework 4.6以降

DateTimeOffset構造体のメソッドToUnixTimeSecondsおよびFromUnixTimeSecondsを使うことにより、DateTimeOffsetで表される時間とUNIX時間を相互に変換することができる。

using System;

class Sample {
  static void Main()
  {
    // DateTimeOffsetからUNIX時間への変換
    var dto = new DateTimeOffset(2009, 02, 13, 23, 31, 30, new TimeSpan(+00, 00, 00));

    Console.WriteLine(dto.ToUnixTimeSeconds());

    // 2038-01-19T03:14:07+00:00をUNIX時間に変換
    Console.WriteLine((new DateTimeOffset(2038, 01, 19, 03, 14, 07, new TimeSpan(+00, 00, 00))).ToUnixTimeSeconds());

    // 2038-01-19T12:14:07+09:00をUNIX時間に変換
    Console.WriteLine((new DateTimeOffset(2038, 01, 19, 12, 14, 07, new TimeSpan(+09, 00, 00))).ToUnixTimeSeconds());

    Console.WriteLine();



    // UNIX時間からDateTimeOffsetへの変換
    Console.WriteLine(DateTimeOffset.FromUnixTimeSeconds(1000000000L));

    // UNIX時間からローカル時間に変換
    Console.WriteLine(DateTimeOffset.FromUnixTimeSeconds(1000000000L).ToLocalTime());

    // 64ビット符号付き整数の最大値を変換
    Console.WriteLine(DateTimeOffset.FromUnixTimeSeconds((long)int.MaxValue));
    Console.WriteLine(DateTimeOffset.FromUnixTimeSeconds((long)int.MaxValue).ToLocalTime());
  }
}
Imports System

Class Sample
  Shared Sub Main()
    ' DateTimeOffsetからUNIX時間への変換
    Dim dto As New DateTimeOffset(2009, 02, 13, 23, 31, 30, New TimeSpan(+00, 00, 00))

    Console.WriteLine(dto.ToUnixTimeSeconds())

    ' 2038-01-19T03:14:07+00:00をUNIX時間に変換
    Console.WriteLine((New DateTimeOffset(2038, 01, 19, 03, 14, 07, New TimeSpan(+00, 00, 00))).ToUnixTimeSeconds())

    ' 2038-01-19T12:14:07+09:00をUNIX時間に変換
    Console.WriteLine((New DateTimeOffset(2038, 01, 19, 12, 14, 07, New TimeSpan(+09, 00, 00))).ToUnixTimeSeconds())

    Console.WriteLine()



    ' UNIX時間からDateTimeOffsetへの変換
    Console.WriteLine(DateTimeOffset.FromUnixTimeSeconds(1000000000L))

    ' UNIX時間からローカル時間に変換
    Console.WriteLine(DateTimeOffset.FromUnixTimeSeconds(1000000000L).ToLocalTime())

    ' 32ビット符号付き整数の最大値を変換
    Console.WriteLine(DateTimeOffset.FromUnixTimeSeconds(CLng(Integer.MaxValue)))
    Console.WriteLine(DateTimeOffset.FromUnixTimeSeconds(CLng(Integer.MaxValue)).ToLocalTime())
  End Sub
End Class
出力例
1234567890
2147483647
2147483647

2001/09/09 1:46:40 +00:00
2001/09/09 10:46:40 +09:00
2038/01/19 3:14:07 +00:00
2038/01/19 12:14:07 +09:00

FromUnixTimeSecondsメソッドは指定されたUNIX時間をUTC(世界協定時)と解釈する。 戻り値として返されるDateTimeOffsetのOffsetプロパティも+00:00となる。 このため、UNIX時間をローカル時間に変換したい場合は、FromUnixTimeSecondsメソッドで得られたDateTimeOffsetに対してToLocalTimeメソッドを呼び出すことによってローカル時間に変換する必要がある。

FromUnixTimeSecondsメソッドでは、64ビット整数で表されるUNIX時間を扱うことができる。 そのため2038年以降の日時を表すUNIX時間を扱うこともできるが、一方DateTimeOffsetで扱える範囲外の日時へ変換しようとした場合は例外ArgumentOutOfRangeExceptionがスローされる。 (DateTimeOffsetで扱える日時の最大値・最小値: 型の種類・サイズ・精度・値域 §.型のサイズ・精度と値域)

ミリ秒単位のUNIX時間を扱いたい場合は、ToUnixTimeMillisecondsおよびFromUnixTimeMillisecondsを使うことができる。

なおDateTime構造体にはこのようなUNIX時間との相互変換を行うメソッドは用意されていない。

.NET Framework 4.5以前

上記のようなメソッドが用意されないため、独自に変換処理を実装する必要がある。

変換方法と実装

UNIX時間は「unix epoch(UTCでの1970年1月1日 午前0時00分00秒)からの経過秒数」と定義される。 そのため、unix epochの日時を設定したDateTime型インスタンスを用意しておき、それに対してUNIX時間の値を秒数として足す(DateTime.AddSeconds)ことでDateTime型の値に変換することができる。

同様にDateTime型からUNIX時間を求めるには、DateTime.ToUniversalTimeメソッド時刻をUTCに変換してからunix epochとの差をとり(DateTime.Subtract)、その差を秒数として取得することでUNIX時間に変換することができる。

using System;

public class UnixTime {
  // unix epochをDateTimeで表した定数
  public readonly static DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);

  // DateTimeをUNIX時間に変換するメソッド
  public static long ToUnixTime(DateTime dateTime)
  {
    // 時刻をUTCに変換
    dateTime = dateTime.ToUniversalTime();

    // unix epochからの経過秒数を求める
    return (long)dateTime.Subtract(UnixEpoch).TotalSeconds;
  }

  // UNIX時間からDateTimeに変換するメソッド
  public static DateTime FromUnixTime(long unixTime)
  {
    // unix epochからunixTime秒だけ経過した時刻を求める
    return UnixEpoch.AddSeconds(unixTime);
  }

  static void Main()
  {
    Console.WriteLine(ToUnixTime(new DateTime(2009, 02, 13, 23, 31, 30, DateTimeKind.Utc)));
    Console.WriteLine(ToUnixTime(new DateTime(2038, 01, 19, 03, 14, 07, DateTimeKind.Utc)));
    Console.WriteLine(ToUnixTime(new DateTime(2038, 01, 19, 12, 14, 07, DateTimeKind.Local)));
    Console.WriteLine();

    Console.WriteLine(FromUnixTime(1000000000));
    Console.WriteLine(FromUnixTime(1000000000).ToLocalTime());
    Console.WriteLine(FromUnixTime(int.MaxValue));
    Console.WriteLine(FromUnixTime(int.MaxValue).ToLocalTime());
  }
}
Imports System

Public Module UnixTime

  ' unix epochをDateTimeで表した定数
  Public ReadOnly UnixEpoch As DateTime= new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)

  ' DateTimeをUNIX時間に変換するメソッド
  Public Function ToUnixTime(ByVal dateTime As DateTime) As Long

    ' 時刻をUTCに変換
    dateTime = dateTime.ToUniversalTime()

    ' unix epochからの経過秒数を求める
    Return CLng(dateTime.Subtract(UnixEpoch).TotalSeconds)

  End Function

  ' UNIX時間からDateTimeに変換するメソッド
  Public Function FromUnixTime(ByVal unixTime As Long) As DateTime

    ' unix epochからunixTime秒だけ経過した時刻を求める
    Return UnixEpoch.AddSeconds(unixTime)

  End Function

  Public Sub Main()

    Console.WriteLine(ToUnixTime(new DateTime(2009, 02, 13, 23, 31, 30, DateTimeKind.Utc)))
    Console.WriteLine(ToUnixTime(new DateTime(2038, 01, 19, 03, 14, 07, DateTimeKind.Utc)))
    Console.WriteLine(ToUnixTime(new DateTime(2038, 01, 19, 12, 14, 07, DateTimeKind.Local)))
    Console.WriteLine()

    Console.WriteLine(FromUnixTime(1000000000))
    Console.WriteLine(FromUnixTime(1000000000).ToLocalTime())
    Console.WriteLine(FromUnixTime(Integer.MaxValue))
    Console.WriteLine(FromUnixTime(Integer.MaxValue).ToLocalTime())

  End Sub

End Module
出力例
1234567890
2147483647
2147483647

2001/09/09 1:46:40
2001/09/09 10:46:40
2038/01/19 3:14:07
2038/01/19 12:14:07

上記サンプルの注意点など。

  1. 上記のFromUnixTimeメソッドは、UNIX時刻をUTCでのDateTimeとして返す点に注意。 結果をローカル時刻に変換するにはToLocalTimeメソッドを使う必要がある。 DateTimeとUTC・ローカル時刻の扱いについては時刻の種類・UTCとの時差・タイムゾーン間の変換を参照。
  2. DateTime型の最小値(System.DateTime.MinValue)は「0001年1月1日 午前0時00分00秒」となっている。 したがってDateTimeはunix epochよりも前の日時を表せるため、上記のToUnixTimeメソッドでDateTimeを変換すると負のUNIX時間を返す可能性がある点に注意。
  3. DateTime型の最大値(System.DateTime.MaxValue)は「9999年12月31日の 23時59分59秒9999999」となっている。 したがってこの日時より先の日時を表すUNIX時間を上記のFromUnixTimeメソッドでDateTimeに変換しようとすると、AddSecondsメソッドがArgumentOutOfRangeExceptionをスローする点に注意。
  4. DateTimeOffset型をUNIX時間に変換したい場合は、上記のメソッドにDateTimeOffset.UtcDateTimeプロパティの値を渡す。 このプロパティは、DateTimeOffsetが表す日時をUTCに変換したDateTimeとして返す。

参考情報

現在時刻

現在時刻 (現地時間)
現在時刻 (UTC)
UNIX時間

UNIX時間→現在時刻

UNIX時間
現地時間
-
UTC
-