从日期计算夏令时

我正在使用Arduino和实时时钟芯片。 该芯片补偿闰年等,所以它会始终有正确的日期,但它不处理夏令时,我假设由于区域并发症。 时钟可以给我日,月,年(1基)和星期几(星期日= 0到星期六= 6)。

因为我需要与用户输入的日期和时间进行比较,所以我需要知道夏令时调整的日期和时间。 如果当前日期处于夏令时,我可以简单地在时钟上添加一小时,然后获得所需的时间。

最难的部分是确定我是否处于夏令时,因为它每年都在变化。 我只关心它在我的位置(山区时间)工作。 我的平台似乎没有任何全面的日期库,而且我觉得这样做无论如何都是过度的。 是否有一个简单的公式来确定我是否在DST中?


这实际上看似简单。 有几个事实可以帮助我们:

  • 在美国的大部分地区,夏令时开始于3月的第二个星期日,并于11月的第一个星期日结束,时间是上午2点。
  • 三月的第二个星期日总是在8日和14日之间。
  • 11月的第一个星期日将始终在1日和7日之间。
  • 星期几的编号非常方便,因为每周的星期几会给你前一个星期日。
  • 这些事实导致下面的代码(C#,但轻松地移植到您的平台):

        public bool IsDST(int day, int month, int dow)
        {
            //January, february, and december are out.
            if (month < 3 || month > 11) { return false; }
            //April to October are in
            if (month > 3 && month < 11) { return true; }
            int previousSunday = day - dow;
            //In march, we are DST if our previous sunday was on or after the 8th.
            if (month == 3) { return previousSunday >= 8; }
            //In november we must be before the first sunday to be dst.
            //That means the previous sunday must be before the 1st.
            return previousSunday <= 0;
        }
    

    事实证明,您甚至不需要知道年份就可以做到这一点,只要您可以相信每周的每日价值即可。

    我编写了一个快速单元测试,并验证了该代码与TimeZone.IsDayLightSavingsTime()在1800到2200年间的所有日期都一致。我没有考虑凌晨2点的规则,但是如果星期几是星期日日期为8日至14日(3月)或1日和7日(11月)。


    中欧代码(每年在2014 - 3000年范围内测试)

        public static bool IsDst(int day, int month, int dow)
        {
            if (month < 3 || month > 10)  return false; 
            if (month > 3 && month < 10)  return true; 
    
            int previousSunday = day - dow;
    
            if (month == 3) return previousSunday >= 25;
            if (month == 10) return previousSunday < 25;
    
            return false; // this line never gonna happend
        }
    

    测试功能

        static void Main(string[] args)
        {
            TimeZoneInfo tzf2 = TimeZoneInfo.FindSystemTimeZoneById("Central Europe Standard Time");
    
            var date = new DateTime(2014, 01, 1, 5, 0,0);
            bool wasSummer = false;
    
            while (date <= new DateTime(3000,1,1))
            {                                         
                var dow = (int) date.DayOfWeek;
    
                var isDst = IsDst(date.Day, date.Month, dow);               
    
                DateTime f2 = TimeZoneInfo.ConvertTime(date, tzf2);
                var isSummer = f2.IsDaylightSavingTime();
    
                if (isSummer != isDst)
                {
                    Console.WriteLine("ERROR");
                    Console.WriteLine(date);
                }
    
                if (isSummer != wasSummer)
                {
                    Console.WriteLine(date.AddDays(-1).ToShortDateString());
                }
    
                date = date.AddDays(1);
                wasSummer = isSummer;
            }
    
            Console.ReadKey();
    

    }


    尽管根据当前规则很容易计算某个特定位置的某个特定日期是否属于DST,但请注意,DST处于政治家的心血结晶之中,并且可能随时发生变化。 我有一个制造于2007年以前的时钟,可以自动调整夏令时,现在我必须每年更换四次 :实际更改发生两次,现在两次 - 在旧日期错误地更改。

    在这种情况下,您可以通过让用户输入时区以及日期和时间的简单方法完全忽略DST。 或者你可以像大多数消费设备那样做,并让用户每年调整两次到当地时区的时间。

    但是,如果您确实需要处理DST并确实想做正确的事情,请使用zoneinfo数据库并确保可以以某种方式进行更新。 如果由于某种原因你不能这样做,至少允许用户覆盖规则。 如果即使这样也太难了,至少应该让用户选择关闭自动调整功能(不像我的笨闹闹钟)。

    链接地址: http://www.djcxy.com/p/29409.html

    上一篇: Calculating daylight saving time from only date

    下一篇: What are the "standard" timezone abbreviations?