Daylight savings problem

Hi all,

I am newbie from Belgium to this forum and wanted to share this piece of code I used for a few years to solve this issue on a particle core.
I didn’t find how to post code in a nice gray background so forgive me posting it as plain text.

The original formula is from the following site :

http://delphiforfun.org/programs/math_topics/dstcalc.htm
in my application it changes the setting on midnight, so not on 2 or 3 .

//zomert is a bool, false when wintertime is active and true when summertime is active 

  switch (zomert)   // check summer / winter time
 { 
  case false: // if current setting is winter
    if ( ((Time.day() >= (31-(((5*Time.year()/4)+4)%7))) and (Time.month() == 3 )) or ((Time.month() < 10) and (Time.month() > 3)) )
   {
     // summer time
     zomert = true;
     zoneUTC=2;
     Time.zone(+2);
     Particle.syncTime();
     delay(2000);
   }
   break;
   
   case true: // if current setting is summer
    if ( ((Time.day() >= (31-(((5*Time.year()/4)+1)%7))) and (Time.month() == 10 )) or ((Time.month() < 3) or (Time.month() > 10)))
    {
      // winter time
      zomert = false;
      zoneUTC=1;
      Time.zone(+1);
      Particle.syncTime();
      delay(2000);
    }
   break;    
 }

regards,
Ronny

1 Like

I have reformatted your code block.
To achieve the same thing you can use this icon image or you use the edit option (image ) on your own post and see what I added before and after your code to achive the same thing (with the extra formatting hint cpp).

Ronny

There are fully working and tested functions above in this topic thread which you could also use/study and that use the Time.isDST() and Time.beginDST() rather than move the Timezone!
What help are you after?

Hi Armor,
I will look at the functions above, i don’t have a specific problem, I just wanted to share my code that I’ve been using for a few years to tackle the daylight saving problem
Kind regards

1 Like

Thanks ScruffR for the explanation and the edit, will do it that way next time😉

1 Like
bool isDST(int day, int month, int dayOfWeek) {
        if (month < 3 || month > 10) {
                return false;
        }
        if (month > 3 && month < 10) {
                return true;
        }
        int previousSunday = day - dayOfWeek;
        if (month == 3) {
                return previousSunday >= 25;
        }
        if (month == 10) return previousSunday < 25; {
                return false;
        }
}

The biannual Particle DST problem has again bitten me in the botty! :rofl: :rofl:
The above code isn’t working for the UK DST ended at 02:00 on Sunday 25 October…

Can anyone who is in the UK share what’s working for them?

Thanks!!!

I'm not in the UK, but have ties :wink:
You can have a look at my code I suggested in the fourth post in this thread :sunglasses:

This is the line you need to adapt for BST

:rofl: I have a feeling this is going to just plague me twice yearly and I’m never going to programmatically “solve” it :laughing:

I implemented this about 8 days ago, and for a while, it worked!

Time.zone(IsDST(Time.day(), Time.month(), Time.weekday()) ? 0 : 1);
this after my loop

bool IsDST(int day, int month, int dayOfWeek)
{
  if (month < 3 || month > 10)
  {
    return false;
  }
  if (month > 3 && month < 10)
  {
    return true;
  }
  int previousSunday = day - dayOfWeek;
  if (month == 3)
  {
    return previousSunday >= 25;
  }
  if (month == 10) return previousSunday < 25;
  {
    return false;
  }
}

and what’s weird is…it worked for a few days. Now it doesn’t work again. It fell over on the first day of November I note.

ScruffR, I’ll take a look at your solution in the fourth post on the thread! :wink:

thanks

I know the feeling!! :persevere: So, I took a look around a while back and found this post which helped me a great deal:
https://stackoverflow.com/questions/5590429/calculating-daylight-saving-time-from-only-date

In particular, this quote:

  1. The day of week numbering is quite convenient because the day - day of week will give you the previous Sunday.

What the author does is subtract 1 from "dayOfWeek" giving:

Sunday 0 .. Saturday 6.

instead of

Sunday 1 .. Saturday 7

I have not run anybody else's code to test but I have been using this routine below. It has been working for me. I hope it can illustrate a solution for you.

const int g_timeZone = -8; //  Pacific Standard Time Zone from UTC
uint32_t g_timeNow = Time.now();    //  save current Time snapshot


Time.zone(g_timeZone + (isDaylightSavingsTime() ? 1.0 : 0.0));    
//  set proper zone according to Standard or Daylight Savings regs
//  Now, time is accurate for present day

//   your code .....

bool isDaylightSavingsTime()  { // Daylight Saving Time starts on the 
                                // second Sunday in March of every year and ends on the first          
                                // Sunday in November.
  int dayNow = Time.day(g_timeNow);
  int monthNow = Time.month(g_timeNow);
  int dayOfWeekNow = Time.weekday(g_timeNow) - 1; // Sunday 0 .. Saturday 6
  int previousSunday = dayNow - dayOfWeekNow;
  
  switch (monthNow) {
    case 1:             //  Jan, Feb and Dec are definitely standard time
    case 2:
    case 12:
      return false;

    case 4:             //  Apr to Oct are definitely DST
    case 5:
    case 6:
    case 7:
    case 8:
    case 9:
    case 10:     
      return true;
    
    case 3:                         //  March       
      if (previousSunday >= 8) {    //  today is 2nd Sunday or later
        return true;
      }                   
      return false;                 //  today is before 2nd Sunday

    case 11:                        //  November        
      if (previousSunday <= 0) {    //  today is before 1st Sunday   
        return true;
      }                    
      return false;                 //  today is 1st Sunday or after

  } //  END switch
  return false;   //  switch statement should have returned before now

}   //  END isDaylightSavingsTime  
2 Likes

This works for me in the UK and currently all EU states.

// returns true or false should DST changed event be sent
// according to the time zone if (0.0(exc. Iceland), +1.0, +2.0) Europe exc. Russia/Belarus
// essentially from the last Sunday in March to the last Sunday in October DST is enabled at UTC 01.00 -> 02.00 and disabled at UTC 02.00 -> 01.00
// automatically begins DST at UTC 01.00 or ends DST at UTC 02.00
bool isDSTactive()
{
    float tz = Time.zone();                                 //offset from UTC
    int dayOfMonth = Time.day();
    int hour = ((Time.now() % 86400) / 3600);
    int month = Time.month();
    int dayOfWeek = Time.weekday() - 1;                     //make Sunday 0 .. Saturday 6
    bool shouldDSTbeEnabled = false;                        //not in European time zones for which coded DST rules apply by default
    if (tz == 0.0 || tz == 1.0 || tz == 2.0)                //European time zones (WET/GMT, CET, EET)
    {
        switch (month)
        {
            case 1:                                         //Jan, Feb, Nov and Dec are definitely standard time
            case 2:
            case 11:
            case 12:
                shouldDSTbeEnabled = false;
                break;
            case 4:                                         //Apr to Sep definitely DST
            case 5:
            case 6:
            case 7:
            case 8:
            case 9:
                shouldDSTbeEnabled = true;
                break;
            case 10:                                        //March and October need deeper examination
            case 3:
                if (!(dayOfMonth - dayOfWeek > 24))         //but before switching Sunday     
                {
                    shouldDSTbeEnabled = (month == 10);     //for October DST will be true, for March not
                }
                else if (dayOfWeek > 0)                     //after the switching Sunday (dayOfWeek !=)
                {
                    shouldDSTbeEnabled = (month == 3);      //for March DST is true, for October not
                }
                else                                        //switching Sunday (dayOfWeek = 0)
                {
                    if (hour >= 1 && month == 3)  shouldDSTbeEnabled = true; //time is 01:00 or later on switching sunday in march then DST should be ON
                    if (hour >= 2 && month == 10) shouldDSTbeEnabled = false; //time is 02:00 or later on switching sunday in october then DST should be OFF
                }
                break;
        }
        //then if a change condition check if switch required from current setting
        if (shouldDSTbeEnabled && !Time.isDST())            //if it should be on but is off
        {
            Time.beginDST();
            param.isDst = true;
            putParameters();
            return true;
        }
        else if (!shouldDSTbeEnabled && Time.isDST())       //if it should be off but is on
        {
            Time.endDST();
            param.isDst = false;
            putParameters();
            return true;
        }
        else
        {
            return false;
        }
    }
    else
    {
        return false;
    }
}
4 Likes

huge thanks - and then what do you do in loop()? Do you just call it once a day or something? I’m aware that the above needs ‘activating’ or calling, right?
Thanks!

From loop() I typically call a clockTimeUpdate() function as below using a millis() based timer. I normally do this every 20 seconds to keep the clock time responsive and near to the internet time.

This is only suitable for the Photon which has a RTC, for the GEN3 devices I have implemented an external RTC (DS3231).

void clockTimeUpdate()
{
    if (Time.isValid())             //only do this if RTC Time is valid
    {
        if (isDSTactive())         //true if changed, false if no change in DST - this is so it is only changed once
        {
            //publish event that DST has changed
        }
        //set clock time using formatted Time.now()
    }
    else
    {
        //if time is invalid then set clock time as not set
    }
}
1 Like

Yes, on a Gen 3 device, I call it once per day at the 1:00 am hour immediately after I synchronize the time with the Particle Device Cloud :

if (Particle.connected()) {
    Particle.syncTime();    
    waitUntil(Particle.syncTimeDone);
}
Time.zone(g_timeZone + (isDaylightSavingsTime() ? 1.0 : 0.0)); 

This is fantastic – handles the headache of setting Daylight Savings Time manually. Thanks for sharing!

And that would just be something like Time.zone(-1); (for end of DST) or endDST() ? Do those essentially the same thing? Doesn't really matter which one I choose?

So it would be

void clockTimeUpdate()
{
    if (Time.isValid())             //only do this if RTC Time is valid
    {
        if (isDSTactive())         //true if changed, false if no change in DST - this is so it is only changed once
        {
            beginDST();
        }
        //set clock time using formatted Time.now()
    }
    else
    {
        //if time is invalid then set clock time as not set
    }
}

I guess I don't see how using the above code I would ever turn DST off?

Thanks. Sorry for being dumb about this, I'm just really hoping after years of fiddling and frustration to finally knock this on the head this year!

I think @robc has posted a complete example of the function plus code for loop to actually make the change but his example is for Pacific standard time so I can't just transplant his example for my GMT example :slight_smile:

Actually scratch that. Surely if I just call your function isDSTactive every day at 03:00 in the morning I will be laughing? This is what I meant by

but I think I wasn't clear enough!! :slight_smile: :slight_smile:

And I need to initially set a time.zone in setup, right?

EDIT Right, I've implemented some of this code, just wondering if there's a way to test it on the hoof to avoid waiting until March to see if it works? Could I Particle Publish a new month to see if it all works?

EDIT2 Ahh... first hang up, I think I must be going about this wrong. Trying to call isDSTactive from TimeAlarms and I can't because it's a bool not a void. Oops.

EDIT3 So close...I'm getting errors that "param" was not declared in this scope nor putParameters.

Thanks all!

You can try using the statement Time.setTime() to make your test cases in your main loop. This will override the time set by the Particle Device Cloud. Print or publish your data after calling your DST calculating routine. Here are some examples:

// Set the time to 2014-10-11 13:37:42
Time.setTime(1413034662);

// Set the time to 2020-10-30 10:11:12           
Time.setTime(1604052672);                 // Unix timestamp calculator

// Set the time to 2020-11-05 20:21:22
Time.setTime(1604607682);                 // Unix timestamp calculator

This does work and this is where DST is turned off in March!
In terms of testing - if you stay un connected from the Cloud you can set the time manually (beaten to the answer) - with the Photon the onboard RTC will be reset and the time valid.

isDSTactive() can be converted from bool to void type. I only have it that way because I need to know when DST has been set on or off to send an event to the web based device management app.