Dealing With Daylight Saving Time on DS3231

Hello folks, please tell me about usable libraries for DS3231 RTC to deal with DST.

I've got several projects on the go, all of which have the above RTC and I've successfully used RTClib.h. to get the correct date and time . I'm in time zone 0 (i.e. UTC). I now want to be able to deal with the spring and autumn adjuectment to the clock.

I can easily calculate when to make DST active by something like:
........ Check if date is between 26/3 and 31/3
.........If so, check if dayOfWeek is 1 (i.e. Sunday)
.........If it's Sunday, set a variable called DSTactive to = 1, else do nothing
.........If DSTactive=1 , then do something to make sure RTC is incremented by 1 hour.
-and obviously, the reverse of this in November.

I appreciate that this logic would trigger a change at midnight not the UK official 2am, but can live with that.

How do I get the DS3231 to increment or decrement its hour value just the once? I'm happy to use a different library if necessary?

I've looked at time.h and timeZone.h but neither seem to float my boat. Ideally I just want a functiont that tells the RTC to sort itself out.

Many thanks.

You need to detect when the date becomes in the range that you are testing for rather than when it is in the range that you are testing for

er, okay.

Deciding when to adjust is less of a problem to me than how to adjust the RTC.

But I'd be grateful for any ideas/code on how to do it.

A discussion with a variety of solutions occurred here

a7

That is not what you originally said>

How do I get the DS3231 to increment or decrement its hour value just the once?

rtc.setHour(now.hour() + 1);?

What Arduino?

For the AVR processors, I use the Jeelabs/Adafruit library, because it's so easy to set the RTC to UTC and produce local time:

const int DST = 1; // 0 for EST and 1 for EDT
...
DateTime getLocalTime() {
  DateTime now = rtc.now();
  DateTime localNow = now + TimeSpan(0, -5 + DST, 0, 0);
  return localNow;
}

Additionally, hidden in AVR-GCC, are two simple time functions that tell you if daylight savings time is in effect. In the code above, I don't use it, but it's included in the calculations and I can set or clear it manually.

Sometimes I post and realize how lazy I was, so I updated it:

const int DST = 1; // 0 for EST and 1 for EDT
const int ZONE = -5; // EST/EDT - New York etc.
...
DateTime getLocalTime() {
  DateTime now = rtc.now();
  DateTime localNow = now + TimeSpan(0, ZONE + DST, 0, 0);
  return localNow;
}

For reasons of synchronization as well as avoiding certain local time setting stumbling blocks, it is almost always better to set the RTC to UTC time and calculate the offset for local use.

I think I've seen the thread referred to by alto777 and also several other similar ones. They all seem to concentrate on one of the following:

  • Code to calculate when to change
  • Using a look up table to decide when to change
  • Using NPT, GPS or some other source over WiFi or network

I've got that covered, as noted above. But nothing I can find tells me now to increment or decrement once only, at some time around just after midnight on the correct day.

It's a pity that the DS3231 doesn't have a parameter to set, saying if TRUE, add on one hour, but if it does, I can't find it.

Reply #7 tells you how to increment. The functions I mentioned tell you when to increment.

If you happen to be dead-set on setting your RTC to local time, I can't help you at all. It messes up the logic too much.

In fact, you can use the TimeSpan class to add/subtract DST time from a local time, but if you want to play with that, you are on your own.

I guess we understand the English language differently and hope my later posts clarify. Bottom line - I don't need to care about in or becomes in range. I just need to figure how to increment or decrement once.

How can you increment or decrement time once? It is constantly changing.

Functions exist in most RTC libraries to set and adjust the time. Can you not use those, even if your insistence on using local time is questionable?

Did you miss

See the StateChangeDetection example in the IDE and adapt it

Your approach is misguided. What if the device is turned off when the DST time change passes? When you turn it on, how will it know whether DST is in effect (EDIT has been adjusted) or not? It's not possible to pull this off without one or many kludges.

1 Like

Okay, I now see why so many times this subject seems to result in a thread that bounces around before hitting a dead end or petering out without a solution. My apologes for opening the can of worms again.

I'll start again and see if I can be really clear with the requirement and what I know how to do:

  • DST comes around last Sunday in March and reverts last Sunday in October every year.
  • I need a usable time, don't care if it comes direct from RTC or is somehow adjusted in code.
  • I'm not committed to the idea of changing RTC, it just seemed the simplest idea. Obviously not.
  • I have zero problem in deciding when to make the change(s). That bit is easy.
  • I have no problem in how to change the RTC (if necessary). That bit is easy.
  • I do have a problem is just adding on one hour in code, worried that there is a rollover issue with a 25th hour. If that's not the case, someone please tell me. Hence why I assumed changing the RTC (once) was simplest.
  • As previously mentioned, I've looked at the timeZone library and found nothing useful. I'm in Zone 0, UTC so don't need the complexity.
  • I was not aware of the TimeSpan option, thanks for that. Is it in native Arduino, or does it need another library?

At the moment I have solution in mind but it's very, very clunky. I would decide when to increment or decrement the RTC, move it by one hour and set a flag to indicate I've done it once. It just seems a shame to have this running in the loop, over and over, multiple times a second all year long. Hey ho.

Well, I can see how this is going so it will be my last comment. MCU do not charge by the hour for their time. It's free. But for the sake of argument, I use something like this in all my clocks:

  // 20 Hz display frame rate
  nowMillis = millis();
  if (nowMillis - updateMillis >= 50)
  {

so that time checks are not performed every millisecond, unless I really need it.

At the moment I have solution in mind but it's very, very clunky.

I'll be straightforward. That is absolutely true, and you should consider why the standard approach is the one that is almost universally uses. But it's not the implementation that is clunky, it's the concept.

My approach may be misguided to your mind. I'd welcome a contribution of something workable rather than just criticism.

I posted a complete solution. Welcome to my permanent ignore list. I will not see any of your replies.

1 Like

No you didn't, but I'll thoroughly enjoy not having to weed out your comments in future. Looks like a win-win for both of us.

You really need to store in eeprom the current state of the clock, whether it is in DST or not, otherwise there is no way to know at startup what state the clock is in. Easier to leave the clock alone and adjust for DST offset in the code.

Something like this maybe to add 1 hour

rtc.adjust(rtc.now() + TimeSpan(0, 1, 0, 0));

Similar for subtracting an hour.

Problem is, as already pointed out, the RTC doesn't know which time zone it is set for, so your code needs to store that somewhere that's non-volatile. Unfortunately, unlike the older DS1302, the otherwise superior DS3231 doesn't have any spare NVRAM you can use to store something like timezone in. Many Arduino have EEPROM, or can simulate it with an area of Flash memory, so that's another possibility.

Or, as also pointed out, keep your RTC permanently on UTC+0 and add one hour during BST.