![]() |
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 StatesPosts: 313 |
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: AustraliaPosts: 6283 |
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: AustraliaPosts: 6283 |
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 ' 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: AustraliaPosts: 2642 |
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: AustraliaPosts: 6283 |
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 ' 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 KingdomPosts: 2170 |
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 StatesPosts: 313 |
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: Edited 2022-08-03 23:22 by pwillard |
||||
pwillard Guru ![]() Joined: 07/06/2022 Location: United StatesPosts: 313 |
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 StatesPosts: 313 |
More progress... . |
||||
CaptainBoing![]() Guru ![]() Joined: 07/09/2016 Location: United KingdomPosts: 2170 |
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 StatesPosts: 313 |
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 KingdomPosts: 2170 |
two rare absolutes in date processing, everything can be worked out fairly easily if you have those. |
||||
![]() |
![]() |
The Back Shed's forum code is written, and hosted, in Australia. | © JAQ Software 2025 |