Page 2 of 2
Re: Calculate last day of month
Posted: Mon Nov 19, 2018 5:25 pm
by Little John
Dude wrote:Little John wrote:I never have read the number 3600 in this context
This is what I commented in some source code a few years ago:
Code: Select all
; Check if February of the year "y" is a Leap Year. Note that the year
; 3600 is a one-off special case (www.google.com/search?q=leap+year+faq).
ok=Bool((y%4=0 And (y%100<>0 Or y%400=0) And y<>3600))
Searching Google with that phrase doesn't show anything anymore, but I trust my comment.

I'm sure you do.

However, I'm sorry to say that for me (and probably also for the rest of the world) private self-written comments of a single person are not of relevance in a context like this. I prefer information from good textbooks or other reliable sources.
Dude wrote:However, I concede now that 3600 doesn't really need to be checked. I was being super-cautious, I guess.

Using 3600 was/is not super-cautious, but wrong.
The rules for calculating dates in the Gregorian calendar are nowadays defined by ISO. Here they are again:
The Gregorian Calendar says that if the year is divisible by 4 or 400 it is a
leap year. If it is divisible by 100 (but not 400) it is not a leap year.
Source:
http://web.mit.edu/jmorzins/www/iso8601/y2kdat.htm
The number 3600 does not occur anywhere in that document.
It is true that this rule for calculating leap years will not yield satisfactory results forever. So people have thought about modifications, e.g.
In the 19th century, Sir John Herschel proposed a modification to the Gregorian calendar with 969 leap days every 4000 years, instead of 970 leap days that the Gregorian calendar would insert over the same period.[79] This would reduce the average year to 365.24225 days. Herschel's proposal would make the year 4000, and multiples thereof, common instead of leap. While this modification has often been proposed since, it has never been officially adopted
Source:
https://en.wikipedia.org/wiki/Gregorian ... r#Accuracy
Again no occurrence of 3600. Maybe someone made another proposal, that contained 3600 as additional divisor.
But in any case there is a huge difference between an existing standard and a
proposal for modifying it.
Re: Calculate last day of month
Posted: Mon Nov 19, 2018 10:27 pm
by Demivec
wilbert wrote:Dude wrote:I don't understand what it's doing.

You can see the value $fbbeecf as a lookup table with two bits for each month .
It consists of values between 0 and 3 representing the days within a month minus 28.
So you lookup the month inside that table, add 28 and if the month equals 2, the leap year rule determines if 1 should be added.
The lookup table has extra values at the beginning and end. I would think these should be set to zero so that the table would be equal to $3bbeecc (= %0011 1011 1011 1110 1110 1100 1100) for 0<m<13.
I guess it probably doesn't matter in light of the fact that the padding on either end of the table shouldn't be used if m is set properly.
Re: Calculate last day of month
Posted: Tue Nov 20, 2018 7:22 am
by wilbert
Demivec wrote:The lookup table has extra values at the beginning and end.
I know. I chose to do so.
It supports a range of 0 - 14 where month 0 equals December of the previous year and month 13 and 14 equal January and February of the next year.
If you pass a month value PB supports (1 - 12) it doesn't do any harm but I prefer this over setting the bits to 0.
Re: Calculate last day of month
Posted: Wed Nov 21, 2018 5:04 am
by citystate
Dude wrote:citystate wrote:why not use PB's inbuilt date functions?
That example fails for December:
Code: Select all
today=Date(2018,12,25,0,0,0)
first=AddDate(today,#PB_Date_Day,1-Day(today))
last=AddDate(AddDate(first,#PB_Date_Day,-1),#PB_Date_Month,1)
Debug "xmas "+FormatDate("%dd/%mm/%yyyy",today)
Debug "first "+FormatDate("%dd/%mm/%yyyy",first)
Debug "last "+FormatDate("%dd/%mm/%yyyy",last) ; Shows 30
thanks Dude, fixed
Code: Select all
today=Date(2018,12,25,0,0,0)
first=AddDate(today,#PB_Date_Day,1-Day(today))
last=AddDate(AddDate(first,#PB_Date_Month,1),#PB_Date_Day,-1)
Debug "xmas "+FormatDate("%dd/%mm/%yyyy",today)
Debug "first "+FormatDate("%dd/%mm/%yyyy",first)
Debug "last "+FormatDate("%dd/%mm/%yyyy",last) ; Shows 31 as it should
Re: Calculate last day of month
Posted: Wed Nov 21, 2018 9:02 pm
by C87
Here is my two penneth, using string handling.
In the olden days before OOP, which have numerous date functions included, string handling was in fairly common use to solve this type of problem.
You will need to decide if it is a leap year
If LeapYear = True
mLastDayInMonth = "312931303130313130313031"
Else
mLastDayInMonth = "312831303130313130313031"
Endif
max days for a months are then
mMonth.i = Month(Date()) ; or whichever month you want
NoOfDays.s = Mid( mLastDayInMonth, ( ( mMonth * 2 ) -1 ),2 )
or instead
NoOfDays.s = Mid( mLastDayInMonth, ( ( Month(Date()) * 2 ) -1 ),2 )
You can do the same for days of the week
mDaysOfWk= "MonTueWedThuFriSatSun"
For a day name = Mid( mDaysOfWk, (DayNumberVar * 3 ) -2 ),3 )
"Monday TuesdayWednesdayThursday Friday Saturday Sunday"
( 3 @ 6 ; 2 @ 8 ; 1 @ 7 ; 1 @ 9 so each day has to be 9 chars long, shorter ones packed with spaces)
for a dayname = Mid( DaysNameVar, (( DayNumber *9) -8),9)
Same with months, where the longest is also 9
Or of course you could us an array!
Or any one of the suggestions in this Topic, all of which are brilliant. There is never one way or a best way in computing. Just one that suits you!
C87
Re: Calculate last day of month
Posted: Thu Nov 22, 2018 7:28 am
by Michael Vogel
I like Wilbert's solution (as always), so it's my number one now
Code: Select all
Procedure LastDayOfMonth(m,y)
; Version Wilbert+
ProcedureReturn 31-($441122)>>(m+m)&3-Bool(m=2 And (y&3 Or (y%100=0 And y%400)))
; Version II
If m-2
ProcedureReturn 30+(m+m>>3)&1
Else
ProcedureReturn 28+Bool(y%4=0 And (y%100 Or y%400=0))
EndIf
; Version III - only works within Date function range
Protected d=Date(y,m,1,0,0,0)+1<<22
ProcedureReturn Day(Date(Year(d),Month(d),1,0,0,0)-1)
EndProcedure
c.s="1900.2000.2100.2016.2018"
For m=0 To 12
s.s=""
For n=0 To CountString(c,".")
y.s=StringField(c,n+1,".")
If m : s+" "+Str(LastDayOfMonth(m,Val(y)))+" " : Else : s+" "+y+" " : EndIf
Next n
Debug s
Next m