C#在特定的TimeZone中添加1天到DateTimeOffset [英] C# Add 1 day in specific TimeZone to DateTimeOffset

查看:175
本文介绍了C#在特定的TimeZone中添加1天到DateTimeOffset的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 DateTimeOffset 的实例,我需要在特定的 TimeZone 中添加1天(W.欧洲标准时间)考虑了夏令时规则(因此可能会导致 Offset 更改)。没有第三方库怎么办?

I have an instance of DateTimeOffset and I need to add 1 day to it in specific TimeZone (W. Europe Standard Time) taking into account daylight saving rules (so it might result in Offset change). How can I do it without 3rd party libraries?

可验证的示例:

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如果导致无效/模糊/跳过日期,则可以抛出异常。

PS If it results in invalid/ambigous/skipped date, then it is fine to throw exception.

推荐答案

TimeZoneInfo 使此合理简单-只需在值的 DateTime 部分添加一天,检查结果是否被跳过或模棱两可,如果不是,则向该区域询问UTC偏移量。这是一个完整的示例,显示了所有不同的可能性:

TimeZoneInfo makes this reasonably simple - just add a day to the DateTime part of the value, check whether the result is skipped or ambiguous, and if not, ask the zone for the UTC offset. Here's a complete example showing all the different possibilities:

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

}

这篇关于C#在特定的TimeZone中添加1天到DateTimeOffset的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆