Calculate last day of month

Share your advanced PureBasic knowledge/code with the community.
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:
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
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. :lol:
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.
User avatar
Demivec
Addict
Addict
Posts: 4091
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Re: Calculate last day of month

Post by Demivec »

wilbert wrote:
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.
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.
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 »

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.
Windows (x64)
Raspberry Pi OS (Arm64)
citystate
Enthusiast
Enthusiast
Posts: 638
Joined: Sun Feb 12, 2006 10:06 pm

Re: Calculate last day of month

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

WARNING: may be talking out of his hat
User avatar
C87
Enthusiast
Enthusiast
Posts: 176
Joined: Mon Jul 17, 2017 7:22 am
Location: Cotswolds England

Re: Calculate last day of month

Post 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
If it's falling over......just remember the computer is never wrong!
User avatar
Michael Vogel
Addict
Addict
Posts: 2677
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Re: Calculate last day of month

Post by Michael Vogel »

I like Wilbert's solution (as always), so it's my number one now :wink:

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
Post Reply