Calculate last day of month

Share your advanced PureBasic knowledge/code with the community.
Dude
Addict
Addict
Posts: 1907
Joined: Mon Feb 16, 2015 2:49 pm

Calculate last day of month

Post 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.
Little John
Addict
Addict
Posts: 4527
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: Calculate last day of month

Post 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.
Last edited by Little John on Sun Nov 18, 2018 4:03 pm, edited 1 time in total.
User avatar
Sicro
Enthusiast
Enthusiast
Posts: 538
Joined: Wed Jun 25, 2014 5:25 pm
Location: Germany
Contact:

Re: Calculate last day of month

Post by Sicro »

Image
Why OpenSource should have a license :: PB-CodeArchiv-Rebirth :: Pleasant-Dark (syntax color scheme) :: RegEx-Engine (compiles RegExes to NFA/DFA)
Manjaro Xfce x64 (Main system) :: Windows 10 Home (VirtualBox) :: Newest PureBasic version
User avatar
Michael Vogel
Addict
Addict
Posts: 2680
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Re: Calculate last day of month

Post 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
Dude
Addict
Addict
Posts: 1907
Joined: Mon Feb 16, 2015 2:49 pm

Re: Calculate last day of month

Post 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.
Little John
Addict
Addict
Posts: 4527
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: Calculate last day of month

Post 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. :-)
citystate
Enthusiast
Enthusiast
Posts: 638
Joined: Sun Feb 12, 2006 10:06 pm

Re: Calculate last day of month

Post 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)
there is no sig, only zuul (and the following disclaimer)

WARNING: may be talking out of his hat
Dude
Addict
Addict
Posts: 1907
Joined: Mon Feb 16, 2015 2:49 pm

Re: Calculate last day of month

Post 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:
Dude
Addict
Addict
Posts: 1907
Joined: Mon Feb 16, 2015 2:49 pm

Re: Calculate last day of month

Post 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
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3870
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Calculate last day of month

Post 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).
Windows (x64)
Raspberry Pi OS (Arm64)
Dude
Addict
Addict
Posts: 1907
Joined: Mon Feb 16, 2015 2:49 pm

Re: Calculate last day of month

Post by Dude »

wilbert wrote:LastDayOfMonth=Day(Date(y+m/12,m%12+1,1,0,0,0)-1)
Nice! So simple. :) Thanks.
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3870
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Calculate last day of month

Post 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
Last edited by wilbert on Mon Nov 19, 2018 5:45 pm, edited 1 time in total.
Windows (x64)
Raspberry Pi OS (Arm64)
Dude
Addict
Addict
Posts: 1907
Joined: Mon Feb 16, 2015 2:49 pm

Re: Calculate last day of month

Post by Dude »

Wow, that's amazing, even though I don't understand what it's doing. :lol:
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3870
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Calculate last day of month

Post 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.
Windows (x64)
Raspberry Pi OS (Arm64)
Dude
Addict
Addict
Posts: 1907
Joined: Mon Feb 16, 2015 2:49 pm

Re: Calculate last day of month

Post by Dude »

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