표준 시간대 간에 시간 변환

날짜 및 시간을 사용하는 애플리케이션에서 표준 시간대 간의 차이를 처리하는 것이 더욱 중요해지고 있습니다. 애플리케이션은 더 이상 모든 시간이 DateTime 구조에서 사용 가능한 시간인 로컬 시간으로 표현될 수 있다고 가정할 수 없습니다. 예를 들어 동아시아 지역 고객에게는 미국 동부 지역의 현재 시간을 표시하는 웹 페이지의 신뢰성이 떨어집니다. 이 문서에서는 시간을 한 표준 시간대로 변환하고 표준 시간대 인식이 제한된 DateTimeOffset 값을 변환하는 방법을 설명합니다.

UTC로 변환

UTC(협정 세계시)는 고정밀 원자 시간 표준입니다. 전세계의 표준 시간대가 UTC의 양 또는 음 오프셋으로 표시됩니다. 따라서 UTC는 시간대가 없는 시간 또는 시간대 중립적인 시간을 제공합니다. 컴퓨터 간에 날짜 및 시간의 이식성이 중요한 경우 UTC를 사용하는 것이 좋습니다. (날짜 및 시간 사용에 대한 자세한 내용 및 기타 모범 사례는 .NET Framework에서 DateTime을 사용한 최선의 코딩 방법을 참조하세요.) 개별 표준 시간대를 UTC로 변환하면 시간을 보다 쉽게 비교할 수 있습니다.

참고 항목

또한 DateTimeOffset 구조를 직렬화하여 단일 시점을 명확하게 나타낼 수도 있습니다. DateTimeOffset 개체는 UTC로부터의 오프셋과 함께 날짜 및 시간 값을 저장하므로 항상 UTC를 기준으로 특정 시점을 나타냅니다.

시간을 UTC로 변환하는 가장 쉬운 방법은 static(Visual Basic의 경우 Shared) TimeZoneInfo.ConvertTimeToUtc(DateTime) 메서드를 호출하는 것입니다. 이 메서드에서 수행되는 정확한 변환은 다음 표에서 보여 주듯이 dateTime 매개 변수의 Kind 속성 값에 따라 다릅니다.

DateTime.Kind 전환
DateTimeKind.Local 현지 시간을 UTC로 변환합니다.
DateTimeKind.Unspecified dateTime 매개 변수가 현지 시간인 것으로 가정하고 현지 시간을 UTC로 변환합니다.
DateTimeKind.Utc 변경하지 않은 dateTime 매개 변수를 반환합니다.

다음 코드에서는 현재 현지 시간을 UTC로 변환하고 그 결과를 콘솔에 표시합니다.

DateTime dateNow = DateTime.Now;
Console.WriteLine($"The date and time are {TimeZoneInfo.ConvertTimeToUtc(dateNow)} UTC.");
Dim dateNow As Date = Date.Now
Console.WriteLine("The date and time are {0} UTC.", _
                  TimeZoneInfo.ConvertTimeToUtc(dateNow))

날짜 및 시간 값이 로컬 시간이나 UTC를 나타내지 않으면 ToUniversalTime 메서드가 잘못된 결과를 반환할 가능성이 높습니다. 그러나 TimeZoneInfo.ConvertTimeToUtc 메서드를 사용하여 지정된 표준 시간대의 날짜 및 시간을 변환할 수 있습니다. 대상 표준 시간대를 나타내는 TimeZoneInfo 개체 검색에 대한 자세한 내용은 로컬 시스템에 정의된 표준 시간대 찾기를 참조하세요. 다음 코드는 TimeZoneInfo.ConvertTimeToUtc 메서드를 사용하여 동부 표준시를 UTC로 변환합니다.

DateTime easternTime = new DateTime(2007, 01, 02, 12, 16, 00);
string easternZoneId = "Eastern Standard Time";
try
{
    TimeZoneInfo easternZone = TimeZoneInfo.FindSystemTimeZoneById(easternZoneId);
    Console.WriteLine($"The date and time are {TimeZoneInfo.ConvertTimeToUtc(easternTime, easternZone)} UTC.");
}
catch (TimeZoneNotFoundException)
{
    Console.WriteLine($"Unable to find the {easternZoneId} zone in the registry.");
}
catch (InvalidTimeZoneException)
{
    Console.WriteLine($"Registry data on the {easternZoneId} zone has been corrupted.");
}
Dim easternTime As New Date(2007, 01, 02, 12, 16, 00)
Dim easternZoneId As String = "Eastern Standard Time"
Try
    Dim easternZone As TimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(easternZoneId)
    Console.WriteLine("The date and time are {0} UTC.", _
                      TimeZoneInfo.ConvertTimeToUtc(easternTime, easternZone))
Catch e As TimeZoneNotFoundException
    Console.WriteLine("Unable to find the {0} zone in the registry.", _
                      easternZoneId)
Catch e As InvalidTimeZoneException
    Console.WriteLine("Registry data on the {0} zone has been corrupted.", _
                      easternZoneId)
End Try

DateTime 개체의 Kind 속성과 표준 시간대가 일치하지 않으면 TimeZoneInfo.ConvertTimeToUtc 메서드는 ArgumentException을 throw합니다. Kind 속성이 DateTimeKind.Local이지만 TimeZoneInfo 개체가 로컬 표준 시간대를 나타내지 않거나, Kind 속성이 DateTimeKind.Utc이지만 TimeZoneInfo 개체가 TimeZoneInfo.Utc와 같지 않은 경우 불일치가 발생합니다.

이러한 메서드는 모두 DateTime 값을 매개 변수로 사용하고 DateTime 값을 반환합니다. DateTimeOffset 값의 경우 DateTimeOffset 구조에는 현재 인스턴스의 날짜와 시간을 UTC로 변환하는 ToUniversalTime 인스턴스 메서드가 있습니다. 다음 예에서는 ToUniversalTime 메서드를 호출하여 로컬 시간과 기타 여러 시간을 UTC로 변환합니다.

DateTimeOffset localTime, otherTime, universalTime;

// Define local time in local time zone
localTime = new DateTimeOffset(new DateTime(2007, 6, 15, 12, 0, 0));
Console.WriteLine("Local time: {0}", localTime);
Console.WriteLine();

// Convert local time to offset 0 and assign to otherTime
otherTime = localTime.ToOffset(TimeSpan.Zero);
Console.WriteLine("Other time: {0}", otherTime);
Console.WriteLine("{0} = {1}: {2}",
                  localTime, otherTime,
                  localTime.Equals(otherTime));
Console.WriteLine("{0} exactly equals {1}: {2}",
                  localTime, otherTime,
                  localTime.EqualsExact(otherTime));
Console.WriteLine();

// Convert other time to UTC
universalTime = localTime.ToUniversalTime();
Console.WriteLine("Universal time: {0}", universalTime);
Console.WriteLine("{0} = {1}: {2}",
                  otherTime, universalTime,
                  universalTime.Equals(otherTime));
Console.WriteLine("{0} exactly equals {1}: {2}",
                  otherTime, universalTime,
                  universalTime.EqualsExact(otherTime));
Console.WriteLine();
// The example produces the following output to the console:
//    Local time: 6/15/2007 12:00:00 PM -07:00
//
//    Other time: 6/15/2007 7:00:00 PM +00:00
//    6/15/2007 12:00:00 PM -07:00 = 6/15/2007 7:00:00 PM +00:00: True
//    6/15/2007 12:00:00 PM -07:00 exactly equals 6/15/2007 7:00:00 PM +00:00: False
//
//    Universal time: 6/15/2007 7:00:00 PM +00:00
//    6/15/2007 7:00:00 PM +00:00 = 6/15/2007 7:00:00 PM +00:00: True
//    6/15/2007 7:00:00 PM +00:00 exactly equals 6/15/2007 7:00:00 PM +00:00: True
Dim localTime, otherTime, universalTime As DateTimeOffset

' Define local time in local time zone
localTime = New DateTimeOffset(#6/15/2007 12:00:00PM#)
Console.WriteLine("Local time: {0}", localTime)
Console.WriteLine()

' Convert local time to offset 0 and assign to otherTime
otherTime = localTime.ToOffset(TimeSpan.Zero)
Console.WriteLine("Other time: {0}", otherTime)
Console.WriteLine("{0} = {1}: {2}", _
                  localTime, otherTime, _
                  localTime.Equals(otherTime))
Console.WriteLine("{0} exactly equals {1}: {2}", _
                  localTime, otherTime, _
                  localTime.EqualsExact(otherTime))
Console.WriteLine()

' Convert other time to UTC
universalTime = localTime.ToUniversalTime()
Console.WriteLine("Universal time: {0}", universalTime)
Console.WriteLine("{0} = {1}: {2}", _
                  otherTime, universalTime, _
                  universalTime.Equals(otherTime))
Console.WriteLine("{0} exactly equals {1}: {2}", _
                  otherTime, universalTime, _
                  universalTime.EqualsExact(otherTime))
Console.WriteLine()
' The example produces the following output to the console:
'    Local time: 6/15/2007 12:00:00 PM -07:00
'    
'    Other time: 6/15/2007 7:00:00 PM +00:00
'    6/15/2007 12:00:00 PM -07:00 = 6/15/2007 7:00:00 PM +00:00: True
'    6/15/2007 12:00:00 PM -07:00 exactly equals 6/15/2007 7:00:00 PM +00:00: False
'    
'    Universal time: 6/15/2007 7:00:00 PM +00:00
'    6/15/2007 7:00:00 PM +00:00 = 6/15/2007 7:00:00 PM +00:00: True
'    6/15/2007 7:00:00 PM +00:00 exactly equals 6/15/2007 7:00:00 PM +00:00: True   

UTC를 지정한 표준 시간대로 변환

UTC를 현지 시간으로 변환하려면 다음에 나오는 UTC를 현지 시간으로 변환 섹션을 참조하세요. UTC를 지정한 표준 시간대의 시간으로 변환하려면 ConvertTimeFromUtc 메서드를 호출합니다. 메서드는

  • 변환할 UTC. 이는 Kind 속성이 Unspecified 또는 Utc로 설정된 DateTime 값이어야 합니다.

  • UTC를 변환한 값이 속하게 될 표준 시간대

다음 코드는 UTC를 중부 표준시로 변환합니다.

DateTime timeUtc = DateTime.UtcNow;
try
{
    TimeZoneInfo cstZone = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
    DateTime cstTime = TimeZoneInfo.ConvertTimeFromUtc(timeUtc, cstZone);
    Console.WriteLine("The date and time are {0} {1}.",
                      cstTime,
                      cstZone.IsDaylightSavingTime(cstTime) ?
                              cstZone.DaylightName : cstZone.StandardName);
}
catch (TimeZoneNotFoundException)
{
    Console.WriteLine("The registry does not define the Central Standard Time zone.");
}
catch (InvalidTimeZoneException)
{
    Console.WriteLine("Registry data on the Central Standard Time zone has been corrupted.");
}
Dim timeUtc As Date = Date.UtcNow
Try
    Dim cstZone As TimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time")
    Dim cstTime As Date = TimeZoneInfo.ConvertTimeFromUtc(timeUtc, cstZone)
    Console.WriteLine("The date and time are {0} {1}.", _
                      cstTime, _
                      IIf(cstZone.IsDaylightSavingTime(cstTime), _
                          cstZone.DaylightName, cstZone.StandardName))
Catch e As TimeZoneNotFoundException
    Console.WriteLine("The registry does not define the Central Standard Time zone.")
Catch e As InvalidTimeZoneException
    Console.WriteLine("Registry data on the Central Standard Time zone has been corrupted.")
End Try

UTC를 현지 시간으로 변환

UTC를 로컬 시간으로 변환하려면 시간을 변환하려는 DateTime 개체의 ToLocalTime 메서드를 호출합니다. 이 메서드의 정확한 동작은 다음 표에서 보여 주듯이 개체의 Kind 속성 값에 따라 다릅니다.

DateTime.Kind 전환
DateTimeKind.Local 변경되지 않은 DateTime 값을 반환합니다.
DateTimeKind.Unspecified DateTime 값이 UTC라고 가정하고 UTC를 로컬 시간으로 변환합니다.
DateTimeKind.Utc DateTime 값을 로컬 시간으로 변환합니다.

참고 항목

TimeZone.ToLocalTime 메서드는 DateTime.ToLocalTime 메서드와 똑같이 동작합니다. 변환하려면 날짜 및 시간 값인 단일 매개 변수가 필요합니다.

static(Visual Basic의 경우 Shared) TimeZoneInfo.ConvertTime 메서드를 사용하여 지정된 표준 시간대의 시간을 로컬 시간으로 변환할 수도 있습니다. 이 기술은 다음 섹션에서 설명됩니다.

두 표준 시간대 간 변환

TimeZoneInfo 클래스의 다음 두 가지 static(Visual Basic의 경우 Shared) 메서드 중 하나를 사용하여 두 표준 시간대 간에 변환할 수 있습니다.

  • ConvertTime

    이 메서드의 매개 변수는 변환할 날짜 및 시간 값, 날짜 및 시간 값의 표준 시간대를 나타내는 TimeZoneInfo 개체, 날짜 및 시간 값을 변환할 표준 시간대를 나타내는 TimeZoneInfo 개체입니다.

  • ConvertTimeBySystemTimeZoneId

    이 메서드의 매개 변수는 변환할 날짜 및 시간 값, 날짜 및 시간 값의 표준 시간대 식별자, 날짜 및 시간 값을 변환할 표준 시간대의 식별자입니다.

두 방법 모두 변환할 날짜 및 시간 값의 Kind 속성과 해당 표준 시간대를 나타내는 TimeZoneInfo 개체 또는 표준 시간대 식별자가 서로 일치해야 합니다. 그렇지 않으면 ArgumentException이 throw됩니다. 예를 들어, 날짜 및 시간 값의 Kind 속성이 DateTimeKind.Local인 경우 메서드에 매개 변수로 전달된 TimeZoneInfo 개체가 TimeZoneInfo.Local과 같지 않으면 예외가 throw됩니다. 메서드에 매개 변수로 전달된 식별자가 TimeZoneInfo.Local.Id와 같지 않은 경우에도 예외가 throw됩니다.

다음 예에서는 ConvertTime 메서드를 사용하여 하와이 표준시를 로컬 시간으로 변환합니다.

DateTime hwTime = new DateTime(2007, 02, 01, 08, 00, 00);
try
{
    TimeZoneInfo hwZone = TimeZoneInfo.FindSystemTimeZoneById("Hawaiian Standard Time");
    Console.WriteLine("{0} {1} is {2} local time.",
            hwTime,
            hwZone.IsDaylightSavingTime(hwTime) ? hwZone.DaylightName : hwZone.StandardName,
            TimeZoneInfo.ConvertTime(hwTime, hwZone, TimeZoneInfo.Local));
}
catch (TimeZoneNotFoundException)
{
    Console.WriteLine("The registry does not define the Hawaiian Standard Time zone.");
}
catch (InvalidTimeZoneException)
{
    Console.WriteLine("Registry data on the Hawaiian Standard Time zone has been corrupted.");
}
Dim hwTime As Date = #2/01/2007 8:00:00 AM#
Try
    Dim hwZone As TimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Hawaiian Standard Time")
    Console.WriteLine("{0} {1} is {2} local time.", _
                      hwTime, _
                      IIf(hwZone.IsDaylightSavingTime(hwTime), hwZone.DaylightName, hwZone.StandardName), _
                      TimeZoneInfo.ConvertTime(hwTime, hwZone, TimeZoneInfo.Local))
Catch e As TimeZoneNotFoundException
    Console.WriteLine("The registry does not define the Hawaiian Standard Time zone.")
Catch e As InvalidTimeZoneException
    Console.WriteLine("Registry data on the Hawaiian Standard Time zone has been corrupted.")
End Try

DateTimeOffset 값 변환

DateTimeOffset 개체가 나타내는 날짜 및 시간 값은 개체가 인스턴스화될 때 해당 표준 시간대에서 연결이 해제되므로 표준 시간대를 완전히 인식하지 못합니다. 그러나 많은 경우에는 애플리케이션에서 특정 표준 시간대의 시간이 아니라 단순히 서로 다른 UTC 오프셋 두 개를 기준으로 날짜 및 시간을 변환하면 됩니다. 이 변환을 수행하려면 현재 인스턴스의 ToOffset 메서드를 호출하면 됩니다. 메서드의 단일 매개 변수는 메서드가 반환할 새 날짜 및 시간 값의 오프셋입니다.

예를 들어 사용자가 웹 페이지에서 요청한 날짜 및 시간이 알려져 있고 이 값이 MM/dd/yyyy hh:mm:ss zzzz 형식의 문자열로 serialize된 경우 뒤따르는 ReturnTimeOnServer 메서드에서 이 날짜 및 시간 값을 웹 서버의 날짜 및 시간 값으로 변환합니다.

public DateTimeOffset ReturnTimeOnServer(string clientString)
{
   string format = @"M/d/yyyy H:m:s zzz";
   TimeSpan serverOffset = TimeZoneInfo.Local.GetUtcOffset(DateTimeOffset.Now);

   try
   {
      DateTimeOffset clientTime = DateTimeOffset.ParseExact(clientString, format, CultureInfo.InvariantCulture);
      DateTimeOffset serverTime = clientTime.ToOffset(serverOffset);
      return serverTime;
   }
   catch (FormatException)
   {
      return DateTimeOffset.MinValue;
   }
}
Public Function ReturnTimeOnServer(clientString As String) As DateTimeOffset
    Dim format As String = "M/d/yyyy H:m:s zzz"
    Dim serverOffset As TimeSpan = TimeZoneInfo.Local.GetUtcOffset(DateTimeOffset.Now)

    Try
        Dim clientTime As DateTimeOffset = DateTimeOffset.ParseExact(clientString, format, CultureInfo.InvariantCulture)
        Dim serverTime As DateTimeOffset = clientTime.ToOffset(serverOffset)
        Return serverTime
    Catch e As FormatException
        Return DateTimeOffset.MinValue
    End Try
End Function

메서드가 UTC보다 5시간 빠른 표준 시간대의 날짜 및 시간을 나타내는 "9/1/2007 5:32:07 -05:00" 문자열을 전달하는 경우 미국에 있는 서버는 "9/1/2007 3:32:07 AM -07:00"을 반환합니다. 보여 줍니다.

TimeZoneInfo 클래스에는 ToOffset(TimeSpan) 값으로 표준 시간대 변환을 수행하는 TimeZoneInfo.ConvertTime(DateTimeOffset, TimeZoneInfo) 메서드의 오버로드도 포함되어 있습니다. 메서드의 매개 변수는 DateTimeOffset 값과 시간이 변환될 표준 시간대에 대한 참조입니다. 메서드 호출은 DateTimeOffset 값을 반환합니다. 예를 들어, 이전 예의 ReturnTimeOnServer 메서드를 다음과 같이 다시 작성하여 ConvertTime(DateTimeOffset, TimeZoneInfo) 메서드를 호출할 수 있습니다.

public DateTimeOffset ReturnTimeOnServer(string clientString)
{
   string format = @"M/d/yyyy H:m:s zzz";

   try
   {
      DateTimeOffset clientTime = DateTimeOffset.ParseExact(clientString, format,
                                  CultureInfo.InvariantCulture);
      DateTimeOffset serverTime = TimeZoneInfo.ConvertTime(clientTime,
                                  TimeZoneInfo.Local);
      return serverTime;
   }
   catch (FormatException)
   {
      return DateTimeOffset.MinValue;
   }
}
Public Function ReturnTimeOnServer(clientString As String) As DateTimeOffset
    Dim format As String = "M/d/yyyy H:m:s zzz"

    Try
        Dim clientTime As DateTimeOffset = DateTimeOffset.ParseExact(clientString, format, CultureInfo.InvariantCulture)
        Dim serverTime As DateTimeOffset = TimeZoneInfo.ConvertTime(clientTime, TimeZoneInfo.Local)
        Return serverTime
    Catch e As FormatException
        Return DateTimeOffset.MinValue
    End Try
End Function

참고 항목