Home
JAQForum Ver 24.01
Log In or Join  
Active Topics
Local Time 06:53 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 : A day of the year function.

     Page 1 of 2    
Author Message
Paul_L
Guru

Joined: 03/03/2016
Location: United States
Posts: 769
Posted: 12:41am 10 Jul 2018
Copy link to clipboard 
Print this post

Take a look at this day of the year function which I dashed off just now. I wonder if anyone can suggest a better way to do it.

Paul in NY

' DofY.bas, P Lepkowski, 7/9/2018
' tests function DofY(d$) which finds the numeric day of any year
' run it under MMBasic for DOS

GLOBALS:
Option base 1
Dim m%,d%,y%,day$, year%,LeapYear%
' date$="dd-mm-yyyy", time$="hh:mm:ss"

main:
Do
Print "Enter a day, month and year or '0' (zero) to end!"
Input "day"; d%: If (d%<1 Or d%>31) Then Exit Do
Input "month"; m%: If (m%<1 Or m%>12) Then Exit Do
Input "year"; y%: If y%<100 Then y%=2000+y%
day$=Str$(d%,2,0,"0")+"-"+Str$(m%,2,0,"0")+"-"+Str$(y%,4,0,"0")
Print
Print day$+" is the "+ Str$( DofY%(day$) )+" day of the year."
Loop
Print
Print "Today is "+Date$+" which is the "+ Str$( DofY%(Date$) )+" day of the year."
Print
Print "This displays all years from 2000 to 2500 followed by '1' if it is a leap year or '0' if it is not a leap year."
Print "It verifies that 2100, 2200, 2300 and 2500 are not leap years."
Print "Hint: stretch this window horizontally and vertically until you see 20 columns and 25 rows!."
For year%=2000 To 2500
If (year%\100)=(year%/100) Then
LeapYear%=((year%\400)=(year%/400))
Else
LeapYear%=((year%\4)=(year%/4))
EndIf
Print Str$(year%)+" "+Str$(LeapYear%),
Next year%
End

Function DofY%(DofY.dat$) 'accepts date$() or "dd-mm-yyyy"
Local DofY.i%, DofY.d%, DofY.m%, DofY.y%, DofY.LeapY%, DofY.inMo%(12)
' parse DofY.dat$ passed in
DofY.d%=Val(Mid$(DofY.dat$,1,2))
DofY.m%=Val(Mid$(DofY.dat$,4,2))
DofY.y%=Val(Mid$(DofY.dat$,7,4))
' is DofY.Y% a leap year
If (DofY.y%\100)=(DofY.y%/100) Then
DofY.LeapY%=((DofY.y%\400)=(DofY.y%/400))
Else
DofY.LeapY%=((DofY.y%\4)=(DofY.y%/4))
EndIf
' load DofY.inMo%(12) array
If DofY.LeapY%=1 Then Restore DofYleapData Else Restore DofYData
For DofY.i%=1 To 12:Read DofY.inMo%(DofY.i%):Next DofY.i%
' calculate Day of Year
If DofY.m%=1 Then DofY%=DofY.d% Else DofY%=DofY.d%+DofY.inMo%(DofY.m%-1)
End Function 'DofY%

DofYData:
Data 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365

DofYleapData:
Data 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366

''''''''''''''''''''''''''''eof
 
Grogster

Admin Group

Joined: 31/12/2012
Location: New Zealand
Posts: 9610
Posted: 02:45am 10 Jul 2018
Copy link to clipboard 
Print this post

I setup a one-dimensional array to hold the days:


DOW$(0)="Sunday":DOW$(1)="Monday":DOW$(2)="Tuesday":DOW$(3)="Wednesday"
DOW$(4)="Thursday":DOW$(5)="Friday":DOW$(6)="Saturday"


...then a Function to calculate the day reference:


function DayOfWeek(year, month, day)
a = int((14-month)/12)
m = month + 12*a - 2
y = year - a
DayOfWeek = (day + y + int(y/4)-int(y/100)+int(y/400)+int(31*m/12)) mod 7
end function



...then used a simple SUB to build the date string whenever I needed it:



SUB BUILD_DATE
YEAR=val(MID$(DATE$,7,4)):MONTH=VAL(MID$(DATE$,4,2)):DAY=val(MID$(DATE$,1,2))
DOW_DAY$=DOW$(DayOfWeek(YEAR,MONTH,DAY)) + ", " + DATE$
CtrlVal(MM_DAD)="THE DATE TODAY IS: "+DOW_DAY$
END SUB



Result:






The formula for DayOfWeek came from someone here on the forums, and I think they got it from the net. I understand it is a reasonably well known formula for calculating the day of the week.

Smoke makes things work. When the smoke gets out, it stops!
 
MicroBlocks

Guru

Joined: 12/05/2012
Location: Thailand
Posts: 2209
Posted: 02:52am 10 Jul 2018
Copy link to clipboard 
Print this post

  Grogster said  
The formula for DayOfWeek came from someone here on the forums, and I think they got it from the net. I understand it is a reasonably well known formula for calculating the day of the week.

Yep, that would have been me. :)

Used that for so many years even back in the GWBasic days.

I know I got it from somewhere (was not the internet at that time!) :)

I made it a bit smaller, and more obscure I think, to fit in a tiny function that can be included when needed.

Microblocks. Build with logic.
 
Grogster

Admin Group

Joined: 31/12/2012
Location: New Zealand
Posts: 9610
Posted: 02:55am 10 Jul 2018
Copy link to clipboard 
Print this post


Smoke makes things work. When the smoke gets out, it stops!
 
TassyJim

Guru

Joined: 07/08/2011
Location: Australia
Posts: 6283
Posted: 03:01am 10 Jul 2018
Copy link to clipboard 
Print this post

This is a SUB I have used in the past.
It was before Integers were available and includes the Microsoft Excel 'days since 1900'. You can remove or just ignore that line.
  Quote   'given day, month, year
'dayz=days since 1/1/1900 - agrees with Excel after 1/3/1900
SUB toMSday (d, m, y, dayz, dayofyear)
dayofyear= d+
INT((m-1)*30.57+0.5)
IF m>2 THEN
dayofyear= dayofyear-
1
IF (y MOD 4)>0 THEN dayofyear= dayofyear-1
IF (y MOD 100)=0 THEN dayofyear= dayofyear-1
IF (y MOD 400)=0 THEN dayofyear= dayofyear+1
ENDIF
dayz=
INT((y-1900)*365.25-0.25)+dayofyear+1
END SUB


I did a quick check and it seems to agree with your code.

Jim

VK7JH
MMedit
 
greybeard
Senior Member

Joined: 04/01/2010
Location: Australia
Posts: 174
Posted: 03:58am 10 Jul 2018
Copy link to clipboard 
Print this post

Probably a bit simple

function DayOfWeek(year, month, day)
DayOfWeek = Today
end Function
 
Paul_L
Guru

Joined: 03/03/2016
Location: United States
Posts: 769
Posted: 04:32am 10 Jul 2018
Copy link to clipboard 
Print this post

@TassyJim - thanks, that's a nice one.

The rest of youse guys, DofY should return an integer from 1 to 366, never "Monday".

Paul in NY
 
rave
Newbie

Joined: 24/02/2018
Location: United States
Posts: 28
Posted: 11:10pm 11 Jul 2018
Copy link to clipboard 
Print this post

  Paul_L said   @TassyJim - thanks, that's a nice one.

The rest of youse guys, DofY should return an integer from 1 to 366, never "Monday".

Paul in NY


True. The following two simple functions do the trick (this is all very standard stuff and published elsewhere):

' return days since 01-01-0001 without Julian calendar correction
Function Days(d, m, y)
Local a
a = Int((14-m)/12)
m = m+12*a
y = y-a
Days = 365*y+Int(y/4)-Int(y/100)+Int(y/400)+Int((153*m-457)/5)+d-306
End Function

' return the weekday of the given date
Function WeekDay$(d, m, y)
Local a,w$
a = 7*(Days(d, m, y) Mod 7)+1
w$ = "Sun Mon Tues Wednes Thurs Fri Satur "
WeekDay$ = Mid$(w$,a,Instr(a,w$," ")-a)+"day"
End Function


I shamelessly optimized string storage requirements, in the second function, sacrificing its readability

- Rob
 
Paul_L
Guru

Joined: 03/03/2016
Location: United States
Posts: 769
Posted: 03:10am 12 Jul 2018
Copy link to clipboard 
Print this post

Hi Rob, it's good to see you drop in here.

That's a nice way to optimize string storage in that second function, but I'm not sure it works in MMBasic. I believe that Geoff had to compromise and allocate 256 bytes for any string so using an array might work better but even then it might have 256 bytes reserved.

option base 1
' return days since 01-01-0001 without Julian calendar correction
Function Days(d, m, y)
Local a
a = Int((14-m)/12)
m = m+12*a
y = y-a
Days = 365*y+Int(y/4)-Int(y/100)+Int(y/400)+Int((153*m-457)/5)+d-306
End Function

' return the weekday of the given date
Function WeekDay$(d, m, y)
Local a,w$(7) length 6 =("Sun","Mon","Tues","Wednes","Thurs","Fri","Satur")
' the entire w$() array might still use 256 bytes instead of 49 bytes
a = 7*(Days(d, m, y) Mod 7)+1
WeekDay$ = w$(a)+"day"
End Function

While we're at it, do you see any way to optimize this further?

Dim d%,m%,y%,day$="dd-mm-yyyy",DOY%
d%=11:m%=2:y%=1940:DOY%=DofY%():print DOY%,
day$="11-02-1940":DOY%=DofYs%(day$):print DOY%,
DOY%=DofYs%(DATE$):print DOY%,
END

function DofYs%(d$) ' return dayofyear% given DATE$() or "dd-mm-yyyy"
d%=Val(Mid$(d$,1,2)):m%=Val(Mid$(d$,4,2)):y%=Val(Mid$(d$,7,4)):DofYs%=DofY%()
End function 'DofYs%(d$) ' return dayofyear% given DATE$() or "dd-mm-yyyy"

Function DofY%() ' return dayofyear% given globals d%, m%, y%
DofY%= d% + Int((m%-1)*30.57+0.5)
If m%>2 Then
DofY%=DofY%-1
If (y% Mod 4)>0 Then DofY%= DofY%-1 'not leap year
If (y% Mod 100)=0 Then DofY%= DofY%-1 'not leap century
If (y% Mod 400)=0 Then DofY%= DofY%+1 'leap 4th century
EndIf
End Function 'DofY%() ' return dayofyear% given globals d%, m%, y%

Paul in NY
 
TassyJim

Guru

Joined: 07/08/2011
Location: Australia
Posts: 6283
Posted: 04:49am 12 Jul 2018
Copy link to clipboard 
Print this post

  Paul_L said   Hi Rob, it's good to see you drop in here.

That's a nice way to optimize string storage in that second function, but I'm not sure it works in MMBasic. I believe that Geoff had to compromise and allocate 256 bytes for any string so using an array might work better but even then it might have 256 bytes reserved.

Either way works.
I often use Rob's method.

Jim
VK7JH
MMedit
 
rave
Newbie

Joined: 24/02/2018
Location: United States
Posts: 28
Posted: 05:03pm 12 Jul 2018
Copy link to clipboard 
Print this post

Hi Paul,

  Paul_L said  That's a nice way to optimize string storage in that second function, but I'm not sure it works in MMBasic.
[...]
option base 1
' return the weekday of the given date
Function WeekDay$(d, m, y)
Local a,w$(7) length 6 =("Sun","Mon","Tues","Wednes","Thurs","Fri","Satur")
' the entire w$() array might still use 256 bytes instead of 49 bytes
a = 7*(Days(d, m, y) Mod 7)+1
WeekDay$ = w$(a)+"day"
End Function


I like your suggestion to use the inline array!! Unfortunately, MMBASIC V4.5 runs on the Colour MaxiMite that I'm using and does not support this.

  Paul_L said  
While we're at it, do you see any way to optimize this further?

[...]
Function DofY%() ' return dayofyear% given globals d%, m%, y%
DofY%= d% + Int((m%-1)*30.57+0.5)
If m%>2 Then
DofY%=DofY%-1
If (y% Mod 4)>0 Then DofY%= DofY%-1 'not leap year
If (y% Mod 100)=0 Then DofY%= DofY%-1 'not leap century
If (y% Mod 400)=0 Then DofY%= DofY%+1 'leap 4th century
EndIf
End Function 'DofY%() ' return dayofyear% given globals d%, m%, y%


Sure, I'd reckon that your DofY%() function can be simplified to:
Function DofY%()
Local mm%,yy%,a%
a% = Int((14-m%)/12)
mm% = m%+12*a%
yy% = y%-a%
DofY% = 365*yy%+Int(yy%/4)-Int(yy%/100)+Int(yy%/400)+Int((153*mm%-457)/5)+d%-306
End Function

PS. Note that the Days() function in my earlier example changes the arguments m and y when passed as variables to the function, which in general we want to avoid by using locals mm% and yy% such as in the code above.

- Rob
 
lew247

Guru

Joined: 23/12/2015
Location: United Kingdom
Posts: 1702
Posted: 07:53am 09 Sep 2018
Copy link to clipboard 
Print this post

I'm still having problems with the day of the week function

It keeps saying the day is Sat

Can anyone see any problems with this code?
I'm using a PICROMITE - the code should be identical to any other version of the MM though

[code]
DOW$(0)="Sun":DOW$(1)="Mon":DOW$(2)="Tue":DOW$(3)="Wed":DOW$(4)="Thu":DOW$(5)="Fri":DOW$(6)="Sat"
Year=Val(Mid$(Date$,7,4)):Month=Val(Mid$(Date$,4,2)):Day=Val(Mid$(Date$,1,2))
dowx1$=DOW$(DayOfWeek(YEAR,MONTH,DAY))
do
print DOW$(DayOfWeek(YEAR,MONTH,DAY))
pause 2000
print DOW$(DayOfWeek(YEAR,MONTH,DAY)) @print 2nd time to see if it changes the day after a pause
end
function DayOfWeek(year, month, day)
print year 'to check if it's correct
print month 'to check if it's correct
print day 'to check if it's correct
local a,m,y
a = int((14-month)/12)
m = month + 12*a - 2
y = year - a
DayOfWeek = (day + y + int(y/4)-int(y/100)+int(y/400)+int(31*m/12)) mod 7
end function
[/code]
 
CaptainBoing

Guru

Joined: 07/09/2016
Location: United Kingdom
Posts: 2170
Posted: 08:17am 09 Sep 2018
Copy link to clipboard 
Print this post

really tiny Leapyear function.

returns a boolean so if you want, you can just "add" it to 365 for days in a particular year

http://www.fruitoftheshed.com/MMBasic.IsLeapYear-Function-to-determine-if-the-given-year-is-a-Leap-Year-on-the-Gregorian -western-calendar.ashx
 
Paul_L
Guru

Joined: 03/03/2016
Location: United States
Posts: 769
Posted: 05:51pm 09 Sep 2018
Copy link to clipboard 
Print this post

  lew247 said   I'm still having problems with the day of the week function
It keeps saying the day is Sat
Can anyone see any problems with this code?

Hi Lew ... It looks like your code repetitively extracts Year, Month, and Day from the MMVar DATE$. If you run this under DOS then DATE$ will get the current date from DOS (Windowze?). If you run it on a chip it might return the correct date if you have an RTC module hooked up and it's set properly, or if it has access to a GPS receiver. If you just start up a cold PIC chip I don't know what DATE$ will initially return. It does make sense that it will repetitively return the same day, ("Sat"), if DATE$ doesn't change. I have added comments and indented your code below.

Paul in NY

[code] DOW$(0)="Sun":DOW$(1)="Mon":DOW$(2)="Tue":DOW$(3)="Wed":DOW$(4)="Thu":DOW$(5)="Fri":DOW$(6)="Sat"
Year=Val(Mid$(Date$,7,4)):Month=Val(Mid$(Date$,4,2)):Day=Val(Mid$(Date$,1,2))
dowx1$=DOW$(DayOfWeek(YEAR,MONTH,DAY)) 'DOESN'T DO ANYTHING BECAUSE dowx1$ IS NEVER USED BELOW
do 'THIS DO DOESN'T DO ANYTHING BECAUSE THERE IS NO LOOP BELOW
print DOW$(DayOfWeek(YEAR,MONTH,DAY))
pause 2000 'YEAR, MONTH, or DAY don't change during this pause
'DATE$ will change if you pass midnight during the pause
'but YEAR, MONTH and DAY still won't change unless you specifically
'set them again with line #2 above
print DOW$(DayOfWeek(YEAR,MONTH,DAY)) '@print 2nd time to see if it changes the day after a pause
end

function DayOfWeek(year, month, day)
print year 'to check if it's correct
print month 'to check if it's correct
print day 'to check if it's correct
local a,m,y
a = int((14-month)/12)
m = month + 12*a - 2
y = year - a
DayOfWeek = (day + y + int(y/4)-int(y/100)+int(y/400)+int(31*m/12)) mod 7
end function
[/code]
 
lew247

Guru

Joined: 23/12/2015
Location: United Kingdom
Posts: 1702
Posted: 08:59pm 09 Sep 2018
Copy link to clipboard 
Print this post

Hi Paul

I only included the actual DOW part of the actual code

Yes when booted up it uses the default date I have told it to use whic is 01-01-1999

After 2 seconds the Picromite has got the current correct local time and date and stored it in DAY$ and DATE$

I'm only trying to get the day of the week after the correct local time and date has been processes

The "only" reason I have the Pause in the code above is to confirm it prints the same day both times - it's not actually neededEdited by lew247 2018-09-11
 
GoodToGo!

Senior Member

Joined: 23/04/2017
Location: Australia
Posts: 188
Posted: 06:25am 10 Sep 2018
Copy link to clipboard 
Print this post

Hi Lew,

I tried your code in DOS MMBasic ver 5.04.05 Beta 6 and it worked fine after I made a couple of edits:-
I had to declare the variable DOW$(6) at the start,
I commented out the 'do'
I commented out the 'dowx1$=DOW$...etc etc line.

dim DOW$(6) as string

DOW$(0)="Sun":DOW$(1)="Mon":DOW$(2)="Tue":DOW$(3)="Wed":DOW$(4)="Thu":DOW$(5)="Fri":DOW$(6)="Sat"

Year=Val(Mid$(Date$,7,4)):Month=Val(Mid$(Date$,4,2)):Day=Val(Mid$(Date$,1,2))

'dowx1$=DOW$(DayOfWeek(YEAR,MONTH,DAY)) 'DOESN'T DO ANYTHING BECAUSE dowx1$ IS NEVER USED BELOW
'do 'THIS DO DOESN'T DO ANYTHING BECAUSE THERE IS NO LOOP BELOW
print DOW$(DayOfWeek(YEAR,MONTH,DAY))
pause 2000 'YEAR, MONTH, or DAY don't change during this pause
'DATE$ will change if you pass midnight during the pause
'but YEAR, MONTH and DAY still won't change unless you specifically
'set them again with line #2 above
print DOW$(DayOfWeek(YEAR,MONTH,DAY)) '@print 2nd time to see if it changes the day after a pause
end

function DayOfWeek(year, month, day)
print year 'to check if it's correct
print month 'to check if it's correct
print day 'to check if it's correct
local a,m,y
a = int((14-month)/12)
m = month + 12*a - 2
y = year - a
DayOfWeek = (day + y + int(y/4)-int(y/100)+int(y/400)+int(31*m/12)) mod 7
end function


And the result was:-



Is the format of Date$ the same in Picromite as it is in the normal MMbasic?
ie. dd-mm-yyyy format?

Cheers,
GTG!

...... Don't worry mate, it'll be GoodToGo!
 
lew247

Guru

Joined: 23/12/2015
Location: United Kingdom
Posts: 1702
Posted: 07:17am 10 Sep 2018
Copy link to clipboard 
Print this post

Thanks G2G
I thought I'd got everything correct
In my code I had
DIM DOW$ and not DIM DOW$(6)
Tiny little error but stopped it working

Thanks for spotting that

Yes the Date format is the same dd-mm-yyyy

Lewis
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10315
Posted: 01:58pm 10 Sep 2018
Copy link to clipboard 
Print this post

  Quote  In my code I had
DIM DOW$ and not DIM DOW$(6)
Tiny little error but stopped it working


This is an error that should be getting caught by the MMBasic parser when you assign to DOW$(n). I've reported it to Geoff and I'm sure a fix will be included in a subsequent version of MMBasic so that it does generate an error.

DIM DOW$
DOW$(1)="test" ' this statement should generate an error
 
Volhout
Guru

Joined: 05/03/2018
Location: Netherlands
Posts: 5091
Posted: 06:39am 11 Sep 2018
Copy link to clipboard 
Print this post

  MicroBlocks said  
  Grogster said  
The formula for DayOfWeek came from someone here on the forums, and I think they got it from the net. I understand it is a reasonably well known formula for calculating the day of the week.

Yep, that would have been me. :)

Used that for so many years even back in the GWBasic days.

I know I got it from somewhere (was not the internet at that time!) :)

I made it a bit smaller, and more obscure I think, to fit in a tiny function that can be included when needed.


It was in K&R standard book on C.

Volhout
PicomiteVGA PETSCII ROBOTS
 
barewires
Newbie

Joined: 13/04/2015
Location: United Kingdom
Posts: 32
Posted: 11:16pm 31 Dec 2018
Copy link to clipboard 
Print this post

I keep a Perpetual Calendar in my head.
Made an interesting programming exercise which I have somewhere on an old drive.

Remember the following phrases and sets of numbers.

"I work at the 7-11 from 9-5. Reverse 11-7 and 5-9.
Remember 2-2, 4-4, 6-6, 8-8, 10-10 and 12-12.
Last day of February."

These dates were all Wednesday in 2018.

Add a day for next year or two days if coming into a leap year.

2018 Wed
2019 Thu

2020 Sat
2021 Sun
2022 Mon
2023 Tue

2024 Thu

January and March do not equate by this but are easy to calculate.
Enjoy and have a Happy New Year and remember the magic day for 2019 is Thursday!
 
     Page 1 of 2    
Print this page
The Back Shed's forum code is written, and hosted, in Australia.
© JAQ Software 2025