DateTime, DateTimeOffset, TimeSpan 및 TimeZoneInfo 중에서 선택

.NET 애플리케이션은 여러 가지 방법으로 날짜 및 시간 정보를 사용할 수 있습니다. 날짜 및 시간 정보의 일반적인 용도는 다음과 같습니다.

  • 시간 정보가 중요하지 않도록 날짜만 반영합니다.

  • 날짜 정보가 중요하지 않도록 시간만 반영합니다.

  • 특정 시간과 장소에 연결되지 않은 추상 날짜와 시간을 반영합니다(예: 국제 체인의 상점은 대부분 평일 오전 9:00에 열림).

  • .NET 외부의 원본에서 날짜 및 시간 정보를 검색하려면 일반적으로 날짜 및 시간 정보가 간단한 데이터 형식으로 저장됩니다.

  • 단일 시점을 고유하고 명확하게 식별합니다. 일부 애플리케이션에서는 호스트 시스템에서만 날짜와 시간이 명확해야 합니다. 다른 앱에서는 시스템 간에 명확하게 구분되어야 합니다(즉, 한 시스템에서 직렬화된 날짜는 전 세계 다른 시스템에서 의미 있는 역직렬화 및 사용 가능).

  • 여러 개의 관련 시간(예: 요청자의 현지 시간 및 서버의 웹 요청 수신 시간)을 보존합니다.

  • 날짜 및 시간 산술 연산을 수행합니다(단일 시점을 고유하고 명확하게 식별하는 결과를 제공할 수 있음).

.NET에는 날짜 및 TimeZoneInfo 시간과 함께 작동하는 애플리케이션을 빌드하는 데 사용할 수 있는 , 및 형식이 모두 포함TimeSpanDateTimeDateTimeOffset됩니다.

참고

이 항목에서는 해당 기능이 거의 전적으로 클래스에 TimeZoneInfo 통합되어 있기 때문에 설명하지 TimeZone 않습니다. 가능하면 클래스 대신 클래스를 TimeZone 사용합니다TimeZoneInfo.

DateTimeOffset 구조체

DateTimeOffset 구조체는 날짜 및 시간 값과 해당 값이 UTC와 다른 정도를 나타내는 오프셋을 나타냅니다. 따라서 값이 항상 단일 시점을 명확하게 식별합니다.

DateTimeOffset 형식에는 DateTime 형식의 모든 기능과 표준 시간대 인식 기능이 포함됩니다. 이렇게 하면 다음과 같은 애플리케이션에 적합합니다.

  • 단일 시점을 고유하고 명확하게 식별합니다. DateTimeOffset 형식을 통해 “now"의 의미를 명확하게 정의하고, 트랜잭션 시간을 기록하고, 시스템 또는 애플리케이션 이벤트의 시간을 기록하고, 파일을 만든 시간과 수정 시간을 기록할 수 있습니다.

  • 일반적인 날짜 및 시간 산술 연산을 수행합니다.

  • 시간이 두 개의 개별 값으로 저장되거나 한 구조체의 두 멤버로 저장된 경우 관련된 여러 시간을 보존합니다.

참고

DateTimeOffset 값의 사용은 DateTime 값의 사용보다 훨씬 더 일반적입니다. 따라서 애플리케이션 개발의 기본 날짜 및 시간 유형으로 간주 DateTimeOffset 합니다.

값은 DateTimeOffset 특정 표준 시간대에 연결되지 않지만 다양한 표준 시간대에서 비롯할 수 있습니다. 다음 예제에서는 여러 값(현지 태평양 표준시 포함)이 DateTimeOffset 속할 수 있는 표준 시간대를 나열합니다.

using System;
using System.Collections.ObjectModel;

public class TimeOffsets
{
   public static void Main()
   {
      DateTime thisDate = new DateTime(2007, 3, 10, 0, 0, 0);
      DateTime dstDate = new DateTime(2007, 6, 10, 0, 0, 0);
      DateTimeOffset thisTime;

      thisTime = new DateTimeOffset(dstDate, new TimeSpan(-7, 0, 0));
      ShowPossibleTimeZones(thisTime);

      thisTime = new DateTimeOffset(thisDate, new TimeSpan(-6, 0, 0));
      ShowPossibleTimeZones(thisTime);

      thisTime = new DateTimeOffset(thisDate, new TimeSpan(+1, 0, 0));
      ShowPossibleTimeZones(thisTime);
   }

   private static void ShowPossibleTimeZones(DateTimeOffset offsetTime)
   {
      TimeSpan offset = offsetTime.Offset;
      ReadOnlyCollection<TimeZoneInfo> timeZones;

      Console.WriteLine("{0} could belong to the following time zones:",
                        offsetTime.ToString());
      // Get all time zones defined on local system
      timeZones = TimeZoneInfo.GetSystemTimeZones();
      // Iterate time zones
      foreach (TimeZoneInfo timeZone in timeZones)
      {
         // Compare offset with offset for that date in that time zone
         if (timeZone.GetUtcOffset(offsetTime.DateTime).Equals(offset))
            Console.WriteLine("   {0}", timeZone.DisplayName);
      }
      Console.WriteLine();
   }
}
// This example displays the following output to the console:
//       6/10/2007 12:00:00 AM -07:00 could belong to the following time zones:
//          (GMT-07:00) Arizona
//          (GMT-08:00) Pacific Time (US & Canada)
//          (GMT-08:00) Tijuana, Baja California
//
//       3/10/2007 12:00:00 AM -06:00 could belong to the following time zones:
//          (GMT-06:00) Central America
//          (GMT-06:00) Central Time (US & Canada)
//          (GMT-06:00) Guadalajara, Mexico City, Monterrey - New
//          (GMT-06:00) Guadalajara, Mexico City, Monterrey - Old
//          (GMT-06:00) Saskatchewan
//
//       3/10/2007 12:00:00 AM +01:00 could belong to the following time zones:
//          (GMT+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna
//          (GMT+01:00) Belgrade, Bratislava, Budapest, Ljubljana, Prague
//          (GMT+01:00) Brussels, Copenhagen, Madrid, Paris
//          (GMT+01:00) Sarajevo, Skopje, Warsaw, Zagreb
//          (GMT+01:00) West Central Africa
Imports System.Collections.ObjectModel

Module TimeOffsets
    Public Sub Main()
        Dim thisTime As DateTimeOffset

        thisTime = New DateTimeOffset(#06/10/2007#, New TimeSpan(-7, 0, 0))
        ShowPossibleTimeZones(thisTime)

        thisTime = New DateTimeOffset(#03/10/2007#, New TimeSpan(-6, 0, 0))
        ShowPossibleTimeZones(thisTime)

        thisTime = New DateTimeOffset(#03/10/2007#, New TimeSpan(+1, 0, 0))
        ShowPossibleTimeZones(thisTime)
    End Sub

    Private Sub ShowPossibleTimeZones(offsetTime As DateTimeOffset)
        Dim offset As TimeSpan = offsetTime.Offset
        Dim timeZones As ReadOnlyCollection(Of TimeZoneInfo)

        Console.WriteLine("{0} could belong to the following time zones:", _
                          offsetTime.ToString())
        ' Get all time zones defined on local system
        timeZones = TimeZoneInfo.GetSystemTimeZones()
        ' Iterate time zones
        For Each timeZone As TimeZoneInfo In timeZones
            ' Compare offset with offset for that date in that time zone
            If timeZone.GetUtcOffset(offsetTime.DateTime).Equals(offset) Then
                Console.WriteLine("   {0}", timeZone.DisplayName)
            End If
        Next
        Console.WriteLine()
    End Sub
End Module
' This example displays the following output to the console:
'       6/10/2007 12:00:00 AM -07:00 could belong to the following time zones:
'          (GMT-07:00) Arizona
'          (GMT-08:00) Pacific Time (US & Canada)
'          (GMT-08:00) Tijuana, Baja California
'       
'       3/10/2007 12:00:00 AM -06:00 could belong to the following time zones:
'          (GMT-06:00) Central America
'          (GMT-06:00) Central Time (US & Canada)
'          (GMT-06:00) Guadalajara, Mexico City, Monterrey - New
'          (GMT-06:00) Guadalajara, Mexico City, Monterrey - Old
'          (GMT-06:00) Saskatchewan
'       
'       3/10/2007 12:00:00 AM +01:00 could belong to the following time zones:
'          (GMT+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna
'          (GMT+01:00) Belgrade, Bratislava, Budapest, Ljubljana, Prague
'          (GMT+01:00) Brussels, Copenhagen, Madrid, Paris
'          (GMT+01:00) Sarajevo, Skopje, Warsaw, Zagreb
'          (GMT+01:00) West Central Africa

출력은 이 예제의 각 날짜 및 시간 값이 세 개 이상의 표준 시간대에 속할 수 있음을 보여 줍니다. 2007년 6월 10일 값은 DateTimeOffset 날짜 및 시간 값이 일광 절약 시간을 나타내는 경우 UTC의 오프셋이 원래 표준 시간대의 기본 UTC 오프셋 또는 표시 이름에 있는 UTC의 오프셋과 반드시 일치하지는 않음을 보여 줍니다. 단일 DateTimeOffset 값은 표준 시간대와 긴밀하게 결합되지 않으므로 일광 절약 시간제로의 전환과 일광 절약 시간을 반영할 수 없습니다. 날짜 및 시간 산술 연산을 사용하여 값을 조작 DateTimeOffset 할 때 문제가 될 수 있습니다. 표준 시간대의 조정 규칙을 고려하는 방식으로 날짜 및 시간 산술 연산을 수행하는 방법에 대한 자세한 내용은 날짜 및 시간을 사용하여 산술 연산 수행을 참조하세요.

DateTime 구조체

DateTime 값은 특정 날짜와 시간을 정의합니다. 여기에는 해당 날짜와 시간이 속한 표준 시간대에 대한 제한된 정보를 제공하는 속성이 포함 Kind 됩니다. DateTimeKind 값은 Kind 속성에서 반환된 값은 DateTime 값이 현지 시간(DateTimeKind.Local), UTC(협정 세계시)(DateTimeKind.Utc) 또는 지정되지 않은 시간(DateTimeKind.Unspecified)인지를 나타냅니다.

DateTime 구조는 다음 특성 중 하나 이상의 애플리케이션에 적합합니다.

  • 날짜만 사용합니다.

  • 시간만 사용합니다.

  • 추상 날짜와 시간을 사용합니다.

  • 표준 시간대 정보가 없는 날짜 및 시간을 사용합니다.

  • UTC 날짜 및 시간만 사용합니다.

  • .NET 외부의 원본(예: SQL 데이터베이스)에서 날짜 및 시간 정보를 검색합니다. 일반적으로 이러한 소스는 DateTime 구조체와 호환되는 간단한 형식으로 날짜 및 시간 정보를 저장합니다.

  • 날짜 및 시간 산술 연산을 수행하지만 일반적인 결과와 관련이 있습니다. 예를 들어 특정 날짜와 시간에 6개월을 더하는 더하기 연산에서 일광 절약 시간제에 맞게 결과를 조정하는지 여부는 대체로 중요하지 않습니다.

특정 DateTime 값이 UTC를 나타내지 않는 경우 해당 날짜 및 시간 값은 대체로 모호하거나 이식성이 제한됩니다. 예를 들어 DateTime 값이 현지 시간을 나타내는 경우 현지 표준 시간대 내에서 이식할 수 있습니다(즉, 동일한 표준 시간대의 다른 시스템에서 값을 역직렬화하는 경우 해당 값이 여전히 단일 시점을 명확하게 식별함). 현지 표준 시간대 외부에서는 해당 DateTime 값이 여러 가지로 해석될 수 있습니다. 값의 Kind 속성이 DateTimeKind.Unspecified이면 이식성이 훨씬 감소합니다. 이제 동일한 표준 시간대 내에서 모호하며 처음 직렬화된 시스템에서도 모호할 수 있습니다. DateTime 값이 UTC를 나타내는 경우에만 값이 사용되는 시스템이나 표준 시간대에 관계없이 단일 시점을 명확하게 식별합니다.

중요

DateTime 데이터를 저장하거나 공유하는 경우 UTC를 사용해야 하며 DateTime 값의 Kind 속성을 DateTimeKind.Utc로 설정해야 합니다.

TimeSpan 구조체

TimeSpan 구조체는 시간 간격을 나타냅니다. 일반적으로 다음 두 가지 용도로 사용됩니다.

  • 두 개의 날짜 및 시간 값의 시간 간격을 반영합니다. 예를 들어 다른 값에서 DateTime 값을 빼면 TimeSpan 값이 반환됩니다.

  • 경과 시간을 측정합니다. 예를 들어 이 속성은 Stopwatch.Elapsed 경과된 시간을 측정하기 시작하는 메서드 중 Stopwatch 하나에 대한 호출 이후 경과된 시간 간격을 반영하는 값을 반환 TimeSpan 합니다.

값이 TimeSpan 특정 날짜에 대한 DateTime 참조 없이 시간을 반영하는 경우 값을 대체 값으로 사용할 수도 있습니다. 이 사용법은 날짜에 DateTime.TimeOfDay 대한 참조 없이 시간을 나타내는 값을 반환 TimeSpan 하는 속성 및 속성과 DateTimeOffset.TimeOfDay 유사합니다. 예를 들어 TimeSpan 구조체를 사용하여 매일 상점을 여는 시간 또는 닫는 시간을 반영하거나 정기 이벤트가 발생하는 시간을 나타낼 수 있습니다.

다음 예제에서는 상점을 여는 시간과 닫는 시간에 사용되는 StoreInfo 개체와 상점의 표준 시간대를 나타내는 TimeSpan 개체가 포함된 TimeZoneInfo 구조체를 정의합니다. 구조체에는 현지 표준 시간대에 있는 것으로 가정되는 사용자가 지정한 시간에 상점이 열려 있는지 여부를 나타내는 IsOpenNowIsOpenAt의 두 메서드도 포함됩니다.

using System;

public struct StoreInfo
{
   public String store;
   public TimeZoneInfo tz;
   public TimeSpan open;
   public TimeSpan close;

   public bool IsOpenNow()
   {
      return IsOpenAt(DateTime.Now.TimeOfDay);
   }

   public bool IsOpenAt(TimeSpan time)
   {
      TimeZoneInfo local = TimeZoneInfo.Local;
      TimeSpan offset = TimeZoneInfo.Local.BaseUtcOffset;

      // Is the store in the same time zone?
      if (tz.Equals(local)) {
         return time >= open & time <= close;
      }
      else {
         TimeSpan delta = TimeSpan.Zero;
         TimeSpan storeDelta = TimeSpan.Zero;

         // Is it daylight saving time in either time zone?
         if (local.IsDaylightSavingTime(DateTime.Now.Date + time))
            delta = local.GetAdjustmentRules()[local.GetAdjustmentRules().Length - 1].DaylightDelta;

         if (tz.IsDaylightSavingTime(TimeZoneInfo.ConvertTime(DateTime.Now.Date + time, local, tz)))
            storeDelta = tz.GetAdjustmentRules()[tz.GetAdjustmentRules().Length - 1].DaylightDelta;

         TimeSpan comparisonTime = time + (offset - tz.BaseUtcOffset).Negate() + (delta - storeDelta).Negate();
         return comparisonTime >= open & comparisonTime <= close;
      }
   }
}
Public Structure StoreInfo
    Dim store As String
    Dim tz As TimeZoneInfo
    Dim open As TimeSpan
    Dim close As TimeSpan

    Public Function IsOpenNow() As Boolean
        Return IsOpenAt(Date.Now.TimeOfDay)
    End Function

    Public Function IsOpenAt(time As TimeSpan) As Boolean
        Dim local As TimeZoneInfo = TimeZoneInfo.Local
        Dim offset As TimeSpan = TimeZoneInfo.Local.BaseUtcOffset

        ' Is the store in the same time zone?
        If tz.Equals(local) Then
            Return time >= open AndAlso time <= close
        Else
            Dim delta As TimeSpan = TimeSpan.Zero
            Dim storeDelta As TimeSpan = TimeSpan.Zero

            ' Is it daylight saving time in either time zone?
            If local.IsDaylightSavingTime(Date.Now.Date + time) Then
                delta = local.GetAdjustmentRules(local.GetAdjustmentRules().Length - 1).DaylightDelta
            End If
            If tz.IsDaylightSavingTime(TimeZoneInfo.ConvertTime(Date.Now.Date + time, local, tz))
                storeDelta = tz.GetAdjustmentRules(tz.GetAdjustmentRules().Length - 1).DaylightDelta
            End If
            Dim comparisonTime As TimeSpan = time + (offset - tz.BaseUtcOffset).Negate() + (delta - storeDelta).Negate
            Return (comparisonTime >= open AndAlso comparisonTime <= close)
        End If
    End Function
End Structure

StoreInfo 구조체는 클라이언트 코드에서 다음과 같이 사용될 수 있습니다.

public class Example
{
   public static void Main()
   {
      // Instantiate a StoreInfo object.
      var store103 = new StoreInfo();
      store103.store = "Store #103";
      store103.tz = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
      // Store opens at 8:00.
      store103.open = new TimeSpan(8, 0, 0);
      // Store closes at 9:30.
      store103.close = new TimeSpan(21, 30, 0);

      Console.WriteLine("Store is open now at {0}: {1}",
                        DateTime.Now.TimeOfDay, store103.IsOpenNow());
      TimeSpan[] times = { new TimeSpan(8, 0, 0), new TimeSpan(21, 0, 0),
                           new TimeSpan(4, 59, 0), new TimeSpan(18, 31, 0) };
      foreach (var time in times)
         Console.WriteLine("Store is open at {0}: {1}",
                           time, store103.IsOpenAt(time));
   }
}
// The example displays the following output:
//       Store is open now at 15:29:01.6129911: True
//       Store is open at 08:00:00: True
//       Store is open at 21:00:00: False
//       Store is open at 04:59:00: False
//       Store is open at 18:31:00: False
Module Example
    Public Sub Main()
        ' Instantiate a StoreInfo object.
        Dim store103 As New StoreInfo()
        store103.store = "Store #103"
        store103.tz = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time")
        ' Store opens at 8:00.
        store103.open = new TimeSpan(8, 0, 0)
        ' Store closes at 9:30.
        store103.close = new TimeSpan(21, 30, 0)

        Console.WriteLine("Store is open now at {0}: {1}",
                          Date.Now.TimeOfDay, store103.IsOpenNow())
        Dim times() As TimeSpan = {New TimeSpan(8, 0, 0),
                                    New TimeSpan(21, 0, 0),
                                    New TimeSpan(4, 59, 0),
                                    New TimeSpan(18, 31, 0)}
        For Each time In times
            Console.WriteLine("Store is open at {0}: {1}",
                              time, store103.IsOpenAt(time))
        Next
    End Sub
End Module
' The example displays the following output:
'       Store is open now at 15:29:01.6129911: True
'       Store is open at 08:00:00: True
'       Store is open at 21:00:00: False
'       Store is open at 04:59:00: False
'       Store is open at 18:31:00: False

TimeZoneInfo 클래스

TimeZoneInfo class represents any of the Earth's time zones, and enables the conversion of any date and time in one time zone to its equivalent in another time zone. TimeZoneInfo 클래스를 사용하면 모든 날짜 및 시간 값이 명확하게 단일 시점을 식별하도록 날짜 및 시간 작업을 할 수 있습니다. TimeZoneInfo 클래스는 확장도 가능합니다. Windows 시스템에 대해 제공되고 레지스트리에 정의된 표준 시간대 정보에 따라 달라지지만 사용자 지정 표준 시간대 생성을 지원합니다. 또한 표준 시간대 정보의 직렬화 및 역직렬화를 지원합니다.

TimeZoneInfo 클래스를 완전히 활용하기 위해 추가 개발 작업이 필요한 경우도 있습니다. 날짜 및 시간 값이 속한 표준 시간대와 긴밀하게 결합되지 않은 경우 추가 작업이 필요합니다. 애플리케이션에서 날짜와 시간을 연결된 표준 시간대와 연결하는 메커니즘을 제공하지 않는 한 특정 날짜 및 시간 값이 표준 시간대에서 분리되기 쉽습니다. 이 정보를 연결하는 한 가지 방법으로 날짜 및 시간 값, 그리고 연결되는 표준 시간대 개체를 둘 다 포함하는 클래스나 구조체를 정의합니다.

.NET에서 표준 시간대 지원을 활용하려면 해당 날짜 및 시간 개체가 인스턴스화될 때 날짜 및 시간 값이 속하는 표준 시간대를 알고 있어야 합니다. 표준 시간대는 특히 웹 또는 네트워크 앱에서 알 수 없는 경우가 많습니다.

추가 정보