2017-12-08 18 views
0

나는 DateTimeOffset의 인스턴스를 가지고 있으며 일광 절약 규칙을 고려하여 특정 TimeZone (W. 유럽 표준시)에 1 일을 추가해야합니다 (따라서 Offset 변화). 제 3 자 라이브러리가 없으면 어떻게해야합니까?C# 특정 TimeZone에서 DateTimeOffset으로 1 일 추가

입증 가능한 예 :

using System; 
using Microsoft.VisualStudio.TestTools.UnitTesting; 

namespace UnitTestProject 
{ 
    [TestClass] 
    public class TimeZoneTests 
    { 
     [TestMethod] 
     public void DateTimeOffsetAddDays_DaylightSaving_OffsetChange() 
     { 
      var timeZoneId = "W. Europe Standard Time"; 
      var utcTimestamp = new DateTimeOffset(2017, 10, 28, 22, 0, 0, TimeZoneInfo.Utc.BaseUtcOffset); 
      var weuropeStandardTimeTimestamp = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(utcTimestamp, timeZoneId); 
      Assert.AreEqual(new DateTime(2017, 10, 29), weuropeStandardTimeTimestamp.DateTime); 
      Assert.AreEqual(TimeSpan.FromHours(2), weuropeStandardTimeTimestamp.Offset); 

      var weuropeStandardTimeTimestampNextDay = AddDaysInTimeZone(weuropeStandardTimeTimestamp, 1, timeZoneId); 

      Assert.AreEqual(new DateTime(2017, 10, 30), weuropeStandardTimeTimestampNextDay); 
      Assert.AreEqual(TimeSpan.FromHours(1), weuropeStandardTimeTimestamp.Offset); 
     } 

     private DateTimeOffset AddDaysInTimeZone(DateTimeOffset timestamp, int days, string timeZoneId) 
     { 
      // this line has to be fixed: 
      return timestamp.AddDays(days); 
     } 
    } 
} 

AddDaysInTimeZone 방법은 정확한 구현으로 대체되어야한다.

추신 : 잘못된/애매한/건너 뛴 날짜가 발생하면 예외가 발생합니다.

+1

[mcve]를 사용하면 이상적으로 * 정확하게 * 명확하게 설명하십시오. 'DateTimeOffset'에 문제의 시간대에 대해 유효한 오프셋이 포함되어 있습니까? 일을 추가하면 모호하거나 건너 뛴 시간이 생기면 무엇을하고 싶습니까? (매일 오전 1시 30 분 * 시계가 오전 2시 또는 오후 1시에 앞뒤로 진행된다고 상상해보십시오.) –

+0

"비 Microsoft"라이브러리가 없다면 그 대답을 의심 할 것입니다 아니요 : https://docs.microsoft.com/en-us/dotnet/standard/datetime/performing-arithmetic-operations –

+1

@DylanNicholson : 소량의 코드로 'TimeZoneInfo'를 사용하여 실행 가능해야합니다. . (물론 Noda Time과 함께라면 더 좋을 것입니다.하지만 그건 다른 문제입니다.) 그러나 먼저 정확한 요구 사항 집합이 필요합니다. 이전에는 시도 할 필요가 없습니다. –

답변

2

TimeZoneInfo합리적으로 간단하게 - 단지 결과가 생략하거나 모호, 그렇지 않은 경우, 오프셋 UTC의 영역을 요청 여부를 확인 값의 DateTime 부분에 하루를 추가합니다. 다음은 모든 다른 가능성을 보여주는 완벽한 예입니다.

using System; 
using System.Globalization; 

using static System.FormattableString; 

class Program 
{ 
    static void Main() 
    {   
     // Stay in winter 
     Test("2017-01-22T15:00:00+01:00"); 
     // Skipped time during transition 
     Test("2017-03-25T02:30:00+01:00"); 
     // Offset change to summer 
     Test("2017-03-25T15:00:00+01:00"); 
     // Stay in summer 
     Test("2017-06-22T15:00:00+02:00"); 
     // Ambiguous time during transition 
     Test("2017-10-28T02:30:00+02:00"); 
     // Offset change back to winter 
     Test("2017-10-28T15:00:00+02:00"); 
     // Stay in winter 
     Test("2017-12-22T15:00:00+01:00"); 
    } 

    static void Test(string startText) 
    { 
     var zone = TimeZoneInfo.FindSystemTimeZoneById("W. Europe Standard Time"); 
     var start = DateTimeOffset.ParseExact(
      startText, "yyyy-MM-dd'T'HH:mm:ssK", CultureInfo.InvariantCulture); 
     try 
     { 
      var end = AddOneDay(start, zone); 
      Console.WriteLine(Invariant($"{startText} => {end:yyyy-MM-dd'T'HH:mm:ssK}")); 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine($"{startText} => {e.Message}"); 
     } 
    } 

    static DateTimeOffset AddOneDay(DateTimeOffset start, TimeZoneInfo zone) 
    { 
     var newLocal = start.DateTime.AddDays(1); 
     // TODO: Use a better exception type :) 
     if (zone.IsAmbiguousTime(newLocal)) 
     { 
      throw new Exception("Ambiguous"); 
     } 
     if (zone.IsInvalidTime(newLocal)) 
     { 
      throw new Exception("Skipped"); 
     } 
     return new DateTimeOffset(newLocal, zone.GetUtcOffset(newLocal)); 
    } 

}