【问题标题】:C# Add 1 day in specific TimeZone to DateTimeOffsetC# 将特定时区中的 1 天添加到 DateTimeOffset
【发布时间】:2017-12-08 08:18:22
【问题描述】:

我有一个 DateTimeOffset 的实例,我需要在特定的 TimeZone(西欧洲标准时间)中添加 1 天,同时考虑到夏令时规则(因此它可能会导致 Offset 更改)。如果没有 3rd 方库,我该怎么做?

可验证的例子:

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 如果它导致无效/不明确/跳过日期,那么抛出异常是可以的。

【问题讨论】:

  • 请澄清确切您的意思,最好使用minimal reproducible exampleDateTimeOffset 是否包含对相关时区绝对有效的偏移量?如果添加一天导致时间不明确或被跳过,您会怎么做? (想象一下前一天的凌晨 1:30,时钟分别在凌晨 2 点或 1 点向后或向前。你想增加一天做什么?)
  • 如果你的意思是没有“非微软”库,我怀疑答案是否定的:docs.microsoft.com/en-us/dotnet/standard/datetime/…
  • @DylanNicholson:我确信使用少量代码,使用TimeZoneInfo 应该是可行的。 (当然,使用 Noda Time 会更好,但那是另一回事。)但我们首先需要一组非常精确的要求 - 在此之前尝试没有意义。
  • 向问题添加了可验证的示例。
  • 这不是真正的minimal reproducible example - 我们不能复制/粘贴/编译/运行。但更重要的是,您还没有解决我的问题,即偏移量是否绝对有效,以及您想对模棱两可/跳过的时间做什么。我不会花时间编写可能不适用于您的实际、未说明的要求的代码。

标签: c# .net timezone datetimeoffset .net-4.6


【解决方案1】:

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

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

}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-05-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-16
    相关资源
    最近更新 更多