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

Code: Select all

And y<>3600
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! :lol:
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. :P

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. :lol:

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. :lol:

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. :lol:
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
:shock: I'll take your word for it. I've never understood bits representing data. Like, how does $fbbeecf mean anything?