Like many others, I have lots of projects that depend on time. Here in VA, the time changed from EST to EDT on Sunday the 11th at 2am. Everything in my house changed (except dumb items like the microwave) as normal, except for my Moteino’s, Arduino’s and Particle projects. I seen lots of others take various approaches to making this change transparent, so I thought I would try myself. What follows seems to work for me…I’ve tried to test it extensively.
This code works for me, and I know it’s not terribly optimized, but hey, for something that only runs twice a year, I’m ok with readability over minimum bytes or machine cycles. I found data for VA through 2029 and built a simple table. If you run this example, it will print whether or not you’re in DST (from a VA perspective), and then simply become a clock, counting by one second down the screen just to prove that it detected the right DST setting.
To make this work in my projects, I simply add this check to the routine in my existing code that does something on the hour (i.e., 9:00, 11:00, 13:00, 15:00, etc.). That way, I only check once an hour and I tried to write the code with as many shortcuts as possible to make the fewest comparisons needed.
typedef struct DSTStruct
{
int year;
int startDay; // DST start day in Mar
int endDay; // DST end day in Nov
} DST;
DST dst[] = { // Table data for Richmond, VA
12,0,0, // Year field holds # of elements
2018,11,4,
2019,10,3,
2020,8,1,
2021,14,7,
2022,13,6,
2023,12,5,
2024,10,3,
2025,9,2,
2026,8,1,
2027,14,7,
2028,12,5,
2029,11,4
};
void setup(void)
{
int rc;
Serial.begin(115200);
Time.zone(-5); // EST/EDT
rc = isDSTActive();
if (rc == 0)
{
Time.endDST();
Serial.println("DST not active");
}
else if (rc == 1)
{
Time.setDSTOffset(1.0); // Offset is 1 hour
Time.beginDST();
Serial.println("DST active");
}
else Serial.println("Error determining DST");
}
void loop(void)
{
Serial.println(Time.format("%r"));
delay(1000);
}
int isDSTActive(void)
{
int sDay, // Start day in Mar
eDay; // End day in Nov
if (Time.month() >= 4 && Time.month() <= 10) // Apr - Oct = EDT
return 1;
else if (Time.month() < 3 || Time.month() == 12) // Jan, Feb, Dec = EST
return 0;
if (!findYear(Time.year(), &sDay, &eDay)) // Did we find this year's data?
{
Serial.println("Error - couldn't find data for this year");
return 2;
}
switch (Time.month())
{
case 3: // March (spring forward)
if (Time.day() > sDay)
return 1;
else if (Time.day() == sDay && Time.hour() >= 2) // All changes occur at 2am
return 1;
else
return 0;
case 11: // November (fall back)
if (Time.day() < eDay)
return 1;
if (Time.day() == eDay && Time.hour() < 2) // All changes occur at 2am
return 1;
else
return 0;
}
}
bool findYear(int year, int *sDay, int *eDay)
{
int numItems = dst[0].year; // How many structure items?
for (int x = 1; x <= numItems; x++)
{
if (dst[x].year == year)
{
*sDay = dst[x].startDay;
*eDay = dst[x].endDay;
return 1; // Found current year's data
}
}
return 0;
}
I hope I commented enough so that everything is understandable. Comments welcome.