计算DST转换边界处的持续时间(向前/向后弹回的量) [英] Calculate duration (amount to spring forward/fall back) at DST transitions boundaries

查看:67
本文介绍了计算DST转换边界处的持续时间(向前/向后弹回的量)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

通过这个很好的答案,我可以确定夏令时的转换日期: https://stackoverflow.com/a/24378695/1159939

From this great answer, I am able to determine daylight saving transitions dates: https://stackoverflow.com/a/24378695/1159939

除了这些日期外,我还需要知道时钟是要增加还是减少以及时钟量是多少(总是一个小时?).

In addition of those dates, I need to know if the clock is going to increase or decrease and by what amount (is it always an hour?).

例如,在美国/太平洋时区,当本地时钟到达2020-03-08T02:00:00时,我需要以某种方式获取值+ 1h.当时钟到达2020-11-01T02:00:00时,我需要获取值-1h.

For example, in time zone US/Pacific, when the local clock reaches 2020-03-08T02:00:00, I need to somehow get value +1h. When the clock reaches 2020-11-01T02:00:00, I need to get value -1h.

在NodaTime中,有一个Offset.Savings值是+0或+1.现在确定如何使用它.

In NodaTime, there is a Offset.Savings value that is +0 or +1. Now sure how I can use that.

-更新1:我正在建立一个调度程序.我需要让用户更好地控制在节省1小时的时间内执行预定作业时如何执行作业.

--Update1: I am building a scheduler. I need to give the user more control over how jobs are executed when a scheduled job is to occur during the 1-hour savings period.

我正在考虑进行以下设置,以便用户可以选择:

I am thinking for having the following settings the user can select:

[x]时钟向前跳时,运行丢失的作业.

[x] Run missed jobs when clocks spring forward.

[x]时钟回落时重新运行作业.

[x] Re-run jobs when clocks fall back.

例如,假设一项工作计划在2020-03-08T02:15:00美国/太平洋地区运行.该本地时间不存在.如果用户勾选时钟向前运行时运行错过的作业",则显示为否".复选框,该作业将在凌晨3:15执行,否则,该作业将被跳过.

For example, let's say a job is scheduled to run at 2020-03-08T02:15:00 US/Pacific. This local time does not exist. If the user ticks off the "Run missed jobs when clocks spring forward" checkbox, the job will be executed at 3:15AM, otherwise, the job will be skipped.

例如,假设一个作业计划在2020-11-01T01:45:00美国/太平洋地区运行.此本地时间将发生两次.如果用户勾选时钟回落时重新运行作业",则该作业将被执行两次,否则将被执行一次.

For example, let's say a job is scheduled to run at 2020-11-01T01:45:00 US/Pacific. This local time will occur twice. If the user ticks off the "Re-run jobs when clocks fall back", the job will be executed twice, otherwise, it will be executed once.

为了进行上述计算,我需要知道我从前面提到的帖子中获得的夏令时转换日期.我还需要知道时钟将改变哪个方向以及改变多少时间(例如:1h).

In order to make the calculations above, I need to know the day light saving transition dates which I got from the post mentioned previously. I also need to know which direction the clocks will change and by how much (e.g.: 1h).

-Update2:

经过深思熟虑之后,我认为我需要一个包含以下数据的时区转换列表:

After giving it more thought, I think I need a list of time zone transitions that contains the following data:

2020-03-08 02:00:00 US/Eastern | 2020-03-08 07:00:00 UAT (01:00:00)
2020-11-01 02:00:00 US/Eastern | 2020-11-01 06:00:00 UAT (-01:00:00)

下面是我用来生成此数据的代码.不知道这是否在所有情况下都有效.为了计算时间变化,我使用下一个区域间隔的开始与当前区域间隔的结束之间的差.

Below is the code that I am using to generate this data. Not sure if this will work in all cases. In order to calculate time change, I am using the difference between the start of the next zone interval and the end of the current zone interval.

using NodaTime;
using System;
using System.Collections.Generic;

namespace ConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            string timeZoneId = "US/Eastern";
            DateTimeZone? timeZone = DateTimeZoneProviders.Tzdb.GetZoneOrNull(timeZoneId);

            if (timeZone is null)
                throw new Exception($"Cannot find time zone '{timeZoneId}'.");

            int year = 2020;

            var daylightSavingTransitions = GetDaylightSavingTransitions(timeZone, year);

            foreach (var daylightSavingTransition in daylightSavingTransitions)
            {
                Console.WriteLine(daylightSavingTransition);
            }


            /// <summary>
            /// Get points in time when a daylight saving time transitions occur.
            /// </summary>
            /// <param name="timeZone">Time zone of the local clock.</param>
            /// <param name="year">The year to find transitions.</param>
            /// <returns></returns>
            static IEnumerable<DaylightSavingTransition> GetDaylightSavingTransitions(DateTimeZone timeZone, int year)
            {
                var yearStart = new LocalDateTime(year, 1, 1, 0, 0).InZoneLeniently(timeZone).ToInstant();
                var yearEnd = new LocalDateTime(year + 1, 1, 1, 0, 0).InZoneLeniently(timeZone).ToInstant();

                LinkedList<NodaTime.TimeZones.ZoneInterval> zoneIntervals = new LinkedList<NodaTime.TimeZones.ZoneInterval>(timeZone.GetZoneIntervals(yearStart, yearEnd));
                LinkedListNode<NodaTime.TimeZones.ZoneInterval>? currentNode = zoneIntervals.First;

                while (currentNode is { })
                {
                    if (currentNode.Next is null)
                        break;

                    //Time change is the difference between the start of the next zone interval and the end of the current zone interval.
                    Period timeChangePeriod = currentNode.Next.Value.IsoLocalStart - currentNode.Value.IsoLocalEnd;
                    TimeSpan timeChange = new TimeSpan(Convert.ToInt32(timeChangePeriod.Hours), Convert.ToInt32(timeChangePeriod.Minutes), Convert.ToInt32(timeChangePeriod.Seconds));
                    DaylightSavingTransition daylightSavingTransition = new DaylightSavingTransition(timeZone.Id, currentNode.Value.IsoLocalEnd.ToDateTimeUnspecified(), currentNode.Value.End.ToDateTimeUtc(), timeChange);
                    yield return daylightSavingTransition;

                    currentNode = currentNode.Next;
                }
            }
        }
    }



    public class DaylightSavingTransition
    {
        public DaylightSavingTransition(string timeZoneId, DateTime transitionLocalDate, DateTime transitionUtcDate, TimeSpan timeChange)
        {
            TimeZoneId = timeZoneId;
            TransitionLocalDate = DateTime.SpecifyKind(transitionLocalDate, DateTimeKind.Unspecified);
            TransitionUtcDate = DateTime.SpecifyKind(transitionUtcDate, DateTimeKind.Utc);
            TimeChange = timeChange;
        }

        public string TimeZoneId { get; }
        public DateTime TransitionLocalDate { get; }
        public DateTime TransitionUtcDate { get; }
        public TimeSpan TimeChange { get; }

        /// <summary>
        /// For fall back transition, used to determine if date is in the duplicated time period.
        /// </summary>
        /// <param name="utcDateTime">Point in time to test if it is inside the repeating time period.</param>
        public bool IsRepeatingDateTime(DateTime utcDateTime)
        {
            if (utcDateTime >= TransitionUtcDate && utcDateTime < TransitionUtcDate.Add(TimeChange.Duration()))
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        public override string ToString()
        {
            return $"{TransitionLocalDate.ToString("yyyy-MM-dd HH:mm:ss")} {TimeZoneId} | {TransitionUtcDate.ToString("yyyy-MM-dd HH:mm:ss")} UAT ({TimeChange})";
        }
    }
}

推荐答案

听起来您真正想要的是 ZoneLocalMapping 其中告诉您如何将本地日期/时间映射到指定的时区.重要的属性是:

It sounds like what you're really looking for is DateTimeZone.MapLocal(LocalDateTime). That returns a ZoneLocalMapping which tells you how a local date/time is mapped into the specified time zone. The important properties are:

  • 计数
    • 如果跳过日期/时间,则为0
    • 1(如果已明确映射)
    • 2如果映射不明确

    ZoneInterval 包含一个 WallOffset ,它是该区域间隔内的整个UTC偏移量.我强烈建议使用该选项,而不是使用 Savings ,以应对没有夏令时的过渡(例如,如果某个区域的标准时间发生了变化).

    ZoneInterval contains a WallOffset which is the overall UTC offset during that zone interval. I'd strongly recommend using that rather than Savings, in order to cope with transitions which aren't daylight saving transitions (e.g. if the standard time for a zone changes).

    您应该能够使用该信息来确定何时运行事物.

    You should be able to use that information to determine when to run things.

    您还可以使用(Local.Recode,DateTime,LocalTimeZoneLocalMappingResolver) ,您将在其中基于用户选择的内容构建自己的解析器(用于处理跳过/模糊时间).

    You could also use DateTimeZone.ResolveLocal(LocalDateTime, ZoneLocalMappingResolver) where you'd build your own resolver (for handling skipped/ambiguous times) based on what the user has selected.

    这篇关于计算DST转换边界处的持续时间(向前/向后弹回的量)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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