C #의 특정 시간대에서 DateTime 만들기


162

시간대가 잘못 설정되어 수정 된 경우 사례를 테스트하기 위해 단위 테스트를 작성하려고합니다.

테스트에서 로컬 시간대가 아닌 시간대에 DateTime 객체를 만들어 테스트를 실행하는 사람들이 위치에 관계없이 성공적으로 수행 할 수 있어야합니다.

DateTime 생성자에서 볼 수 있듯이 TimeZone을 현지 시간대, UTC 시간대 또는 지정하지 않도록 설정할 수 있습니다.

PST와 같은 특정 시간대로 DateTime을 어떻게 만듭니 까?


답변:


216

Jon의 답변TimeZone 에 대해 이야기 하지만 TimeZoneInfo를 대신 사용하는 것이 좋습니다 .

개인적으로 나는 가능한 한 UTC로 물건을 유지하는 것을 좋아합니다 (최소한 과거 에는 미래 를 위해 UTC를 저장하면 잠재적 인 문제가 있습니다 ). 다음과 같은 구조를 제안합니다.

public struct DateTimeWithZone
{
    private readonly DateTime utcDateTime;
    private readonly TimeZoneInfo timeZone;

    public DateTimeWithZone(DateTime dateTime, TimeZoneInfo timeZone)
    {
        var dateTimeUnspec = DateTime.SpecifyKind(dateTime, DateTimeKind.Unspecified);
        utcDateTime = TimeZoneInfo.ConvertTimeToUtc(dateTimeUnspec, timeZone); 
        this.timeZone = timeZone;
    }

    public DateTime UniversalTime { get { return utcDateTime; } }

    public TimeZoneInfo TimeZone { get { return timeZone; } }

    public DateTime LocalTime
    { 
        get 
        { 
            return TimeZoneInfo.ConvertTime(utcDateTime, timeZone); 
        }
    }        
}

더 명확하게하기 위해 "TimeZone"이름을 "TimeZoneInfo"로 변경할 수 있습니다. 더 짧은 이름을 선호합니다.


5
동등한 SQL Server 구문을 알지 못합니다. 시간대 이름을 하나의 열로 사용하고 UTC 값을 다른 열에 사용하는 것이 좋습니다. 별도로 가져 오면 인스턴스를 상당히 쉽게 만들 수 있습니다.
Jon Skeet

2
DateTime 및 TimeZoneInfo를 사용하는 생성자의 예상되는 사용에 대해 잘 모르지만 dateTime.ToUniversalTime () 메서드를 호출한다고 가정하면 현지 시간으로 "아마도"있을 것으로 추측됩니다. 이 경우 전달 된 TimeZoneInfo를 사용하여 해당 시간대에 있다고 가정하므로 UTC로 변환해야한다고 생각합니다.
IDisposable

2
@ChrisMoschini :이 시점에서 여러분은 전 세계 어느 누구도 사용하지 않는 자신 만의 ID 체계를 발명했습니다. 업계 표준 zoneinfo를 고수하겠습니다. 감사합니다. (예를 들어 "유럽 / 런던"이 어떻게 의미가 없는지 알기가 어렵습니다.)
Jon Skeet

2
@ChrisMoschini : 다른 예 : CST. UTC-5입니까 아니면 UTC-6입니까? IST는 어떻습니까? 데이터베이스에 이스라엘, 인도 또는 아일랜드가 있습니까? (현재 오프셋을 알고 있더라도 동일한 약어를 관찰하는 국가마다 시간이 다를 수 있습니다. 따라서 실제 시간대가 무엇인지에 대한 모호성이 여전히 남아 있습니다. 시간대! = 오프셋.) 약어를 사용하면 문제를 가장 잘 해결할 수 있습니다. 산업 표준 시간대 ID를 사용하는 것이 어떻습니까?
Jon Skeet

6
@ChrisMoschini : 글쎄요. 애매 모호한 약어 대신 업계 표준의 명확한 zoneinfo ID를 계속 사용하는 것이 좋습니다. 이것은 누구의 라이브러리를 선호하든 문제가 아닙니다. 라이브러리의 소유권은 실제로 문제가되지 않습니다. 누군가가 좋은 식별자를 선택 하여 다른 라이브러리를 사용하려면 괜찮습니다. 표준 시간대에 대한 식별자 선택은 중요하지만 독자는 IST 예제와 같이 약어 모호하다는 것을 인식하는 것이 매우 중요하다고 생각합니다 .
Jon Skeet

54

DateTimeOffset 구조는 정확히이 유형의 용도로 작성되었습니다.

참조 : http://msdn.microsoft.com/en-us/library/system.datetimeoffset.aspx

특정 시간대를 사용하여 DateTimeOffset 객체를 만드는 예는 다음과 같습니다.

DateTimeOffset do1 = new DateTimeOffset(2008, 8, 22, 1, 0, 0, new TimeSpan(-5, 0, 0));


1
고마워, 이것은 그것을 달성하는 좋은 방법입니다. 올바른 시간대 내에 DateTimeOffset 객체를 가져온 후 .UtcDateTime 속성을 사용하여 생성 한 UTC 시간을 얻을 수 있습니다. UTC로 날짜를 저장하면 각 사용자에 대해 현지 시간으로 변환하는 것이 큰 도움이되지 않습니다. :)
Redth

2
일부 시간대는 다른 시간대에서는 그렇지 않기 때문에 일광 절약 시간제를 올바르게 처리한다고 생각하지 않습니다. 또한 "당일"DST가 시작 / 종료되면 해당 날짜의 일부가 해제됩니다.
crokusek

14
교훈. DST는 특정 시간대의 규칙입니다. DateTimeOffset은 시간대와 관련이 없습니다. -5와 같은 UTC 오프셋 값을 표준 시간대와 혼동하지 마십시오. 시간대가 아니며 오프셋입니다. 동일한 오프셋은 여러 시간대에서 종종 공유되므로 시간대를 참조하는 모호한 방법입니다. DateTimeOffset은 표준 시간대가 아닌 오프셋과 연관되므로 DST 규칙을 적용 할 수 없습니다. 따라서 DateTimeOffset 구조 (예 : Hours 및 TimeOfDay 속성)에서 예외없이 3am은 연중 매일 오전 3시입니다.
Triynko

혼란 스러울 수있는 곳은 DateTimeOffset의 LocalDateTime 속성을 보면입니다. 이 속성은 DateTimeOffset이 아니며 종류가 DateTimeKind.Local 인 DateTime 인스턴스입니다. 해당 인스턴스는 로컬 시스템 시간대와 상관없이 시간대와 연결됩니다. 그 속성은 일광 절약을 반영합니다.
Triynko

4
따라서 DateTimeOffset의 실제 문제는 충분한 정보가 포함되어 있지 않다는 것입니다. 시간대가 아닌 오프셋을 포함합니다. 시간대가 여러 개인 경우 오프셋이 모호합니다.
Triynko

41

여기에있는 다른 답변은 유용하지만 태평양에 구체적으로 액세스하는 방법은 다루지 않습니다.

public static DateTime GmtToPacific(DateTime dateTime)
{
    return TimeZoneInfo.ConvertTimeFromUtc(dateTime,
        TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time"));
}

"태평양 표준시"는 일반적으로 "태평양 일광 절약 시간"과 다른 것을 의미하지만 이상하게도 태평양 표준시를 의미합니다. 실제로 FindSystemTimeZoneById가져 오기 위해 사용 하는 경우 사용 가능한 속성 중 하나는 해당 시간대가 현재 일광 절약 시간인지 여부를 알려주는 바보입니다.

사용자가 요청한 위치 등에 따라 다른 TimeZone에서 필요한 DateTime을 처리하기 위해 함께 던진 라이브러리에서 더 일반적인 예를 볼 수 있습니다.

https://github.com/b9chris/TimeZoneInfoLib.Net

시간 목록이 Windows 레지스트리에서 제공되므로 Windows 외부에서는 작동하지 않습니다 (예 : Linux의 경우 Mono). HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\

그 아래에는 키 (레지스트리 편집기의 폴더 아이콘)가 있습니다. 그 키의 이름은 당신이 전달하는 것 FindSystemTimeZoneById입니다. Linux에서는 적절하게 살펴 보지 않은 별도의 Linux 표준 시간대 정의 세트를 사용해야합니다.


1
또한 ConvertTimeBySystemTimeZoneId ()가 있습니다. 예 : TimeZoneInfo.ConvertTimeBySystemTimeZoneId (DateTime.UtcNow, "Central Standard Time")
Brent

Windows에서 TimeZone ID 목록 도이 답변을 볼 수 있습니다. stackoverflow.com/a/24460750/4573839
yu yang Jian

7

Jon Skeet 이 확장 방법으로 웹에 약간 응답 하도록 변경했습니다 . 그것은 매력처럼 하늘빛에도 작용합니다.

public static class DateTimeWithZone
{

private static readonly TimeZoneInfo timeZone;

static DateTimeWithZone()
{
//I added web.config <add key="CurrentTimeZoneId" value="Central Europe Standard Time" />
//You can add value directly into function.
    timeZone = TimeZoneInfo.FindSystemTimeZoneById(ConfigurationManager.AppSettings["CurrentTimeZoneId"]);
}


public static DateTime LocalTime(this DateTime t)
{
     return TimeZoneInfo.ConvertTime(t, timeZone);   
}
}

2

이를 위해 커스텀 객체를 만들어야합니다. 사용자 정의 객체에는 두 가지 값이 포함됩니다.

해당 CLR 제공 데이터 형식이 있는지 확실하지 않지만 적어도 TimeZone 구성 요소는 이미 사용 가능합니다.


2

Jon Skeet의 답변이 마음에 들지만 한 가지만 추가하고 싶습니다. Jon이 ctor가 항상 현지 시간대로 전달 될 것으로 기대하는지 확실하지 않습니다. 그러나 로컬이 아닌 다른 경우에 사용하고 싶습니다.

데이터베이스에서 값을 읽고 데이터베이스의 시간대를 알고 있습니다. 따라서 ctor에서는 데이터베이스의 시간대를 전달합니다. 그러나 현지 시간의 가치를 원합니다. Jon의 LocalTime은 원래 시간대 날짜로 변환 된 원래 날짜를 반환하지 않습니다. 원래 시간대로 변환 된 날짜를 반환합니다 (ctor에 전달한 날짜).

나는이 속성 이름이 그것을 정리한다고 생각합니다 ...

public DateTime TimeInOriginalZone { get { return TimeZoneInfo.ConvertTime(utcDateTime, timeZone); } }
public DateTime TimeInLocalZone    { get { return TimeZoneInfo.ConvertTime(utcDateTime, TimeZoneInfo.Local); } }
public DateTime TimeInSpecificZone(TimeZoneInfo tz)
{
    return TimeZoneInfo.ConvertTime(utcDateTime, tz);
}

0

TimeZones 클래스를 사용하면 시간 대별 날짜를 쉽게 만들 수 있습니다.

TimeZoneInfo.ConvertTime(DateTime.Now, TimeZoneInfo.FindSystemTimeZoneById(TimeZones.Paris.Id));

1
죄송하지만 Asp .NET Core 2.2에서는 사용할 수 없습니다. VS2017에서 Outlook Nuget 패키지를 설치하도록 제안하고 있습니다.
Machado

예 => TimeZoneInfo.ConvertTime (DateTime.Now, TimeZoneInfo.FindSystemTimeZoneById ( "Pacific Standard Time"))
AZ_
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.