Page 1 of 2
Calculate last day of month
Posted: Sun Nov 18, 2018 12:40 pm
by Dude
Just needed this but couldn't find it with a search, so I converted a C example I found with Google.
Code: Select all
Procedure LastDayOfMonth(m,y)
Select m
Case 1,3,5,7,8,10,12 ; Jan, Mar, May, Jul, Aug, Oct, Dec
d=31
Case 4,6,9,11 ; Apr, Jun, Sep, Nov
d=30
Default ; Feb
d=28+Bool((y%4=0 And (y%100<>0 Or y%400=0) And y<>3600))
EndSelect
ProcedureReturn d
EndProcedure
Debug LastDayOfMonth(2,2016) ; Outputs 29 because Feb 2016 is a Leap Year.
Re: Calculate last day of month
Posted: Sun Nov 18, 2018 2:09 pm
by Little John
After removing this, it will be OK.
BTW: This tip can be found here on the forum in various forms about half a dozen times.
Re: Calculate last day of month
Posted: Sun Nov 18, 2018 2:12 pm
by Sicro
Re: Calculate last day of month
Posted: Sun Nov 18, 2018 3:59 pm
by Michael Vogel
Interestingly similar to my code
Code: Select all
Procedure LastDayOfMonth(m,y)
; Version I
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 II - only works in 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
Debug LastDayOfMonth(2,2000); 28
Debug LastDayOfMonth(2,2016); 29
Debug LastDayOfMonth(2,2099); 28
Debug LastDayOfMonth(2,2100); 28
Re: Calculate last day of month
Posted: Sun Nov 18, 2018 10:14 pm
by Dude
"y<>3600" is a one-off special case from what I once read in a Leap Year FAQ document, so I was just covering the future. There'll be no "Y2K" bugs in my apps!
Little John wrote:This tip can be found here on the forum in various forms about half a dozen times.
Hmm, well no relevant matches come up if you search for "calculate last day of month", which is what I did.
Re: Calculate last day of month
Posted: Mon Nov 19, 2018 12:01 am
by Little John
Dude wrote:"y<>3600" is a one-off special case from what I once read in a Leap Year FAQ document, so I was just covering the future.
In the past, I have read much about time and date calculations, and thus also about calculating leap years. I never have read the number 3600 in this context.
Wikipedia also doesn't mention that. (I'm talking about the Gregorian calendar here.)
Dude wrote:Little John wrote:This tip can be found here on the forum in various forms about half a dozen times.
Hmm, well no relevant matches come up if you search for "calculate last day of month", which is what I did.
Well, that was obviously not a good search term.

Re: Calculate last day of month
Posted: Mon Nov 19, 2018 2:18 am
by citystate
why not use PB's inbuilt date functions?
Code: Select all
today=Date()
first=AddDate(today,#PB_Date_Day,1-Day(today))
last=AddDate(AddDate(first,#PB_Date_Day,-1),#PB_Date_Month,1)
Debug "today "+FormatDate("%dd/%mm/%yyyy",today)
Debug "first "+FormatDate("%dd/%mm/%yyyy",first)
Debug "last "+FormatDate("%dd/%mm/%yyyy",last)
Re: Calculate last day of month
Posted: Mon Nov 19, 2018 8:27 am
by Dude
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.
These days, I comment the actual URL for reference, so I can always look back (with Archive.org if needed).
However, I concede now that 3600 doesn't really need to be checked. I was being super-cautious, I guess.

Re: Calculate last day of month
Posted: Mon Nov 19, 2018 8:34 am
by Dude
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
Re: Calculate last day of month
Posted: Mon Nov 19, 2018 8:47 am
by wilbert
Dude wrote:citystate wrote:why not use PB's inbuilt date functions?
That example fails for December:
You can do it like this
Code: Select all
Procedure LastDayOfMonth(m,y)
ProcedureReturn Day(Date(y+m/12,m%12+1,1,0,0,0)-1)
EndProcedure
but it limits you to the supported PB date range (1970 - 2037).
Re: Calculate last day of month
Posted: Mon Nov 19, 2018 9:05 am
by Dude
wilbert wrote:LastDayOfMonth=Day(Date(y+m/12,m%12+1,1,0,0,0)-1)
Nice! So simple.

Thanks.
Re: Calculate last day of month
Posted: Mon Nov 19, 2018 9:22 am
by wilbert
Dude wrote:Nice! So simple.

Thanks.
Your original approach not being limited to the PB date range could also be done in one line
Code: Select all
Procedure LastDayOfMonth(m,y)
ProcedureReturn $fbbeecf>>(m<<1)&3+28+Bool(m=2 And y&3=0 And (y%100<>0 Or y%400=0))
EndProcedure
Re: Calculate last day of month
Posted: Mon Nov 19, 2018 9:31 am
by Dude
Wow, that's amazing, even though I don't understand what it's doing.

Re: Calculate last day of month
Posted: Mon Nov 19, 2018 9:39 am
by wilbert
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.
Re: Calculate last day of month
Posted: Mon Nov 19, 2018 9:44 am
by Dude

I'll take your word for it. I've never understood bits representing data. Like, how does $fbbeecf mean anything?