Home:ALL Converter>Calculating daylight saving time from only date

Calculating daylight saving time from only date

Ask Time:2011-04-08T12:27:22         Author:Muggz

Json Formatter

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?

Author:Muggz,eproduced under the CC 4.0 BY-SA copyright license with a link to the original source and this disclaimer.
Link to original article:https://stackoverflow.com/questions/5590429/calculating-daylight-saving-time-from-only-date
captncraig :

This is actually deceptively simple. There are a few facts that will help us:\n\n\nIn 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.\nThe second Sunday in March will always be between the 8th and the 14th inclusive.\nThe first Sunday in November will always be between the 1st and 7th inclusive.\nThe day of week numbering is quite convenient because the day - day of week will give you the previous Sunday.\n\n\nThese facts lead to the following code (C#, but trivially portable to your platform):\n\n public bool IsDST(int day, int month, int dow)\n {\n //January, february, and december are out.\n if (month < 3 || month > 11) { return false; }\n //April to October are in\n if (month > 3 && month < 11) { return true; }\n int previousSunday = day - dow;\n //In march, we are DST if our previous sunday was on or after the 8th.\n if (month == 3) { return previousSunday >= 8; }\n //In november we must be before the first sunday to be dst.\n //That means the previous sunday must be before the 1st.\n return previousSunday <= 0;\n }\n\n\nIt 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.\n\nI 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).",
2011-04-08T04:40:59
akworob :

Code for Central Europe (tested for every day in range 2014-3000 year)\n\n public static bool IsDst(int day, int month, int dow)\n {\n if (month < 3 || month > 10) return false; \n if (month > 3 && month < 10) return true; \n\n int previousSunday = day - dow;\n\n if (month == 3) return previousSunday >= 25;\n if (month == 10) return previousSunday < 25;\n\n return false; // this line never gonna happend\n }\n\n\nTest function\n\n static void Main(string[] args)\n {\n TimeZoneInfo tzf2 = TimeZoneInfo.FindSystemTimeZoneById(\"Central Europe Standard Time\");\n\n var date = new DateTime(2014, 01, 1, 5, 0,0);\n bool wasSummer = false;\n\n while (date <= new DateTime(3000,1,1))\n { \n var dow = (int) date.DayOfWeek;\n\n var isDst = IsDst(date.Day, date.Month, dow); \n\n DateTime f2 = TimeZoneInfo.ConvertTime(date, tzf2);\n var isSummer = f2.IsDaylightSavingTime();\n\n if (isSummer != isDst)\n {\n Console.WriteLine(\"ERROR\");\n Console.WriteLine(date);\n }\n\n if (isSummer != wasSummer)\n {\n Console.WriteLine(date.AddDays(-1).ToShortDateString());\n }\n\n date = date.AddDays(1);\n wasSummer = isSummer;\n }\n\n Console.ReadKey();\n\n\n}",
2014-03-31T12:46:37
Anomie :

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.\n\nIn 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.\n\nBut 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).",
2011-04-08T05:13:26
Grog Klingon :

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

March 14th and November 7 are always part of the week that the day light savings occur in the united states.. they may be the Sunday or the Saturday or and day of the week in-between but they are always part of that week. the code below will find the Sunday of that those two dates are part of in the year that the date in question occurs in. it then adds 2 hours to this date to get the time in which the daylight savings actually occur. you then compare the date in question against the daylight savings beginning and end dates and adjust the time by the gmt offset. This process can work for other countries begin and end dates. you could setup a table that has every country code and postal code in it with daylight savings end and begin dates and the gmt offset for both periods. the dates would be the 7th, 14th, 21th, and 28th, for the first through forth Sundays of a month. you would put in the max day in for the last Sunday of the month ex Sep 30th or Oct 31st. \n\n2nd Sunday in March:\n\ncdate(\"3/14/\" & format(now(),\"yyyy\"))-format(cdate(\"3/14/\" & format(now(),\"yyyy\")),\"W\")+1+2/24\n\n\n1st Sunday November:\n\ncdate(\"11/7/\" & format(now(),\"yyyy\"))-format(cdate(\"11/7/\" & format(now(),\"yyyy\")),\"W\")+1+2/24\n\n\nEx.\n\nIf(now() < cdate(\"3/14/\" & format(now(),\"yyyy\"))-format(cdate(\"3/14/\" & format(now(),\"yyyy\")),\"W\")+1+2/24, dateadd(\"H\",-5,now()), if(now() < cdate(\"11/7/\" & format(now(),\"yyyy\"))-format(cdate(\"11/7/\" & format(now(),\"yyyy\")),\"W\")+1+2/24, dateadd(\"H\",-6,now()), dateadd(\"H\",-5,now())))\n\n\nt_SQL example\n\nCASE WHEN [date2check] < DATEADD(hh, 2, CAST('3/14/' + CAST(DATEPART(yyyy, [date2check]) AS nvarchar(4)) AS datetime) \n + 1 - DATEPART(w, CAST('3/14/' + CAST(DATEPART(yyyy, [date2check]) AS nvarchar(4)) AS datetime))) THEN dateadd(hh, - DST_GMT_TM_ZN_DIFF, \n [date2check]) ELSE CASE WHEN [date2check] < DATEADD(hh, 2, CAST('11/7/' + CAST(DATEPART(yyyy, \n [date2check]) AS nvarchar(4)) AS datetime) + 1 - DATEPART(w, CAST('11/7/' + CAST(DATEPART(yyyy, [date2check]) AS nvarchar(4)) \n AS datetime))) THEN dateadd(hh, - STD_GMT_TM_ZN_DIFF, [date2check]) ELSE dateadd(hh, - DST_GMT_TM_ZN_DIFF, \n [date2check]) END END",
2015-09-29T21:11:58
Ed Truong :

I am trying with this approach and I think it simple and accurate:\n\n// for first Sunday of March as if DoW = 1 for Sunday\nif (month==3 && day>=8 && day <=14 && DoW=1) return True \n\n// for second Sunday of Nov as if DoW = 1 for Sunday\nif (month==11 && day>=1 && day <=7 && DoW=1) return True ",
2015-11-09T23:04:59
user35060 :

Here is my answer, and I welcome any corrections. It is assumed that the years are between 2000 and 2099 inclusive. Further details available via the reference link.\n\n int timezone = 0; // Set to correct initial value depending on where you are (or via GPS if you like).\n // Calculate day of week for Daylight savings time.\n int day_of_week = (day_of_month + int(2.6 * (((month + 12 - 3) % 12) + 1) - 0.2) - 40 + \n (month < 3 ? year-1 : year) + int((month < 3 ? year-1 : year)/4) + 5) % 7;\n // Adjust timezone based on Daylight savings time for northern hemisphere, USA\n if ((month > 3 && month < 11 ) || \n (month == 3 && day_of_month >= 8 && day_of_week == 0 && hour >= 2) || // DST starts 2nd Sunday of March; 2am\n (month == 11 && day_of_month < 8 && day_of_week > 0) ||\n (month == 11 && day_of_month < 8 && day_of_week == 0 && hour < 2)) { // DST ends 1st Sunday of November; 2am\n timezone++;\n }\n\n\nDay of Week calculation reference: How to determine the day of the week, given the month, day and year\nDST test reference is via this article as answered by captncraig and my own reasoning and interpretation of his answer.",
2016-01-03T16:38:40
rgvandewalker :

I found this all very helpful. Brazil has some special issues, southern hemisphere, and sometimes Carnival overlaps the fall change date.\n\nIn 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\").\n\nSo, in C:\n\n static const uint8_t carnival[] = {\n 0x04, 0x24, 0x24, 0x21, // 2000... 2031 \n 0x01, 0x09, 0x48, 0x09, // 2032... 2063\n 0x4a, 0x40, 0x4a, 0x52, // 2064... 2095\n 0x02, 0x90, 0x12, 0x94 // 2096... 2127\n }\n\n/* Returns the current time offset. */\n\nint dst(struct tm *tm_ptr)\n{\n\n int st = 0;\n int dst = 60;\n int mon = tm_ptr->tm_mon;\n int mday, previous_sunday;\n int gmt_offset = tm_ptr->gmt_offset;\n\n // If not Brasilia or Amazon time, no DST.\n if(gmt_offset != -240 && gmt_offset != -300)\n return st;\n\n if(NOV < mon || FEB > mon) // Summer?\n return dst;\n else if(NOV > mon && FEB < mon) // Winter?\n return st;\n\n mday = tm_ptr->tm_mday;\n\n previous_sunday = mday - tm_ptr->tm_wday;\n // Begin DST on first Sunday of November.\n if(NOV == mon) // If it's November... i.e. spring, so forward\n {\n if(previous_sunday < 1) // Before Sunday, week 1?\n {\n return st;\n } else { // After or during Sunday, week 1\n return dst;\n }\n // End DST in February, accounting for Carnival.\n } else { // It has to be February, i.e. fall, so backward.\n int year, week_start;\n\n year = tm_ptr->tm_year;\n if(0 == (carnival[year/8] & (1 << (year%8))))\n week_start = 15; // 3rd Sunday is not in Carnival.\n else\n week_start = 22; // Use 4th Sunday, 1 week after Carnival.\n\n if(previous_sunday < (week_start-1))\n return dst;\n if(previous_sunday < week_start) {\n if(tm_ptr->tm_isdst == st) // if it already fell backward, stay.\n return st;\n return dst;\n }\n // On or after the correct Sunday?\n return st;\n }\n}\n",
2019-07-08T18:37:17
yy