Home
JAQForum Ver 24.01
Log In or Join  
Active Topics
Local Time 03:29 24 May 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 : Daylight Saving

     Page 1 of 2    
Author Message
palcal

Guru

Joined: 12/10/2011
Location: Australia
Posts: 1970
Posted: 09:25pm 27 Feb 2025
Copy link to clipboard 
Print this post

FOTS has a daylight saving function Here
This is for the UK where DS starts and ends on the Last Sunday for different months to Australia. It's beyond me to change this for our region.
Has anyone changed this for Australia or have another function for DS.
"It is better to be ignorant and ask a stupid question than to be plain Stupid and not ask at all"
 
disco4now

Guru

Joined: 18/12/2014
Location: Australia
Posts: 983
Posted: 09:52pm 27 Feb 2025
Copy link to clipboard 
Print this post

Adjusted for southern hemisphere in this thread
Latest F4 Latest H7 FotS
 
palcal

Guru

Joined: 12/10/2011
Location: Australia
Posts: 1970
Posted: 10:06pm 27 Feb 2025
Copy link to clipboard 
Print this post

Thanks for that, will try.
"It is better to be ignorant and ask a stupid question than to be plain Stupid and not ask at all"
 
phil99

Guru

Joined: 11/02/2018
Location: Australia
Posts: 2458
Posted: 10:19pm 27 Feb 2025
Copy link to clipboard 
Print this post

It would appear that program preceded the addition of the inbuilt DAY$() function.
Finding the first Sunday may be easier with something like:-

If Day$(Date$) = "Sunday" then ...
 
palcal

Guru

Joined: 12/10/2011
Location: Australia
Posts: 1970
Posted: 10:53pm 27 Feb 2025
Copy link to clipboard 
Print this post

I did have a SUB using that, but it didn't work too well so before I tried anything, I thought I would ask.
I need something that if power is applied after DS has started it still recognised.
Edited 2025-02-28 08:56 by palcal
"It is better to be ignorant and ask a stupid question than to be plain Stupid and not ask at all"
 
GerryL
Newbie

Joined: 24/01/2019
Location: Australia
Posts: 36
Posted: 11:29pm 27 Feb 2025
Copy link to clipboard 
Print this post

here is an alternative that I have extracted from my original weather station program, the sub test at the bottom was a check to see it worked on rollover in April and October.  The only changes you would need is the CONSTANTS of cSTD_TIME_ZONE and CDTS_TIME_ZONE

 dim integer gn_UTCHour
 dim integer gn_UTCMin
 dim integer gn_UTCSec
 dim integer gn_UTCDate
 dim integer gn_UTCMonth
 dim integer gn_UTCYear
 dim integer gn_UTCDay
 dim integer gn_LocalHour
 dim integer gn_LocalDate
 dim integer gn_LocalMonth
 dim integer gn_LocalYear
 dim integer gn_LocalDay
 dim integer gn_LocalMins
 dim integer gn_LocalSecs
 
 
 
 ' time conversion
 CONST cSTD_TIME_ZONE = 9.5 ' Adelaide
 CONST CDTS_TIME_ZONE = 10.5
 CONST cSTANDARD_TIME_ZONE = cSTD_TIME_ZONE * 3600 ' + seconds, (i.e South Australia Central Standard Time, +9.5 Hrs from Z time)
 Const cLOCAL_TIME = 1
 Const cZULU_TIME = 2 ' GMT, time zone =0
 

FUNCTION GetDSTStart(ls_Year as String, ln_TimeType as Integer) as integer
' returns time in seconds since 1970 of the actual first second of DST
' DST start occurs at 0200 local on First Sunday in October or 1630Z on Saturday just prior to First Sunday in October
' ls_Year is the year for the calculation in format of "yyyy"
' ln_TimeType determines what the start time will be referenced to, i.e. Zulu (GMT) or local time.
 local as integer ln_Start
 ln_Start = EPOCH("01-10-" + ls_Year + " 02:00:00") + GetOffsetSeconds(ls_Year, "10") ' 2am first sunday of October
 if ln_TimeType = cZULU_TIME then ln_Start = ln_Start - cSTANDARD_TIME_ZONE '1630Z on Sat prior to first Sunday of Oct
 GetDSTStart = ln_Start
end Function

FUNCTION GetDSTEnd(ls_Year as String, ln_TimeType as Integer) as integer
' returns time in seconds since 1970 of the actual first second of Standard Time (non DST period) in UTC (Z or GMT Time)
' DST end occurs at 0300 local on First Sunday in April or 1630 UTC on Saturday just prior to First Sunday in  April
' ls_Year is the year for the calculation in format of "yyyy"
 local as integer ln_End
 ln_End = EPOCH("01-04-" + ls_Year + " 03:00:00") + GetOffsetSeconds(ls_Year, "04") ' 3am fist sunday of April
if ln_TimeType = cZULU_TIME then ln_End = ln_End - cSTANDARD_TIME_ZONE - 3600 '1630Z on Sat prior to first Sunday of month
GetDSTEnd = ln_End
end Function

Function GetOffsetSeconds(ls_Year as String, ls_Month as String) as integer
' returns time in seconds since 1970 of the actual first second of Standard Time (non DST period) in UTC (Z or GMT Time)
'e.g if month starts on a Monday then returns 86400 *6, Tuesday is 86400 * 5, Sunday = 0
 local as integer ln_Offset
 local as String ls_Day
 ls_Day = DAY$("01-" + ls_Month + "-" + ls_Year)
 SELECT CASE ls_Day    
   CASE "Sunday"
     ln_Offset = 0
   CASE "Monday"
     ln_Offset = 1
   CASE "Tuesday"
     ln_Offset = 2
   CASE "Wednesday"
     ln_Offset = 3
   CASE "Thursday"
     ln_Offset = 4
   CASE "Friday"
     ln_Offset = 5
   CASE "Saturday"
     ln_Offset = 6
   CASE ELSE        
     ln_Offset = 0 ' error if here
   END SELECT
   if ln_Offset <> 0 then
     ln_Offset = 7 - ln_Offset
     ln_Offset = ln_Offset * 86400 ' now seconds
   endif
   GetOffsetSeconds = ln_Offset
End Function

SUB StringUTCtoLocal (sYear as string, sDateTime as string)
' sYear as 20xx, sDateTime = dd-mm-yyyy hh:mm:ss
local as integer ln_UTCTime, ln_StartDST, ln_EndDST, ln_LocalTime
ln_StartDST = GetDSTStart(sYear,cZULU_TIME) 'Oct
   ln_EndDST = GetDSTEnd(sYear, cZULU_TIME) 'April
'print "date time = ",sDateTime
ln_UTCTime = EPOCH(sDateTime)
'print "UTC = ", ln_UTCTime, " Start = ",ln_StartDST, "End = ", ln_EndDST
   if ln_UTCTime < ln_StartDST AND ln_UTCTime > ln_EndDST then 'less than oct and more than april
     gf_LocalTimeZone =cSTD_TIME_ZONE
   else
     gf_LocalTimeZone = CDTS_TIME_ZONE
   end if
  ln_LocalTime = ln_UTCTime + gf_LocalTimeZone * 3600
   sDateTime = DATETIME$(ln_LocalTime) ' dd-mm-yyyy hh:mm:ss
  ' print "date Time = ",ls_TempString1
   gn_LocalDate = val(left$(sDateTime,2)) 'dd
gn_LocalMonth = val(mid$(sDateTime,4,2)) 'month
gn_LocalYear = val(mid$(sDateTime,7,4)) 'year, 4 digit
gn_LocalHour = val(mid$(sDateTime,12,2)) 'hour
gn_LocalMins = val(mid$(sDateTime,15,2)) 'min
gn_LocalSecs = val(mid$(sDateTime,18,2))
END SUB

SUB Test
' convert UTC to local
StringUTCtoLocal ("2025", "05-04-2025 16:29:59")
print "UTC Input = ","05-04-2025 16:29:59"
print "LOCAL Out = ",gn_LocalDate, "-", gn_LocalMonth,"-",gn_LocalYear,"   ",gn_LocalHour,":",gn_LocalMins,":",gn_LocalSecs
StringUTCtoLocal ("2025", "05-04-2025 16:30:01")
print "UTC Input = ","05-04-2025 16:30:01"
print "LOCAL Out = ",gn_LocalDate, "-", gn_LocalMonth,"-",gn_LocalYear,"   ",gn_LocalHour,":",gn_LocalMins,":",gn_LocalSecs

StringUTCtoLocal ("2025", "04-10-2025 16:29:59")
print "UTC Input = ","04-10-2025 16:29:59"
print "LOCAL Out = ",gn_LocalDate, "-", gn_LocalMonth,"-",gn_LocalYear,"   ",gn_LocalHour,":",gn_LocalMins,":",gn_LocalSecs
StringUTCtoLocal ("2025", "04-10-2025 16:30:01")
print "UTC Input = ","04-10-2025 16:30:01"
print "LOCAL Out = ",gn_LocalDate, "-", gn_LocalMonth,"-",gn_LocalYear,"   ",gn_LocalHour,":",gn_LocalMins,":",gn_LocalSecs

End SUB

Test
 
TassyJim

Guru

Joined: 07/08/2011
Location: Australia
Posts: 6230
Posted: 12:22am 28 Feb 2025
Copy link to clipboard 
Print this post

 
 ' as shown, dst starts on the first sunday of April
 ' change the month in the mth1start line to suit and add 7 for second sunday etc.
 ' for last sunday, use the following month and subtract 7 from the dst1
 '
 ' do the same for mth2start and dst2
 ' for the northern hemosphere. reverse the final IF statement
FUNCTION dst()
 LOCAL mth1start, mth2start, dst1, dst2, dateNow$, daynumnow
 dateNow$ = DATE$
 daynumnow = EPOCH(dateNow$+" 00:00:00")/86400
 mth1start = EPOCH("01-04-"+MID$(dateNow$,7,4)+" 00:00:00")/86400
 dst1 = 3-(mth1start MOD 7)
 dst1 = mth1start+dst1 ' first sunday in april in current year. add 7 for 2nd sunday
 
 mth2start = EPOCH("01-10-"+MID$(dateNow$,7,4)+" 00:00:00")/86400
 dst2 = 3-(mth2start MOD 7)
 dst2 = mth2start+ dst2 ' first sunday in october in current year. add 7 for 2nd sunday
 
 IF daynumnow < dst1 OR daynumnow >= dst2 THEN ' swap for northern hemisphere
   dst = 1
 ELSE
   dst = 0
 ENDIF
END FUNCTION
 

Jim
VK7JH
MMedit
 
palcal

Guru

Joined: 12/10/2011
Location: Australia
Posts: 1970
Posted: 12:31am 28 Feb 2025
Copy link to clipboard 
Print this post

Thanks all, I'll have a play around.
"It is better to be ignorant and ask a stupid question than to be plain Stupid and not ask at all"
 
palcal

Guru

Joined: 12/10/2011
Location: Australia
Posts: 1970
Posted: 01:10am 28 Feb 2025
Copy link to clipboard 
Print this post

@ TassyJim
I tested your code by putting in a dummy date, it works OK BUT I had to change the last lines to
IF daynumnow < dst1 OR daynumnow >= dst2 THEN ' swap for northern hemisphere
  dst = 0
ELSE
  dst = 1
ENDIF
END FUNCTION

I reversed dst = 0 and dst = 1
"It is better to be ignorant and ask a stupid question than to be plain Stupid and not ask at all"
 
phil99

Guru

Joined: 11/02/2018
Location: Australia
Posts: 2458
Posted: 01:24am 28 Feb 2025
Copy link to clipboard 
Print this post

TassyJim's method is excellent, simpler than any other that I have seen.
This version lets you put in any test date. If the brackets are empty it works as before.
If you need to invert DST add
DS = NOT DST()
to your program.
' TassyJim's amended Daylight Saving function
' If a date (as a string) is specified such as "28/02/2025" it is used, else Date$ is uesd.
' as shown, dst starts on the first sunday of April
' change the month in the mth1start line to suit and add 7 for second sunday etc.
' for last sunday, use the following month and subtract 7 from the dst1
'
' do the same for mth2start and dst2
' for the northern hemosphere. reverse the final IF statement
Function dst(TestDate$)
 Local mth1start, mth2start, dst1, dst2, dateNow$, daynumnow

 If TestDate$ = "" Then
   dateNow$ = Date$
  Else
   dateNow$ = TestDate$
 EndIf

  daynumnow = Epoch(dateNow$+" 00:00:00")/86400
 mth1start = Epoch("01-04-"+Mid$(dateNow$,7,4)+" 00:00:00")/86400
 dst1 = 3-(mth1start Mod 7)
 dst1 = mth1start+dst1 ' first sunday in april in current year. add 7 for 2nd sunday

 mth2start = Epoch("01-10-"+Mid$(dateNow$,7,4)+" 00:00:00")/86400
 dst2 = 3-(mth2start Mod 7)
 dst2 = mth2start+ dst2 ' first sunday in october in current year. add 7 for 2nd sunday

 If daynumnow < dst1 Or daynumnow >= dst2 Then ' swap for northern hemisphere
   dst = 1
 Else
   dst = 0
 EndIf
End Function

> ? dst()
1
> ? dst("07-04-2025")
0
>
> ? not dst()
0
> ? not dst("07-04-2025")
1
>


Footnote added 2025-02-28 12:33 by phil99
Removed the extra variable, it is redundant.
Function dst(dateNow$)
Local mth1start, mth2start, dst1, dst2, daynumnow

If dateNow$ = "" Then dateNow$ = Date$


Footnote added 2025-02-28 20:48 by phil99
> for n=22 to 31:d$=str$(n)+"-03-2025":? d$, dst(d$), day$(d$) :next
22-03-2025       1      Saturday
23-03-2025       1      Sunday
24-03-2025       1      Monday
25-03-2025       1      Tuesday
26-03-2025       1      Wednesday
27-03-2025       1      Thursday
28-03-2025       1      Friday
29-03-2025       1      Saturday
30-03-2025       0      Sunday
31-03-2025       0      Monday
>
 
palcal

Guru

Joined: 12/10/2011
Location: Australia
Posts: 1970
Posted: 01:48am 28 Feb 2025
Copy link to clipboard 
Print this post

My stupid mistake it starts in Oct so yes we are in DS now if you don't live in Qld.
Edited 2025-02-28 11:53 by palcal
"It is better to be ignorant and ask a stupid question than to be plain Stupid and not ask at all"
 
Turbo46

Guru

Joined: 24/12/2017
Location: Australia
Posts: 1636
Posted: 03:51am 28 Feb 2025
Copy link to clipboard 
Print this post

You could see Geoff’s Super Clock for an example.

Bill
Keep safe. Live long and prosper.
 
palcal

Guru

Joined: 12/10/2011
Location: Australia
Posts: 1970
Posted: 04:48am 28 Feb 2025
Copy link to clipboard 
Print this post

@ Turbo46....I looked at that but got lost in all the code.
"It is better to be ignorant and ask a stupid question than to be plain Stupid and not ask at all"
 
CaptainBoing

Guru

Joined: 07/09/2016
Location: United Kingdom
Posts: 2150
Posted: 11:13am 28 Feb 2025
Copy link to clipboard 
Print this post

  phil99 said  TassyJim's method is excellent,


I have yet to see any garbage from him... the man's a machine!  

In my defence    I program almost exclusively for MicroMites so i don't have the luxury of EPOCH() etc. Probably a lot to ask everyone to remember that... there are always improvements and I love to see them.

h
Edited 2025-02-28 21:23 by CaptainBoing
 
phil99

Guru

Joined: 11/02/2018
Location: Australia
Posts: 2458
Posted: 11:46am 28 Feb 2025
Copy link to clipboard 
Print this post

My last footnote shows DST ending on the last Sunday in March instead of the first in April.
Something to look into.
 
TassyJim

Guru

Joined: 07/08/2011
Location: Australia
Posts: 6230
Posted: 08:20pm 28 Feb 2025
Copy link to clipboard 
Print this post

I will have to check the code.

In Australia
Daylight Saving Time (DST) is used in the Australian Capital Territory, New South Wales, South Australia, Tasmania, and Victoria.
It starts the 1st Sunday of October and ends the 1st Sunday of April.

This is a political decision so anything can happen to change those dates.


I do have a pre epoch() version of the function somewhere...

Jim
Edited 2025-03-01 06:23 by TassyJim
VK7JH
MMedit
 
TassyJim

Guru

Joined: 07/08/2011
Location: Australia
Posts: 6230
Posted: 08:39pm 28 Feb 2025
Copy link to clipboard 
Print this post

I had over simplified the code.
Should have left it alone...

FUNCTION dst(TestDate$)
LOCAL mth1start, mth2start, dst1, dst2, dateNow$, daynumnow

IF TestDate$ = "" THEN
  dateNow$ = DATE$
 ELSE
  dateNow$ = TestDate$
ENDIF

 daynumnow = EPOCH(dateNow$+" 00:00:00")/86400
mth1start = EPOCH("01-04-"+MID$(dateNow$,7,4)+" 00:00:00")/86400
dst1 = (10-(mth1start MOD 7)MOD 7)
dst1 = mth1start+dst1 ' first sunday in april in current year. add 7 for 2nd sunday

mth2start = EPOCH("01-10-"+MID$(dateNow$,7,4)+" 00:00:00")/86400
dst2 = (10-(mth2start MOD 7)MOD 7)
dst2 = mth2start+ dst2 ' first sunday in october in current year. add 7 for 2nd sunday

IF daynumnow < dst1 OR daynumnow >= dst2 THEN ' swap for northern hemisphere
  dst = 1
ELSE
  dst = 0
ENDIF
END FUNCTION



Jim
VK7JH
MMedit
 
phil99

Guru

Joined: 11/02/2018
Location: Australia
Posts: 2458
Posted: 09:05pm 28 Feb 2025
Copy link to clipboard 
Print this post

Perfect, tested April and October for next 4 years plus 2050.

Streamlined my "If TestDate" add-on. Extra variable not needed
Function dst(dateNow$)
 Local mth1start, mth2start, dst1, dst2, daynumnow

 If dateNow$ = "" Then  dateNow$ = Date$

 daynumnow = Epoch(dateNow$+" 00:00:00")/86400
 mth1start = Epoch("01-04-"+Mid$(dateNow$,7,4)+" 00:00:00")/86400
 dst1 = (10-(mth1start Mod 7)Mod 7)
 Inc dst1, mth1start ' first sunday in april in current year. add 7 for 2nd sunday

 mth2start = Epoch("01-10-"+Mid$(dateNow$,7,4)+" 00:00:00")/86400
 dst2 = (10-(mth2start Mod 7)Mod 7)
 Inc dst2, mth2start ' first sunday in october in current year. add 7 for 2nd sunday

 If daynumnow < dst1 Or daynumnow >= dst2 Then ' swap for northern hemisphere
   dst = 1
 Else
   dst = 0
 EndIf
End Function

Edited 2025-03-01 07:23 by phil99
 
TassyJim

Guru

Joined: 07/08/2011
Location: Australia
Posts: 6230
Posted: 09:39pm 28 Feb 2025
Copy link to clipboard 
Print this post

Sorry, still stuffed it. Bracket in wrong place.
This is better:
 '
 DIM startdate$= "01-01-2024"
 DIM startday, tdate$,n,dstchange = 1
 
 startday = EPOCH(startdate$+" 00:00:00")/86400
 FOR n = 0 TO 3660
   tdate$ = LEFT$(DATETIME$((startday+n)*86400),10)
   IF dst(tdate$) <> dstchange THEN
     dstchange = dst(tdate$)
     PRINT tdate$
   ENDIF
 NEXT n
 
FUNCTION dst(TestDate$)
 LOCAL mth1start, mth2start, dst1, dst2, dateNow$, daynumnow
 
 IF TestDate$ = "" THEN
   dateNow$ = DATE$
 ELSE
   dateNow$ = TestDate$
 ENDIF
 
 daynumnow = EPOCH(dateNow$+" 00:00:00")/86400
 mth1start = EPOCH("01-04-"+MID$(dateNow$,7,4)+" 00:00:00")/86400
 dst1 = (10-(mth1start MOD 7))MOD 7
 dst1 = mth1start+dst1 ' first sunday in april in current year. add 7 for 2nd sunday
 
 mth2start = EPOCH("01-10-"+MID$(dateNow$,7,4)+" 00:00:00")/86400
 dst2 = (10-(mth2start MOD 7))MOD 7
 dst2 = mth2start+ dst2 ' first sunday in october in current year. add 7 for 2nd sunday
 
 IF daynumnow < dst1 OR daynumnow >= dst2 THEN ' swap for northern hemisphere
   dst = 1
 ELSE
   dst = 0
 ENDIF
END FUNCTION


VK7JH
MMedit
 
TassyJim

Guru

Joined: 07/08/2011
Location: Australia
Posts: 6230
Posted: 02:29am 01 Mar 2025
Copy link to clipboard 
Print this post

A version for the micromites without epoch()
startdate$= "01-01-2024"
dstchange = 1

startday = toJD(startdate$)
 FOR n = 0 TO 3660
   tdate$ = datex$(startday+n)
   IF dstx(tdate$) <> dstchange THEN
     dstchange = dstx(tdate$)
     PRINT tdate$
   ENDIF
 NEXT n

FUNCTION dstx(dateNow$) AS INTEGER
 LOCAL INTEGER mth1start, mth2start, dst1, dst2, daynumnow
 IF dateNow$ = "" THEN
   dateNow$ = DATE$
 ENDIF
 daynumnow = toJD(dateNow$)
 mth1start = toJD("01-04-"+MID$(dateNow$,7,4))
 dst1 = (13-(mth1start MOD 7))MOD 7
 dst1 = mth1start+dst1 ' first sunday in april in current year. add 7 for 2nd sunday
 mth2start = toJD("01-10-"+MID$(dateNow$,7,4))
 dst2 = (13-(mth2start MOD 7))MOD 7
 dst2 = mth2start+ dst2 ' first sunday in october in current year. add 7 for 2nd sunday
 IF daynumnow < dst1 OR daynumnow >= dst2 THEN ' swap for northern hemisphere
   dstx = 1
 ELSE
   dstx = 0
 ENDIF
END FUNCTION

FUNCTION toJD(myDate$)' valid for Gregorian dates after Oct 15, 1582
LOCAL d, m, y, ff
d = VAL(LEFT$(myDate$,2))
m = VAL(MID$(myDate$,4,2))
y = VAL(RIGHT$(myDate$,4))
ff=FIX((m-14)/12)
toJD = FIX((1461*(y+4800+ff))/4)+FIX((367*(m-2-12*ff))/12)-FIX((3*(FIX(y+4900+ff)/100))/4)+d-32075
END FUNCTION

FUNCTION datex$(jd)' valid for Gregorian dates after Oct 15, 1582
LOCAL l,n,i,j,d,m,y
l = jd+68569    
n = FIX((4*l)/146097)
l = l-FIX((146097*n+3)/4)
i = FIX((4000*(l+1))/1461001)
l = l-FIX((1461*i)/4)+31
j = FIX((80*l)/2447)
d = l-FIX((2447*j)/80)
l = FIX(j/11)
m = j+2-(12*l)
y = 100*(n-49)+i+l
datex$ = STR$(d,2,0,"0")+"-"+STR$(m,2,0,"0")+"-"+STR$(y,2)
END FUNCTION


It should work with integers or floats.

Jim
VK7JH
MMedit
 
     Page 1 of 2    
Print this page
The Back Shed's forum code is written, and hosted, in Australia.
© JAQ Software 2025