Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations TouchToneTommy on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

How do I get last day of month? 2

Status
Not open for further replies.

Givar

Programmer
Nov 7, 2001
5
SE
Hi.

I want to build a sub that can give me the last day of the month (or the number of days in a month), i.e. if I pass in "$year=2001" and "$month=11", the sub should return the number of days in the month November year 2001 (which should be 30). The sub should be able to handle leap-years.

Hope you guys can help out, thanks in advance.
 
Code:
sub LastDayOfMonth {
   my($year, $month) = @_;
   my $date = (31,28,31,30,31,30,31,31,30,31,30,31)[$month];
   if ( ($year % 4 == 0) &&
        ($year % 100 != 0) &&
        ($year % 400 == 0) {
      $date++;
   }
   return $date;
}
Call it like this:
Code:
$lastday = LastDayOfMonth($year,$month);
Note that there should probably be some error checking to make sure that $month is a valid month, etc., but the idea is there. Tracy Dryden
tracy@bydisn.com

Meddle not in the affairs of dragons,
For you are crunchy, and good with mustard.
 
Thanks a lot tsdragon! That's a BIG help :)
I'm getting the month from a date function, so it shouldn't be necessary to check that it's a valid month. I guess I'll have to reduce it by 1 first though. January = month 0 right?
 
OOPS! :~/ I plumb forgot about the arrays being zero based when I wrote that code (sound of forehead being slapped). Good of you to catch that! There are two easy ways to handle that, either change the subscript to
Code:
[--$month]
, or add a zero element to the array with a value of undef, or anything else.

You can also probably remove the test for year divisible by 100 and divisible by 400. The only year your even remotely likely to encounter that that effects is 2000 (and it will work fine without those tests) - unless you expect your program to handle dates back to 1900 or before, or you expect it to still be around in 2100. Neither 1900 nor 2100 is a leap year, but 2000 was, so for dates between 1901 and 2099, just testing for divisibility by 4 will work. It was only the perfectionist in me that made me include the extra tests. Tracy Dryden
tracy@bydisn.com

Meddle not in the affairs of dragons,
For you are crunchy, and good with mustard.
 
just test if the next day is the first day of the month!
 
A lesson in obfuscation :): If you are on UNIX, you can use:
Code:
$month = 2;
$year  = 2000;
chomp( $last = qx( cal $month $year | xargs | awk '{print \$NF}' ) );
print "$last\n";
Cheers, Neil
 


I tried this script and cant get it to work. I executed it and put in month and year such as March,2001 and keep getting output of 31 on every input. Also can someone please explain how the script is working such as the 'my $date = .........' and the modules part. Thanks


sub LastDayOfMonth {
my($year, $month) = @_;
my $date =
(31,28,31,30,31,30,31,31,30,31,30,31)[$month];
if ( ($year % 4 == 0) &&
($year % 100 != 0) &&
($year % 400 == 0) ) {
$date++;
}
return $date;
}


while (<>)
{
chomp;
$lastday = &LastDayOfMonth($year,$month);
print &quot;$lastday\n&quot;;
}
 
Looking back at that subroutine, I just discovered another glaring error: I increment the last day of the month for ANY month in a leap year, NOT just FEBRUARY!!! :~/ That if statement should be:
Code:
   if ( ($month == 2 ) && (
        ($year % 4 == 0) &&
        ($year % 100 != 0) &&
        ($year % 400 == 0) ) {

   # or, to make it simpler, and still usuable for
   # any year from 1901 to 2099

   if ( ($month == 2) && ($year % 4 == 0) ) {

Now, as for the problems florida is having: first of all, Givar was right - arrays are zero-relative, so you either have to adjust the array, or decrement the month by one to make the routine work correctly. Secondly, your $year and $month don't ever have a value assigned to them, so you're calling the routine with (0,0) - which, since the array is still zero-based, will return the first element of the array (element 0), which is 31. That's why it's always returning the same thing. I'm not sure why you have the call to LastDayOfMonth in an input loop.

As for how it works:
Code:
my($year, $month) = @_;
# assign parameters to variables
# @_ contains the list of parameters passed to the subroutine
# they are assigned to $year and $month, respectively
my $date =
(31,28,31,30,31,30,31,31,30,31,30,31)[$month-1];
# use $month-1 as index into array containing the last
# day of the month for each month
if ( $month == 2 && (
($year % 4 == 0) &&
($year % 100 != 0) &&
($year % 400 == 0) ) ) {
# if month is February and if year is divisible by 4,
# but not by 100, but by 400 - it's a leap year
$date++;
# increment the last day of the month
}
return $date;
# return the value
}
Tracy Dryden
tracy@bydisn.com

Meddle not in the affairs of dragons,
For you are crunchy, and good with mustard.
 
Thanks for the detailed explanation.

Now I just need to find how to execute this?

sub LastDayOfMonth {
my($year, $month) = @_;
# assign parameters to variables
# @_ contains the list of parameters passed to thesubroutine
# they are assigned to $year and $month,respectively
my $date =
(31,28,31,30,31,30,31,31,30,31,30,31)[$month-1];
# use $month-1 as index into array containing thelast
# day of the month for each month
if ( $month == 2 && (
($year % 4 == 0) &&
($year % 100 != 0) &&
($year % 400 == 0) ) ) {
# if month is February and if year is divisible by 4,
# but not by 100, but by 400 - it's a leap year
$date++;
# increment the last day of the month
}
return $date;
# return the value
}

print LastDayOfMonth(1999, February);
 
You CAN'T use the NAME of the month! That value is passed to the subroutine and used as an INDEX into the array of day-per-month. You have to call it like this:
Code:
print LastDayOfMonth(1999,2);
# or
print LastDayOfMonth(&quot;2000&quot;,&quot;02&quot;);
It doesn't matter whether you use numbers or strings containing numbers, but they MUST be numeric.

See, I knew I should have put in some error (checking!) Tracy Dryden
tracy@bydisn.com

Meddle not in the affairs of dragons,
For you are crunchy, and good with mustard.
 
Hmmm :) when you've ermmmm completed that Tracy - you fancy making a FAQ out of it? <grin> Mike
michael.j.lacey@ntlworld.com
Email welcome if you're in a hurry or something -- but post in tek-tips as well please, and I will post my reply here as well.
 
Thanks for all the explanation.

The one final question ( I promise) is why are you incrementing '$date' ($date++)?
 
Mike: &quot;Hmmm when you've ermmmm completed that Tracy - you fancy making a FAQ out of it? <grin>&quot; OUCH!
phppplt.gif
Guess I deserved that.

florida: I increment date when it's February of a leap year to make the last day 29 instead of 28.
Tracy Dryden
tracy@bydisn.com

Meddle not in the affairs of dragons,
For you are crunchy, and good with mustard.
 
<grin> Mike
michael.j.lacey@ntlworld.com
Email welcome if you're in a hurry or something -- but post in tek-tips as well please, and I will post my reply here as well.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top