Calculating daylight saving time from only date

后端 未结 9 1594
春和景丽
春和景丽 2021-01-31 10:53

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 s

相关标签:
9条回答
  • 2021-01-31 11:15

    this code uses mktime to get a day of the week. It used a day of the week to compute daylight savings time. If you don't want to use mktime, you can use program second_sunday. Start with 3/14/2007, which is Wednesday. The day of the week will advance 1 day for every year and 2 days for every leap after 2004.

    #include <stdio.h>
    #include <string.h>
    #include <time.h>
    #include <sys/timeb.h>
    
    
    int isDst(int month, int dayOfMonth, int hour, int dayOfWeek);
    
    int main(int argc, char *argv[])
    {
       int isdst, dayOfWeek;
       char buf[80];
       struct tm tmData;
    
       if( argc == 1 )
       {
          printf("\nsyntax: %s mm/dd/yyyy_hh:mm:00", argv[0]);
          return -1;
       }
    
       // 0123456789A12
       // 03/12/2018_12
       strcpy(buf, argv[1]);
       tmData.tm_mon   = atoi(&buf[0]) - 1;  //month -1
       tmData.tm_mday  = atoi(&buf[3]); //day of month
       tmData.tm_year  = atoi(&buf[6]) - 1900; // year - 1900
       tmData.tm_hour  = atoi(&buf[11]); // hour
       tmData.tm_min   = 0; //minutes (not used)
       tmData.tm_sec   = 0; //seconds (not used)
       //tmData.tm_min   = atoi(&buf[14]);
       //tmData.tm_sec   = atoi(&buf[27]);
    
       //day light saving time variable.
       //NOT used in this calculation.
       //Tells mktime the input date is in day light saving time
       tmData.tm_isdst = 0; //
    
       mktime(&tmData);
       dayOfWeek = tmData.tm_wday;
    
       printf("%02d/%02d/%2d_%02d dayWk=%d ",
          tmData.tm_mon+1, tmData.tm_mday, tmData.tm_year, tmData.tm_hour, dayOfWeek);
       isdst = isDst(tmData.tm_mon+1, tmData.tm_mday, tmData.tm_hour, dayOfWeek);
       printf("isdst=%d\n", isdst);
    
       return 0;
    }
    
    
    int isDst(int month, int dayOfMonth, int hour, int dayOfWeek)
    {
       int second_sunday, first_sunday;
    
       if( month  > 3 && month < 11  ) return 1; //4,5,6,7,8,9,10
       if( month  < 3 || month == 12 ) return 0; //1, 2 or 12
       if( month == 3 )
       {
          //The 2nd Sunday in March is 8,9,10,11,12,13,14
          if( dayOfMonth < 8  ) return 0;
          if( dayOfMonth > 14 ) return 1;
    
          //To get here dayOfMonth >= 8 && dayOfMonth <= 14
          second_sunday = dayOfMonth - dayOfWeek;
          if( second_sunday < 8 ) second_sunday += 7;
    printf("2nd_Sunday=%2d ", second_sunday);
          if( dayOfMonth > second_sunday ) return 1;
          if( dayOfMonth < second_sunday ) return 0;
    
          //To get here dayOfMonth = second_sunday
          if( hour >= 2 ) return 1;
          else return 0;
       }
    
       if( month == 11 )
       {
          //The 1st Sunday in Nov is 1,2,3,4,5,6,7
          if( dayOfMonth > 7 ) return 0;
    
          //To get here dayOfMonth >= 1 && dayOfMonth <= 7
          first_sunday = dayOfMonth - dayOfWeek;
          if( first_sunday < 1 ) first_sunday += 7;
    printf("1st_Sunday=%2d ", first_sunday);
          if( dayOfMonth > first_sunday ) return 0;
          if( dayOfMonth < first_sunday ) return 1;
    
          //To get here dayOfMonth = first_sunday
          if( hour >= 2 ) return 0;
          else return 1;
       }
       return -1;
    }
    /**************
       Compile via   cl.exe  isDst.c
    
       Begin and End dates for day light saving time
       03/11/2007_01:00:00    11/04/2007_01:00:00
       03/09/2008_01:00:00    11/02/2008_01:00:00
       03/08/2009_01:00:00    11/01/2009_01:00:00
       03/14/2010_01:00:00    11/07/2010_01:00:00
       03/13/2011_01:00:00    11/06/2011_01:00:00
       03/11/2012_01:00:00    11/04/2012_01:00:00
       03/10/2013_01:00:00    11/03/2013_01:00:00
       03/09/2014_01:00:00    11/02/2014_01:00:00
       03/08/2015_01:00:00    11/01/2015_01:00:00
       03/13/2016_01:00:00    11/06/2016_01:00:00
       03/12/2017_01:00:00    11/05/2017_01:00:00
       03/11/2018_01:00:00    11/04/2018_01:00:00
       03/10/2019_01:00:00    11/03/2019_01:00:00
       03/08/2020_01:00:00    11/01/2020_01:00:00
       03/14/2021_01:00:00    11/07/2021_01:00:00
       03/13/2022_01:00:00    11/06/2022_01:00:00
       03/12/2023_01:00:00    11/05/2023_01:00:00
       03/10/2024_01:00:00    11/03/2024_01:00:00
       03/09/2025_01:00:00    11/02/2025_01:00:00
       03/08/2026_01:00:00    11/01/2026_01:00:00
       03/14/2027_01:00:00    11/07/2027_01:00:00
       03/12/2028_01:00:00    11/05/2028_01:00:00
       03/11/2029_01:00:00    11/04/2029_01:00:00
       03/10/2030_01:00:00    11/03/2030_01:00:00
       03/09/2031_01:00:00    11/02/2031_01:00:00
       03/14/2032_01:00:00    11/07/2032_01:00:00
    
       isDst.exe 03/11/2007_02:00:00  >> dst.txt
       isDst.exe 03/09/2008_02:00:00  >> dst.txt
       isDst.exe 03/08/2009_02:00:00  >> dst.txt
       isDst.exe 03/14/2010_02:00:00  >> dst.txt
       isDst.exe 03/13/2011_02:00:00  >> dst.txt
       isDst.exe 03/11/2012_02:00:00  >> dst.txt
       isDst.exe 03/10/2013_02:00:00  >> dst.txt
       isDst.exe 03/09/2014_02:00:00  >> dst.txt
       isDst.exe 03/08/2015_02:00:00  >> dst.txt
       isDst.exe 03/13/2016_02:00:00  >> dst.txt
       isDst.exe 03/12/2017_02:00:00  >> dst.txt
       isDst.exe 03/11/2018_02:00:00  >> dst.txt
       isDst.exe 03/10/2019_02:00:00  >> dst.txt
       isDst.exe 03/08/2020_02:00:00  >> dst.txt
       isDst.exe 03/14/2021_02:00:00  >> dst.txt
       isDst.exe 03/13/2022_02:00:00  >> dst.txt
       isDst.exe 03/12/2023_02:00:00  >> dst.txt
       isDst.exe 03/10/2024_02:00:00  >> dst.txt
       isDst.exe 03/09/2025_02:00:00  >> dst.txt
       isDst.exe 03/08/2026_02:00:00  >> dst.txt
       isDst.exe 03/14/2027_02:00:00  >> dst.txt
       isDst.exe 03/12/2028_02:00:00  >> dst.txt
       isDst.exe 03/11/2029_02:00:00  >> dst.txt
       isDst.exe 03/10/2030_02:00:00  >> dst.txt
       isDst.exe 03/09/2031_02:00:00  >> dst.txt
       isDst.exe 03/14/2032_02:00:00  >> dst.txt
       isDst.exe 11/04/2007_02:00:00  >> dst.txt
       isDst.exe 11/02/2008_02:00:00  >> dst.txt
       isDst.exe 11/01/2009_02:00:00  >> dst.txt
       isDst.exe 11/07/2010_02:00:00  >> dst.txt
       isDst.exe 11/06/2011_02:00:00  >> dst.txt
       isDst.exe 11/04/2012_02:00:00  >> dst.txt
       isDst.exe 11/03/2013_02:00:00  >> dst.txt
       isDst.exe 11/02/2014_02:00:00  >> dst.txt
       isDst.exe 11/01/2015_02:00:00  >> dst.txt
       isDst.exe 11/06/2016_02:00:00  >> dst.txt
       isDst.exe 11/05/2017_02:00:00  >> dst.txt
       isDst.exe 11/04/2018_02:00:00  >> dst.txt
       isDst.exe 11/03/2019_02:00:00  >> dst.txt
       isDst.exe 11/01/2020_02:00:00  >> dst.txt
       isDst.exe 11/07/2021_02:00:00  >> dst.txt
       isDst.exe 11/06/2022_02:00:00  >> dst.txt
       isDst.exe 11/05/2023_02:00:00  >> dst.txt
       isDst.exe 11/03/2024_02:00:00  >> dst.txt
       isDst.exe 11/02/2025_02:00:00  >> dst.txt
       isDst.exe 11/01/2026_02:00:00  >> dst.txt
       isDst.exe 11/07/2027_02:00:00  >> dst.txt
       isDst.exe 11/05/2028_02:00:00  >> dst.txt
       isDst.exe 11/04/2029_02:00:00  >> dst.txt
       isDst.exe 11/03/2030_02:00:00  >> dst.txt
       isDst.exe 11/02/2031_02:00:00  >> dst.txt
       isDst.exe 11/07/2032_02:00:00  >> dst.txt
       https://stackoverflow.com/questions/5590429/calculating-daylight-saving-time-from-only-date
    ***************/
    
    
    
    /*****
    The previous programs used mktime to compute day_of_week.
    It used day_of_week to compute 2nd_sunday in march and
    1st_sunday in Nov.
    If you don't want to use mktime, you can use this program to
    compute 2nd_sunday.  The same technique will compute 1st_sunday.
    
    On 03/14/2007, the day of the week is Wed, or 3.
    Every year after 2007, the day of the week advances 1 day.
    on leap years, the day of the week advances 2 days.
    Must include the no. of leap years sinc 2004.
    ******/
    
    #include <stdio.h>
    #include <string.h>
    #include <time.h>
    
    int secondSunday(year);
    
    int main(int argc, char *argv[])
    {
       int year, second_sunday;
    
       if( argc == 1 )
       {
          printf("\nsyntax: %s year, with year >= 2007.\n", argv[0]);
          return -1;
       }
    
       year = atoi(argv[1]);
       if( year < 2007 )
       {
          printf("\nsyntax: %s year, with year >= 2007.\n", argv[0]);
          return -1;
       }
    
       second_sunday = secondSunday(year);
       printf("second_sunday=%d\n", second_sunday);
    
       return 0;
    }
    
    
    int secondSunday(year)
    {
       //On 03/14/2007, the day of the week is Wed, or 3.
       int no_years, no_leaps, day_of_week, second_sunday;
    
       no_years = year - 2007;
       no_leaps = (year - 2004)/4;
       day_of_week = 3 + (no_years + no_leaps) % 7;
       second_sunday = 14 - day_of_week;
       if( second_sunday < 8 ) second_sunday += 7;
    
       //printf("no_years=%d,no_leaps=%d,day_of_week=%d, second_sunday=%d\n",
       //no_years, no_leaps, day_of_week, second_sunday);
    
       return second_sunday;
    }
    /**************
       Compile via   cl.exe  second_sunday.c
    
       second_sunday.exe 2007
       second_sunday.exe 2008
       second_sunday.exe 2009
       second_sunday.exe 2010
       second_sunday.exe 2011
       second_sunday.exe 2012
       second_sunday.exe 2013
       second_sunday.exe 2014
       second_sunday.exe 2015
       second_sunday.exe 2016
       second_sunday.exe 2017
       second_sunday.exe 2018
       second_sunday.exe 2019
       second_sunday.exe 2020
       second_sunday.exe 2021
       second_sunday.exe 2022
       second_sunday.exe 2023
       second_sunday.exe 2024
       second_sunday.exe 2025
       second_sunday.exe 2026
       second_sunday.exe 2027
       second_sunday.exe 2028
       second_sunday.exe 2029
       second_sunday.exe 2030
       second_sunday.exe 2031
       second_sunday.exe 2032
    ***************/
    
    0 讨论(0)
  • 2021-01-31 11:19

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

    1. 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.
    2. The second Sunday in March will always be between the 8th and the 14th inclusive.
    3. The first Sunday in November will always be between the 1st and 7th inclusive.
    4. 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).

    0 讨论(0)
  • 2021-01-31 11:19

    I found this all very helpful. Brazil has some special issues, southern hemisphere, and sometimes Carnival overlaps the fall change date.

    In these cases, the legislature delays DST by one week. The US Naval observatory calculation can find easter, (at http://aa.usno.navy.mil/faq/docs/easter.php, retrieved 1/3/2017), and carnival is an exact number of days earlier, the week-end before ash wednesday (Mardi Gras means "fat tuesday").

    So, in C:

        static const uint8_t carnival[] = {
        0x04, 0x24, 0x24, 0x21, // 2000... 2031 
        0x01, 0x09, 0x48, 0x09, // 2032... 2063
        0x4a, 0x40, 0x4a, 0x52, // 2064... 2095
        0x02, 0x90, 0x12, 0x94  // 2096... 2127
        }
    
    /* Returns the current time offset. */
    
    int dst(struct tm *tm_ptr)
    {
    
        int st = 0;
        int dst = 60;
        int mon = tm_ptr->tm_mon;
        int mday, previous_sunday;
        int gmt_offset = tm_ptr->gmt_offset;
    
        // If not Brasilia or Amazon time, no DST.
        if(gmt_offset != -240 && gmt_offset != -300)
            return st;
    
        if(NOV < mon || FEB > mon) // Summer?
            return dst;
        else if(NOV > mon && FEB < mon) // Winter?
            return st;
    
        mday = tm_ptr->tm_mday;
    
        previous_sunday = mday - tm_ptr->tm_wday;
        // Begin DST on first Sunday of November.
        if(NOV == mon) // If it's November... i.e. spring, so forward
        {
            if(previous_sunday < 1) // Before Sunday, week 1?
            {
                return st;
            } else { // After or during Sunday, week 1
                return dst;
            }
            // End DST in February, accounting for Carnival.
        } else { // It has to be February, i.e. fall, so backward.
            int year, week_start;
    
            year = tm_ptr->tm_year;
            if(0 == (carnival[year/8] & (1 << (year%8))))
                week_start = 15; // 3rd Sunday is not in Carnival.
            else
                week_start = 22; // Use 4th Sunday, 1 week after Carnival.
    
            if(previous_sunday < (week_start-1))
                return dst;
            if(previous_sunday < week_start) {
                if(tm_ptr->tm_isdst == st) // if it already fell backward, stay.
                    return st;
                return dst;
            }
            // On or after the correct Sunday?
            return st;
        }
    }
    
    0 讨论(0)
提交回复
热议问题