Calculating daylight saving time from only date

I am working with an Arduino and a real time clock chip. The chip compensates for leap years and such, so it will always have the correct date, but it does not handle daylight saving time, I assume due to regional complications. The clock can give me the day, month, and year (1 based) and the day of the week (sunday = 0 to saturday = 6).

Because I need to compare with user entered dates and times, I need to know the date and time adjusted for daylight saving time. If the current date is in daylight saving time I can simply add an hour to the time from the clock and I have what I need.

The hard part is determining whether I am in daylight saving time or not, because it changes from year to year. I only care that it works in my location (Mountain Time). There doesn't appear to be any comprehensive date libraries for my platform, and I feel like that would be overkill anyway. Is there a simple formula to determine if I am in DST or not?


This is actually deceptively simple. There are a few facts that will help us:

  • In most of the US, DST starts on the second Sunday of March and ends on the first Sunday of November, at 2:AM both times.
  • The second Sunday in March will always be between the 8th and the 14th inclusive.
  • The first Sunday in November will always be between the 1st and 7th inclusive.
  • The day of week numbering is quite convenient because the day - day of week will give you the previous Sunday.
  • These facts lead to the following code (C#, but trivially portable to your platform):

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

    It turns out you don't even need to know the year to do this, as long as you can trust your day of the week value.

    I wrote a quick unit test and verified that this code agrees with TimeZone.IsDayLightSavingsTime() for all dates from 1800 to 2200. I did not account for the 2 am rule, but you could easily do that check if the day of week is Sunday and the date is between 8 and 14 (in March) or 1 and 7 (in November).


    Code for Central Europe (tested for every day in range 2014-3000 year)

        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
        }
    

    Test function

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

    }


    While it is easy to calculate whether a particular date is in DST for a particular location under the current rules, do note that DST is at the whim of politicians and could change at any point. I have a clock manufactured pre-2007 that automatically adjusts for daylight savings time, and now I have to change it four times a year: twice when the actual change occurs, and twice when it now-incorrectly changes itself at the old dates.

    In this case, you might be able to ignore DST completely by the simple expedient of having the user enter the timezone along with the date and time. Or you could do like most consumer devices and let the user adjust the time to the local time zone twice a year.

    But if you really need to handle DST and really want to do things right, use the zoneinfo database and make sure it can be updated somehow. If you can't do that for some reason, at least allow the user to override the rules. And if even that is too difficult, at least give the user the option to turn off automatic adjustments (unlike my stupid alarm clock).

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

    上一篇: 时区以及PHP处理DST的时区

    下一篇: 从日期计算夏令时