2017-12-08 19 views
0

私はDateTimeOffsetのインスタンスを持っており、夏時間ルールを考慮して、特定のTimeZone(W.ヨーロッパ標準時)で1日追加する必要があります(Offset変化する)。サードパーティ製のライブラリがないとどうすればいいですか?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方法は正しい実装に置き換えなければなりません。

PS無効/不明瞭/スキップされた日付になった場合、例外をスローすると問題ありません。

+1

[mcve]と理想的には、*正確に*を明記してください。 'DateTimeOffset'には問題のタイムゾーンに対して間違いなく有効なオフセットが含まれていますか? 1日追加するとあいまいな時間やスキップされた時間になった場合はどうしますか? (午前1時30分*前に午前2時または午後1時に時計が戻るか前になると思います)。 –

+0

「非Microsoft」以外のライブラリがない場合は、答えが疑わしいはありません:https://docs.microsoft.com/en-us/dotnet/standard/datetime/performing-arithmetic-operations –

+1

@DylanNicholson:私は確かに少量のコードでは 'TimeZoneInfo' 。 (野田時代の方がいいかもしれませんが、それは別の問題です)。しかし、まずは本当に正確な要件が必要です。それ以前に試してみる必要はありません。 –

答えて

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)); 
    } 

} 
関連する問題