Daylight savings problem

There is a function Time.format() that will do the formatting for your by means of strftime() format place holdes.

What you are doing can be written like this

  Serial.println(Time.format("%I:%M:%S"));
3 Likes

@ScruffR,

Well, it is almost that time again. We go off Daylight savings on November 2nd. I have followed the links in this and other DST posts and it seems that the goal of automatically recognizing daylight savings time has not yet been realized.

That said, for a specific use case (cellular stationary devices that have their timezone entered once at installation) is it fair to say there is a solution using the API calls you reference above (setDSToffset, beginDST, endDST and isDST)?

Is there a good example sketch for this or should I create one and share for comment? If so, would it make sense to start a new thread?

Thanks, Chip

I hoped these functions would become useful some time but IMO these functions are not really.
You as developer have to set the offset, and then call beginDST() and endDST() when it's time to switch. They don't help you in any shape or form to actually distinguish whether it is time to switch or not nor does the device store the last state across resets.
That's still entirely up to the dev hence it's no real difference to just setting Time.zone(x + dstOffset).
Hence I just implemented my own bool isDST() function that calculates my local switching date and regularly (just after UTC 1:00am every day) call Time.zone(+1.0 + (isDST() ? 1.0 : 0.0)).

@ScruffR,

I see, so these API names are a bit misleading. I would think that a mature platform such as Particle would have settled this issue long ago.

I am going to write a sample sketch for this so, the flow will be:

  1. Store the timezone value in FRAM / EEPROM - -5 for me looks like +1 for you

  2. Modify your isDST function for my country - 2nd Sunday in March, +1 hour. - 1st Sunday in November as DST, +0 hour. Both the calendar values and the DST offset are different by country. So, I might use your code and create isDSTusa()

  3. Once a day, run the code: Time.zone(+1.0 + (isDSTusa() ? 1.0 : 0.0)) .

One question: If all you are doing is setting Time.zone - you don’t have to be connected correct?

Thanks,

Correct - providing the time was synced at some point before to actually being able to know its 1am UTC :wink:

I would have hoped so too :pensive:

@ScruffR,

I took a whack at modifying your isDST function for use in the United States. I have created a simple test sketch that seems to work and posted it to Github:

I made use of the standard Particle functions isDST, beginDST, endDST so I have a slightly different syntax:

if (Time.isValid()) 
  { // We only want to run this if time is valid - otherwise random result
    isDSTusa() ? Time.beginDST() : Time.endDST();       
  }

Comments / suggestions / criticisms are welcome. I hope that other folks will find this useful as that change over is coming up.

Thanks,

Chip

1 Like

I don’t have any products in use in the US so not had to tackle this. Have done for Europe (essentially all countries in timezones 0.0, +1.0, +2.0 except for Iceland all change last Sunday of October and last Sunday of March. We have DST and TZ as a remotely set variables as well as an auto mode for DST that works for Europe. In theory you can get this DST and time zone information from knowing your location and through a google api / website.

I think I based my checking on the same algorithm as @Scruffr but use a switch case conditional logic instead of if’s. I also check more frequently for changes since the check is quick. The bool function below is called from a millis() time check and only if Time.isValid()! The return value is used to inform the web app that the time has been changed.

// returns true or false should DST changed event be sent V155
// 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();
            return true;
        }
        else if (!shouldDSTbeEnabled && Time.isDST())       //if it should be off but is on
        {
            Time.endDST();
            return true;
        }
        else
        {
            return false;
        }
    }
    else
    {
        return false;
    }
}
2 Likes

There is a particle library I use that abstracts the pain …

I also have a function exposed to update the timezone manually if for example the device is behind a corporate firewall and the exit point is in another time zone.

3 Likes

I have just seen this - wow - this is a clever piece of work. Is it reliable?

Working nicely so far … :slight_smile:

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