News:

PROTON pic BASIC Compilers for PIC, PIC24, dsPIC33

Main Menu

British summer time problem

Started by RGV250, Oct 30, 2021, 01:06 PM

Previous topic - Next topic

RGV250

Hi,
I am spending way too much beer on this problem and wondered if anyone else had done it or would welcome any thoughts they have.
I have made a clock with reclaimed parts and decided it would be nice to use a GPS module for the time as it will be outdoors and out of reach. The problem is that GPS uses UTC (Coordinated Universal Time) so twice a year it will be out by an hour.
The date this changes on is not fixed, it goes forward an hour on the last Sunday of March and back to normal on the last Sunday of October.
I am leaning towards using a lookup table with the year and the relevant day number in March and October.
I had thought of doing a routine where after day 24 of the relevant month it checks if the day is a Sunday and sets/resets a flag if so.

Regards,
Bob

trastikata

#1
Hi Bob,

Can you add a RTC chip to keep track of the calendar and sync the clock with the GPS? Some modules have the ZDA message from their internal RTC too.

I read somewhere the Europeans wanted to abolish the daylight savings time this or the following year - so if you wait a bit, the problem will be no longer existing  :).

RGV250

Hi,
I have just looked up the ZDA string, I will have a play with that tonight as that looks just like what I need. Also might add the RTC just to cover if I lose the signal.

I did find some code that set/reset a bit at the correct time but I was concerned if the clock was powered down over the time it changed it would not work.

Regards,
Bob

chris_cb_uk

Ouch, what a big issue for something so trivial! A long pole with a large lever switch to advance and retard the hour.
Joking aside you wouldn't need a RTC in addition? You can just read the date from the GPS NMEA data and refer that to a lookup table, the data includes day and month.  You can easily add year to the mix with a manual setting once you've programmed the Pic.

trastikata

Quote from: RGV250 on Oct 30, 2021, 04:01 PMHi,
I have just looked up the ZDA string, I will have a play with that tonight as that looks just like what I need. Also might add the RTC just to cover if I lose the signal.

If the ZDA message is not available, look at the RMC message's Date Stamp.

Dompie

Bob,
I've done this a few times with my clock projects:
I need a DSTbit as the only extra var
-Daily at 3:00 test whether it is March or October?
    -if yes, is day > 24 ( DSTbit=No and March) or >23 (DSTbit=Yes and October)?
      -if yes, is it sunday?
          -Eureka -if DSTbit=No then Hour=Hour+1 and set DSTbit
          -Eureka -if DSTbit=Yes then Hour=Hour-1 and clear DSTbit

Due to the DSTbit test in October the clock will only be changed once when passing 3:00

Johan

charliecoutas

I know this looks a bit long-winded, but it's the way I do it:

; Take the last 2 digits of the year and add a quarter onto itself. (04 + 1 = 5)
; Get the corresponding code for the month. (January = 6, February = 2, March = 2, etc. See month codes for details). July = 5
; Take the day. (=13)
; Add the numbers together (5 + 5 + 13 = 23)
; Take away 7 (or multiples of 7) until a number from 1-7 is left. (23 - 21 =2)
; This number corresponds to the day of the week. (0=Sunday, 1 = Monday, 2 = Tuesday, etc.)
                           
        a = (year_no / 4) + year_no
        Dec month_no                                                       ;lookupl starts at 0 not 1
        temp = LookUpL month_no,[6,2,2,5,0,3,5,1,4,6,2,4]
         If year_no // 4 = 0 Then                                        ;is this a leap year?
          If month_no < 2 Then                                          ;if so, is month Jan or Feb?
           Dec a                                                                   ;if so then we're too big by 1
          EndIf
         EndIf
        day_no = (day_no + a + temp) // 7                        ;modulus

        Inc month_no
        GMT = 1                                                                  ;assume GMT for now
       
; BST runs from the last Sunday in March until the last Sunday in October...
; BST adds 1 to the GMT hour
       
       Select month_no
        Case <3, >10                                                    ;must be GMT if outside this range
        Case 3                                                              ;in month of March
         If day_num > 24 Then                                     ;possible candidate?
            If day_num-Day_no > 24 Then
              Bump_hour()                                               ;inside BST zone now
              GMT = 0
            EndIf
         EndIf
        Case 10                                                         ;in month of October
             If day_num < 20 Or day_num - day_no < 25 Then              ;the 25th October is the earliest possible "last" Sunday in October     
                Bump_hour()                                             ;haven't reached last Sun in Oct yet, still in BST
                GMT = 0
             EndIf
        Case Else
          Bump_hour()                                                   ;everything else is BST zone
          GMT = 0
       EndSelect

; ---------------------------

RGV250

Hi Johan,
I had thought of something like that but I am a bit worried that if the power goes off at the time of the change it will not work. I am probably over thinking it??

Hi Charlie,
A lot to get my head around, am I right that will work if it is powered up in the middle of the BST?
What are the variable types?
What happens with the year if it is not divisible by 4 IE 2021 would give 5.25?
Trying to understand the codes for the months?
There is a bug in the leap year calc, 2100 is not a leap year, I bet your hoping you will be around then to fix it  :)

Regards,
Bob

Frizie

Quote from: Dompie on Oct 31, 2021, 10:57 AM-if yes, is day > 24 ( DSTbit=No and March) or >23 (DSTbit=Yes and October)?

Hé Dompie, can you tell me why you made a difference for the two months?
Both months (March and October) have 31 days, right?

Frizie.
Ohm sweet Ohm | www.picbasic.nl

charliecoutas

Hi Bob

My code does two things, the first may not be relevant but it works out the day (MON, SUN etc) from the date.
I found this online:

"Here is a standard method suitable for mental computation:

Take the last two digits of the year.
Divide by 4, discarding any fraction.
Add the day of the month.
Add the month's key value: JFM AMJ JAS OND 144 025 036 146
Subtract 1 for January or February of a leap year.
For a Gregorian date, add 0 for 1900's, 6 for 2000's, 4 for 1700's, 2 for 1800's; for other years, add or subtract multiples of 400.
For a Julian date, add 1 for 1700's, and 1 for every additional century you go back.
Add the last two digits of the year.
Divide by 7 and take the remainder.
Now 1 is Sunday, the first day of the week, 2 is Monday, and so on."

The actual BST, GMT code starts just after the line: ; BST runs from the last Sunday in March until the last Sunday in October...

Yes, it works if started at any time.

GMT is Bit
day_num, month_no etc are all byte.

B*gg*r, the year 2100 will be here all too quickly. I'll see if I can correct it.

RGV250

Hi Charlie,
I made today Thursday?, here are my calcs if you could check.
31/10/2021
21/4 = 5 + 21 = 26
Month = 4
So 31 + 21 + 4 = 61
61 / 7 = 8.714
8 * 7 = 56
61 - 56 = 5 = Thursday

Bob

Dompie

Fritzie, YESSSS you are totally right.I looked in my code and indeed I (fortunately) do use one date. I was already afraid that my three projects were wrong, but no, it's not that bad.

Johan

charliecoutas

Bob

I make the current month  1 not 4, from the list  JFM AMJ JAS OND 144 025 036 146

I will check it tomorrow, from Bletchley Park!

RGV250

Hi,
I think I got confused with the Dec so looked a the 9th number but if it was the tenth it would be 6 which makes it Saturday?
QuoteDec month_no                                                       ;lookupl starts at 0 not 1
        temp = LookUpL month_no,[6,2,2,5,0,3,5,1,4,6,2,4]

This is different to the above which would make it 1 but this then makes the remainder 2 which is Monday?.
QuoteAdd the month's key value: JFM AMJ JAS OND 144 025 036 146

Bob


RGV250

Hi,
I missed this as it was not in your original post, if I use that plus the month values in your second post it works.
QuoteFor a Gregorian date, add 0 for 1900's, 6 for 2000's, 4 for 1700's, 2 for 1800's; for other years, add or subtract multiples of 400.

Bob

charliecoutas

Looks as though you've sorted it Bob. I never really fully understood the formula, there are different ways of doing it. We'll all probably be underwater by the time 2100 comes round so I'm not bothering with the leap-year mod.

Best regards
Charlie

RGV250

Hi,
I had to do a simple leap year thing at work and I wrote in the comments it would fail in 2100 but I would fix the bug if I was still around.

I found it works for what I require, it caught me out as Saturday works out as 0 which is not really mentioned in the web article. I have some testing to do but so far so good.

Bob

RGV250

Hi Charlie,
Thanks for the information, I had to change a couple of bits and have made a procedure and tested it quite a bit, all seems good.
This is just to test for the day of week if anyone is interested.

'  ____/\\\\\\\\\_________/\\\\\\\\\\\\__/\\\________/\\\____/\\\\\\\\\_______/\\\\\\\\\\\\\\\______/\\\\\\\____       
'   __/\\\///////\\\_____/\\\//////////__\/\\\_______\/\\\__/\\\///////\\\____\/\\\///////////_____/\\\/////\\\__      
'    _\/\\\_____\/\\\____/\\\_____________\//\\\______/\\\__\///______\//\\\___\/\\\_______________/\\\____\//\\\_     
'     _\/\\\\\\\\\\\/____\/\\\____/\\\\\\\__\//\\\____/\\\_____________/\\\/____\/\\\\\\\\\\\\_____\/\\\_____\/\\\_    
'      _\/\\\//////\\\____\/\\\___\/////\\\___\//\\\__/\\\___________/\\\//______\////////////\\\___\/\\\_____\/\\\_   
'       _\/\\\____\//\\\___\/\\\_______\/\\\____\//\\\/\\\_________/\\\//____________________\//\\\__\/\\\_____\/\\\_  
'        _\/\\\_____\//\\\__\/\\\_______\/\\\_____\//\\\\\________/\\\/____________/\\\________\/\\\__\//\\\____/\\\__ 
'         _\/\\\______\//\\\_\//\\\\\\\\\\\\/_______\//\\\________/\\\\\\\\\\\\\\\_\//\\\\\\\\\\\\\/____\///\\\\\\\/___
'          _\///________\///___\////////////__________\///________\///////////////___\/////////////________\///////_____

' Test code for day of week calculation based on web site - https://cs.uwaterloo.ca/~alopez-o/math-faq/node73.html
' Thanks to CharlieCoutas on the forum for the code which I have tweaked a bit.
 
    Include "Amicus18.inc"
   
    DelayMS 100

    Dim bDay As Byte
    Dim bMonth As Byte
    Dim bYear As Word        
    Dim DOW_String As String *10                     ' Day of week string
   
Dim CHARPOS As Byte System
Dim InCHAR As Byte System    
Dim RXBUFF[20] As Byte    

' Main program loop ----------------------------------------------------------------------
   
Do:
' Call the procedure
    Read_Time()                    ' Read in the time from a serial terminal.

' Move the data from the serial string to the date registers.
    bYear = (RXBUFF[4] * 10) + RXBUFF[5]             ' 2 digit year
    If CHARPOS >= 7 Then                             ' 4 digit year
    bYear = (RXBUFF[4] * 1000) + (RXBUFF[5] * 100) + (RXBUFF[6] * 10) + RXBUFF[7]
    EndIf
    bMonth = (RXBUFF[2] * 10) + RXBUFF[3]            ' Month
    bDay = (RXBUFF[0] * 10) + RXBUFF[1]              ' Day

' Call the procedure
        DayOfWeek(bDay, bMonth, bYear)

' Send result to serial terminal
        HSerOut [Dec bDay,":",Dec bMonth,":",Dec bYear," is a ", Str DOW_String, 10, 13]  
        HSerOut [Dec CHARPOS, 10, 13]
        Loop

' Procedures ------------------------------------------------------------------------------
       
Proc DayOfWeek(pValueDay As Byte, pValueMonth As Byte, pValueYear As Word),DOW_String
        Dim bDOW As Byte                             ' Calculated day of week number
        Dim bYearTemp As Byte  
        Dim bYearTemp1 As Byte                        
        Dim bMonthTemp As Byte

        If pValueYear > 2000 Then
        bYearTemp1 = pValueYear - 2000
        Else
        bYearTemp1 = pValueYear
        EndIf
       
        bYearTemp = (bYearTemp1 / 4) + bYearTemp1
        bMonthTemp = LookUpL pValueMonth,[0,1,4,4,0,2,5,0,3,6,1,4,6]   ' LookUpL starts At 0, not 1 so I have added a dummy 0
                                                                       ' at the start so month does not need to be altered.
         If bYearTemp1 // 4 = 0 Then                                   ' is this a leap year?
          If pValueMonth < 3 Then                                      ' if so, is month Jan or Feb?
           Dec bYearTemp                                               ' if so then we're too big by 1
          EndIf
         EndIf
        bDOW = (pValueDay + bYearTemp + bMonthTemp + 6) // 7           ' modulus
                                                                       ' The 6 is for the 2000's for other years see web site
        Select bDOW
        Case 0
        Result = "Saturday"       
        Case 1
        Result = "Sunday"
        Case 2
        Result = "Monday"
        Case 3
        Result = "Tuesday"
        Case 4
        Result = "Wednesday"
        Case 5
        Result = "Thursday"       
        Case 6
        Result = "Friday"       
        End Select        
EndProc  

Proc Read_Time()
        HRSOut "Enter date in 6 or 8 digit format starting with $ - $xxxxxx" ,10 , 13
        HRSOut "Enter CR after if 6 digit date " ,10 , 13        
HRSIn Wait("$")     ' Wait for $
        CHARPOS = 0
        Repeat ' Create a loop to receive the serial string
           HRSIn InCHAR ' Receive a character serially
            If InCHAR = 13 Then Break ' Exit the loop if the string reaches the end
            RXBUFF[CHARPOS] = InCHAR - 48 ' Convert ASCII to INT and load array GPS_RXBUFF
        Inc CHARPOS
        Until CHARPOS > 7 ' Repeat the loop until the buffer runs out 
EndProc

Regards,
Bob

charliecoutas

That looks very nice Bob, don't procedures make the structuring code so much better?

top204

#19
This has been a good thread to read, and a nicely structured piece of code Bob.

It is so wonderful to see users now using the procedures. It was something that should have been impossible to add to the flat language, but I came up with a unique mechanism that is not in any books, that allowed procedures to be added to the language, and procedures that work as they should. :-)

It took quite a few months, of 18 hours a day coding and lots of head scratching, to add, but it was more than worth it.

Once I'm more settled, I will be looking at adding structure items, Enums, String arrays, and multi-dimensional arrays etc... Sounds more simple that it is, because they also need to be implemented so they can be passed, directly and indirectly, as parameters and returns.