Home
JAQForum Ver 24.01
Log In or Join  
Active Topics
Local Time 06:48 02 Aug 2025 Privacy Policy
Jump to

Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.

Forum Index : Microcontroller and PC projects : Date math gets tricky... we only have a few built-ins

Author Message
pwillard
Guru

Joined: 07/06/2022
Location: United States
Posts: 313
Posted: 11:16pm 02 Aug 2022
Copy link to clipboard 
Print this post

I'm just going to put this out there.  For the inexperienced... Date math is hard.

I'm working on figuring out a Daylight Savings awareness on my clock... and just to figure out the Second Sunday in March got somewhat ugly. (well, to me anyway) and now I need to figure out the first Sunday in November in a similar way.

I've never had to figure this stuff out before... so it's a puzzle.


Sub Secondsunday
' New York, Usa, Time Zone
' Figure Out Eastern Daylight Time By Finding
' The Day Of The Month Of The Second Sunday In March
 Local Myyear$ = Mid$(Date$,7)
 Local Dst.Addday = 0 ' We Start With An Increment, So Begin With 0
 Local Dst.Start$ = ""
 Local Dst.Sunday$ = ""
 Local Dst.Countsunday = 0
 
 Do
   Inc Dst.Addday
  ' Pad Day To Make Day$() Happy
   If Dst.Addday < 10 Then
     Dst.Start$ =  "0" +Str$(Dst.Addday) + "-03-" + Myyear$
   Else
     Dst.Start$ =  Str$(Dst.Addday) + "-03-" + Myyear$
   Endif
 
   Dst.Sunday$ = Day$(Dst.Start$)
   If Dst.Sunday$ = "Sunday" Then
     Inc Dst.Countsunday
     Print "Match " Dst.Addday
   Endif    
 Loop Until Dst.Countsunday = 2

 Print "The Second Sunday In March Is Day " Dst.Addday
 
End Sub


I'm probably making it too hard.
Edited 2022-08-03 09:23 by pwillard
 
TassyJim

Guru

Joined: 07/08/2011
Location: Australia
Posts: 6283
Posted: 03:16am 03 Aug 2022
Copy link to clipboard 
Print this post

Have a look at Geoff's clock code
https://geoffg.net/Downloads/Micromite/GPS_Clock.bas
VK7JH
MMedit
 
TassyJim

Guru

Joined: 07/08/2011
Location: Australia
Posts: 6283
Posted: 04:21am 03 Aug 2022
Copy link to clipboard 
Print this post

For MMBasics that have DAY$
dayz$ = "Sunday   Monday    Tuesday   Wednesday Thursday  Friday    Saturday"
INPUT "Enter month, year ",myM,myY
IF myY < 1900 THEN myY = 2000+myY
PRINT
' the long hand method
testDate$ = "01-"+STR$(myM,2,0,"0")+"-"+STR$(myY)
firstDay$ = DAY$(testDate$)
PRINT firstDay$
firstDayNum = INSTR(dayz$,firstDay$) /10
PRINT firstDayNum
firstSunday = 8-firstDayNum
PRINT firstSunday

' the shorthand method
firstSundayX = 8-(INSTR(dayz$,DAY$("01-"+STR$(myM,2,0,"0")+"-"+STR$(myY))) /10)
PRINT firstSundayX,myM,myY


Just add 7 to get the second Sunday.

Jim
VK7JH
MMedit
 
phil99

Guru

Joined: 11/02/2018
Location: Australia
Posts: 2642
Posted: 05:47am 03 Aug 2022
Copy link to clipboard 
Print this post

Here is my clumsy effort, extracted from a clock and GPS program for the ARMMiteF4.

'ArmMiteF4 with LCD Screen, RTC and GPS - Subroutine for adjusting daylight saving.

' setup the variables
TZ = 10 : Print "Time Zone = "TZ  'Time Zone
DSS = 10 : Print "Daylight Saving Start month", DSS 'Automatic hemispheric adjustment
DSF = 4 : Print "Daylight Saving Finish month", DSF 'ditto
DSW = 1 : Print "Daylight Saving Week of the month for start / finish", DSW
DSD$ = "Sunday" : Print "Daylight Saving Day of the week for start / finish", DSD$
DST$ = "02:00:00" : Print "Daylight Saving Time for start / finish", DSD$
DS = 0 : VAR Restore : Print " Initial Daylight Saving flag = ", DS  'Daylight Saving Flag
' - 0 = Off 1 = On - assumes RTC has right day
'Gets restored if it has been saved before.

Sub DS.Adj   'Subroutine for adjusting daylight saving.
Close GPS

 'Set DS flag for Daylight Saving Start
If Val(Mid$(Date$,4,2)) = DSS Then
 DS.day = DSW * 7 - 6  'start of change week
 Do   'find date of D.S. start day
  DS.date$ = Str$(DS.day,2,0,"0")+Right$(Date$,8)
  Print DateTime$(NOW),"DSS="DSS,"DSF="DSF,"DSW="DSW, "DS.day="DS.day,"DS="ds,"Start"
  Inc DS.day
 Loop Until (Day$(DS.date$)=DSD$) OR (DS.day > 7*DSW+1)
 If Epoch(now) => Epoch(DS.date$+" "+DST$) Then : DS=1 : Else : DS=0 : EndIf
 Print Epoch(now),Epoch(DS.date$+" "+DST$),ds : Pause 200
EndIf

 'Set DS flag for Daylight Saving Finish
If Val(Mid$(Date$,4,2)) = DSF Then
 DS.day = DSW * 7 - 6  'start of D.S. finish week
 Do   'find date of D.S. finish day
  DS.date$ = Str$(DS.day,2,0,"0")+Right$(Date$,8)
  Print DateTime$(NOW),"DSS="DSS,"DSF="DSF,"DSW="DSW, "DS.day="DS.day,"DS="ds,"Finish"
  Inc DS.day
 Loop Until (Day$(DS.date$)=DSD$) OR (DS.day > 7*DSW+1)
 If Epoch(now) => Epoch(DS.date$+" "+DST$) Then : DS=0 : Else : DS=1 : EndIf
 Print Epoch(now),Epoch(DS.date$+" "+DST$),ds : Pause 200
EndIf

  'set DS flag for the months with no change
If DSS > DSF Then   'Southern Hemisphere.
 If (Val(Mid$(Date$,4,2)) > DSF) AND (Val(Mid$(Date$,4,2)) < DSS) Then DS=0
 If (Val(Mid$(Date$,4,2)) > DSS) OR (Val(Mid$(Date$,4,2)) < DSF) Then DS=1
Else   'Swap winter and summer for Northern Hemisphere.
 If (Val(Mid$(Date$,4,2)) > DSF) OR (Val(Mid$(Date$,4,2)) < DSS) Then DS=0
 If (Val(Mid$(Date$,4,2)) > DSS) AND (Val(Mid$(Date$,4,2)) < DSF) Then DS=1
EndIf

Open GPSport$ As GPS, TZ+DS
Text 160,180,"  Waiting for GPS "+Str$(Int((Timer - Timer2)*.001))+" ",CM,,,0,&H808000
Do : Loop Until ((Timer - Timer2 > 1000) OR (GPS(VALID) = 1))
If (GPS(VALID) = 1) Then Time$ = GPS(Time) :  Timer2 = Timer

VAR Save DS
End Sub

Edited 2022-08-03 15:49 by phil99
 
TassyJim

Guru

Joined: 07/08/2011
Location: Australia
Posts: 6283
Posted: 06:31am 03 Aug 2022
Copy link to clipboard 
Print this post

Corrected code:
DIM INTEGER firstSunday, firstDayNum, firstSundayX
dayz$ = "          Monday    Tuesday   Wednesday Thursday  Friday    Saturday  Sunday"

DO
INPUT "Enter month, year ",myM,myY
IF myY < 1900 THEN myY = 2000+myY
PRINT
' the long hand method
testDate$ = "01-"+STR$(myM,2,0,"0")+"-"+STR$(myY)
firstDay$ = DAY$(testDate$)
PRINT firstDay$
firstDayNum = INSTR(dayz$,firstDay$)\10
PRINT firstDayNum
firstSunday = 8-firstDayNum
PRINT firstSunday

' the shorthand method
firstSundayX = 8-(INSTR(dayz$,DAY$("01-"+STR$(myM,2,0,"0")+"-"+STR$(myY)))\10)
PRINT firstSundayX,myM,myY
LOOP UNTIL myM = 0

Edited 2022-08-03 17:04 by TassyJim
VK7JH
MMedit
 
CaptainBoing

Guru

Joined: 07/09/2016
Location: United Kingdom
Posts: 2170
Posted: 08:03am 03 Aug 2022
Copy link to clipboard 
Print this post

  pwillard said   Date math is hard.

I'm working on figuring out a Daylight Savings awareness on my clock...



I have tons of date manipulation functions, all published on FotS

here is my DST function, you might need to tweak the switch points for your time zone
http://www.fruitoftheshed.com/MMBasic.Function-to-Test-a-DateTime-to-see-if-Daylight-Savings-should-be-applied.ashx

I highly recommend you convert datetimes into unix/epoch time for processing, then it is all just simple integer maths. date strings are just for human presentation but are a royal pita otherwise with all their different formats etc. CMM2 has built in functions for this I believe but not playing I can only point to my MM2 versions of the code (a lot of my datetime functions rely on UnixTime() and HumanTime()
http://www.fruitoftheshed.com/MMBasic.UnixTime-or-Epoch-Time.ashx  

Other stuff includes IsDate(), IsTime(), Now(), DateAdd(), DateDiff(), DatePart(), IsDayLight(), IsLeapYear(), DoW() etc.

enjoy.
Edited 2022-08-03 18:42 by CaptainBoing
 
pwillard
Guru

Joined: 07/06/2022
Location: United States
Posts: 313
Posted: 10:34am 03 Aug 2022
Copy link to clipboard 
Print this post

CaptainBoing... thank you.   And yes, it does seem to make more sense to use EPOCH time so I'll give that a try.


DOH!

I just realized that Picomite MMBASIC has an EPOCH() function.

Note: I tend to write code for clarity over efficiency so I'm sort of chatty with code. I'm not sure how robust this code is, but it seems to get the job done.

So now my code looks like this:





Sub SETDST
 
' New York, Usa, Time Zone
' Figure Out Eastern Daylight Time By Finding
' The Day Of The Month Of The Second Sunday In March
' and the Day of the month in the first Sunday in November
' Then determine if the current date is within the DST range
' Set DST to 1 or 0 accordingly
' DST is a Global Integer Variable
 
 Local MyYear$ = Mid$(Date$,7)
 Local Dst.AddDay = 0   ' In the loop, We Start With An Increment, So Begin With 0
 Local Dst.Start$ = ""  ' Will contain the DST Start Date
 LOCAL DST.End$ = ""    ' Will contain the DST End Date
 Local Dst.Sunday$ = "" ' Sunday String matching
 Local Dst.CountSunday = 0 ' Looking for sundays as we increment days
 local Day1, Day2  ' Day of the week
 
' Compute DST Start
 Do
   Inc Dst.AddDay
   ' Pad Day To Make Day$() Happy if needed
   If Dst.AddDay < 10 Then
     Dst.Start$ =  "0" +Str$(Dst.AddDay) + "-03-" + MyYear$
   Else
     Dst.Start$ =  Str$(Dst.AddDay) + "-03-" + MyYear$
   Endif
   Dst.Sunday$ = Day$(Dst.Start$)
   If Dst.Sunday$ = "Sunday" Then
     Inc Dst.CountSunday
   Endif
 Loop Until Dst.CountSunday = 2
 Day1 = DST.AddDay
 
 
'compute DST End
 DST.AddDay = 0
 DST.CountSunday = 0
 Do
   Inc Dst.AddDay
   ' Pad Day To make Day$() happy since day will always be a low number
   Dst.End$ =  "0" +Str$(Dst.AddDay) + "-11-" + MyYear$
   Dst.Sunday$ = Day$(Dst.End$)
   If Dst.Sunday$ = "Sunday" Then
     Inc Dst.CountSunday
   Endif
 Loop Until Dst.CountSunday = 1
 Day2 = DST.AddDay
 
' Print Results
 Print "Second Sunday In March Is Day:" Day1
 Print "First Sunday In November Is Day:" Day2
 Dst.Start$ =  Str$(Day1) + "-03-" + MyYear$ +" 02:00:00"
 print "Current Epoch Time    " EPOCH(NOW)
 print "DST START Value        " DST.Start$
 print "DST START Epoch Time  " EPOCH(DST.Start$)
 Dst.End$ =  "0" +Str$(DAY2) + "-11-" + MyYear$ + " 02:00:00"  
 print "DST END Value          " DST.End$
 print "DST END Epoch Time    " EPOCH(DST.End$)
 
' Set DST STATE
 if EPOCH(NOW) < EPOCH(DST.Start$) then DST = 0
 if EPOCH(NOW) > EPOCH(DST.Start$) then DST = 1
 if EPOCH(NOW) > EPOCH(DST.End$) then DST = 0
 
 print "DST STATE = " DST
End Sub


Printed results:

  Quote  
Second Sunday In March Is Day: 13
First Sunday In November Is Day: 6
Current Epoch Time     1659518520
DST START Value        13-03-2022 02:00:00
DST START Epoch Time   1647136800
DST END Value          06-11-2022 02:00:00
DST END Epoch Time     1667700000
DST STATE =  1

Edited 2022-08-03 23:22 by pwillard
 
pwillard
Guru

Joined: 07/06/2022
Location: United States
Posts: 313
Posted: 07:40pm 08 Sep 2022
Copy link to clipboard 
Print this post

Still goofing around with a clock.

And now that I'm a bit more comfortable with MMBASIC and having found EPOCH() and DATETIME$()... my code just got a LOT simpler.

This is only a couple of lines of code to create this.




So... THANK YOU!
Edited 2022-09-09 05:40 by pwillard
 
pwillard
Guru

Joined: 07/06/2022
Location: United States
Posts: 313
Posted: 02:41pm 09 Sep 2022
Copy link to clipboard 
Print this post

More progress...




.
 
CaptainBoing

Guru

Joined: 07/09/2016
Location: United Kingdom
Posts: 2170
Posted: 03:43pm 09 Sep 2022
Copy link to clipboard 
Print this post

here's a tip for you:

Epoch is commonly called "Unix Time" because Posix based computers counted seconds in that manner and for many their first exposure to Epoch times was the time sysvar of *nix machines. It has spread far and wide since.

Now-a-days, a lot of systems count milli-seconds in their Epoch times (hence they are 13 digits, not 10). You can use the internal timer of MMBasic to keep Epoch time in this manner because it increments in milli-seconds.

so something like
Timer=Epoch(Now)*1000

... will set the Timer to a real time and always has it in Epoch/Unixtime, just divide it by 1000 when you want to use it. Beware timer drift though; RTC Gettime doesn't set the Timer
Edited 2022-09-10 01:55 by CaptainBoing
 
pwillard
Guru

Joined: 07/06/2022
Location: United States
Posts: 313
Posted: 03:54pm 09 Sep 2022
Copy link to clipboard 
Print this post

Very Interesting... (Arte Johnson voice)

I'm not sure how much this will help at this stage of coding.  I currently pull time from RTC every 10 minutes to update the internal time-keeping.

I will say that moving to the use of UTC and EPOCH time changed things for the better.
 
CaptainBoing

Guru

Joined: 07/09/2016
Location: United Kingdom
Posts: 2170
Posted: 04:05pm 09 Sep 2022
Copy link to clipboard 
Print this post

  pwillard said  ... moving to the use of UTC and EPOCH time changed things for the better.


two rare absolutes in date processing, everything can be worked out fairly easily if you have those.
 
Print this page


To reply to this topic, you need to log in.

The Back Shed's forum code is written, and hosted, in Australia.
© JAQ Software 2025