How to implement daylight saving?

General discussion on mikroC PRO for PIC.
Post Reply
Author
Message
aCkO
Posts: 1119
Joined: 14 Feb 2011 04:07
Location: Bar, Montenegro

Re: How to implement daylight saving?

#3 Post by aCkO » 30 Jun 2014 01:52

Actually, this is a lot simpler than it might seem. As Dany already noted, you should keep the clock running as if it were GMT and add the necessary offset based on the DST settings. This way you can make your RTC app location independent, i.e. you get "world clock" functionality.

It all comes down to determining the dates of DST changes (for CET this is the last Sunday of March and the last Sunday of October). Obviously, the last Sunday will be between 25th and 31st of those months. So, for an arbitrary date and day of the week, calculating the date of previous Sunday will determine the DST flag. If we (conveniently) mark the days of the week like Sunday=0, Monday=1,..., Saturday=6, then our calculation of the previous Sunday becomes:

Code: Select all

PrevSunday = Day - DayOfTheWeek;
Our DST function then becomes:

Code: Select all

short IsDST(short day, short month, short dow) {
   if (month < 3 || month > 10) return 0;
   if (month > 3 && month < 10) return 1;
   
   if (month == 3) return day - dow >= 25;
   return day - dow < 25;
}
And that's it :) Of course, if the day of the week is Sunday and the current date is between 25th and 31st of March/October, you will also need to check if time is >= 2AM, but I will leave that to you. :-)

Also, most RTC chips have DayOfTheWeek register, but you can also calculate it from the date (day, month and year):

Code: Select all

int dow(int y, int m, int d) {
   int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
   y -= m < 3;
   return (y + y/4 - y/100 + y/400 + t[m-1] + d) % 7;
}
or more compact version:

Code: Select all

int dow(int y, int m, int d) {
   return (d += m<3 ? y-- : y-2, 23*m/9 + d + 4 + y/4 - y/100 + y/400) % 7;
}
As in the previous example, Sunday=0, Monday=1, etc.

Regards

Dany
Posts: 3854
Joined: 18 Jun 2008 11:43
Location: Nieuwpoort, Belgium
Contact:

Re: How to implement daylight saving?

#4 Post by Dany » 30 Jun 2014 10:12

Code: Select all

short IsDST(short day, short month, short dow) {
   if (month < 3 || month > 10) return 0;
   if (month > 3 && month < 10) return 1;
   
   if (month == 3) return day - dow >= 25;
   return day - dow < 25;
}
Does this also work well if the last sunday of the month e.g. equals the 28th in stead of the 25th? I assume it does, but I do not see how it works...
Kind regards, Dany.
Forget your perfect offering. There is a crack in everything, that's how the light gets in... (L. Cohen)
Remember when we were young? We shone like the sun. (David Gilmour)

aCkO
Posts: 1119
Joined: 14 Feb 2011 04:07
Location: Bar, Montenegro

Re: How to implement daylight saving?

#5 Post by aCkO » 30 Jun 2014 13:15

When you subtract (day - dow), you get the previous Sunday. If the result is between 25th and 31st (or simply >=25) then it is definitely the last Sunday of the month, so DST flag is on.
Let's say the last Sunday is 28th of March:

Code: Select all

Fri 26th  =>  dow = 5  =>  return (26 - 5 >= 25)  =>  False
Sat 27th  =>  dow = 6  =>  return (27 - 6 >= 25)  =>  False
Sun 28th  =>  dow = 0  =>  return (28 - 0 >= 25)  =>  True
Mon 29th  =>  dow = 1  =>  return (29 - 1 >= 25)  =>  True
Tue 30th  =>  dow = 2  =>  return (30 - 2 >= 25)  =>  True
Wed 31st  =>  dow = 3  =>  return (31 - 3 >= 25)  =>  True
Regards

Dany
Posts: 3854
Joined: 18 Jun 2008 11:43
Location: Nieuwpoort, Belgium
Contact:

Re: How to implement daylight saving?

#6 Post by Dany » 30 Jun 2014 16:56

aCkO wrote:When you subtract (day - dow), you get the previous Sunday. If the result is between 25th and 31st (or simply >=25) then it is definitely the last Sunday of the month, so DST flag is on.
Regards
Nice! Thanks :D :D
I did already suspect I did not see the working of your code due to my limited C knowledge... :oops:
Kind regards, Dany.
Forget your perfect offering. There is a crack in everything, that's how the light gets in... (L. Cohen)
Remember when we were young? We shone like the sun. (David Gilmour)

Dany
Posts: 3854
Joined: 18 Jun 2008 11:43
Location: Nieuwpoort, Belgium
Contact:

Re: How to implement daylight saving?

#7 Post by Dany » 01 Jul 2014 10:29

Hi Acko, is it allowed for me to use the code you published in my own (mikroPascal) libraries (that are published under LibStock)? I will add a reference to your post(s) above. Thanks in advance! :D
Kind regards, Dany.
Forget your perfect offering. There is a crack in everything, that's how the light gets in... (L. Cohen)
Remember when we were young? We shone like the sun. (David Gilmour)

aCkO
Posts: 1119
Joined: 14 Feb 2011 04:07
Location: Bar, Montenegro

Re: How to implement daylight saving?

#8 Post by aCkO » 01 Jul 2014 13:32

Hi Dany,

Of course, feel free to use this code anywhere you like :-) I'm glad you found it useful to include it in your libraries :-D

Regards

Dany
Posts: 3854
Joined: 18 Jun 2008 11:43
Location: Nieuwpoort, Belgium
Contact:

Re: How to implement daylight saving?

#9 Post by Dany » 01 Jul 2014 20:03

aCkO wrote:Hi Dany,

Of course, feel free to use this code anywhere you like :-) I'm glad you found it useful to include it in your libraries :-D

Regards
Thanks! :D

The mikroPascal code became:

Code: Select all

function RTC2Dst(Day, Date, Month: byte): boolean;
// see http://www.mikroe.com/forum/viewtopic.php?f=88&t=30565&start=2
var TmpDate, TmpMonth: byte; // decimal versions of the parameters
    I, TmpDay, Tmp: byte;
    SunDayFound: boolean;
begin

  // Transitions occur at
  // The last sunday of March (no DST --> DST) and
  // the last sunday of October (DST --> no DST)
  // Both transitions occur between dates 25..31 inclusive

  Result := false; // no DST (normal time)

  TmpMonth := BCD2DEC(Month); // make binary format

  if (TmpMonth < 3) or (TmpMonth > 10) then // no DST for sure
  begin
    // Result := false;
    exit;
  end;

  if (TmpMonth > 3) and (TmpMonth < 10) then // DST for sure
  begin
    Result := true;
    exit;
  end;


  // The month apparently is March or October, do the calculation

  TmpDate := BCD2DEC(Date);  // make binary format

  // ------------- the Acko solution -------------------------------------------
  // --- see http://www.mikroe.com/forum/viewtopic.php?f=88&t=30565&start=2 ----

  if Day = 7 then Day := 0; // Sunday needs to be zero for this calculation
  // here 0 = Sunday, 1 = Monday etc...

  Tmp := TmpDate - Day;

  if (TmpMonth = 3) then
  begin  // month = March
    if (Tmp >= 25) then // already summertime
    begin
      Result := true;
      exit;
    end;
  end
  else
  begin //  month = October
    if (Tmp < 25) then  // still summertime
    begin
      Result := true;
      exit;
    end;
  end;

end;
The above code could be written more dense I suppose, but it shows clearly what happens. See also the code (http://www.mikroe.com/forum/viewtopic.p ... 65&start=2) and explanation (http://www.mikroe.com/forum/viewtopic.p ... 65&start=4) provided by aCkO.
Kind regards, Dany.
Forget your perfect offering. There is a crack in everything, that's how the light gets in... (L. Cohen)
Remember when we were young? We shone like the sun. (David Gilmour)

Post Reply

Return to “mikroC PRO for PIC General”