lindex has asked for the wisdom of the Perl Monks concerning the following question:

What is the perlish way to get the number of days in a month, based on month and year ?


lindex
/****************************/ jason@gost.net, wh@ckz.org http://jason.gost.net /*****************************/

Replies are listed 'Best First'.
RE: simple stupid time question
by chromatic (Archbishop) on Sep 14, 2000 at 06:39 UTC
    I'd just write a simple routine to do it. Something like the following wouldn't be awful, in a dozen lines of code or so:
    sub days_in_month { my $month = shift; my $year = shift; my @mdays = qw( 31 28 31 30 31 30 31 31 30 31 30 31 ); if ($month == 2) { if ($year % 4 == 0) { # normal leap year if ($year % 100 == 0) { # century year, not a leap year return 28 unless ($year % 400 == 0); # century AND leap year } return 29; } } return $mdays[$month - 1]; # fudge the index }

    Update: Foggy and Adam contributed the current state of (now tested) not-so-bugginess. Seems like I should have actually *looked it up* in my library before I tried to recreate this wheel from memory.

    I originally intended this to be straightforward teaching code, but Adam's second snippet is much better.

      Your leap year code is still wrong. It should be:
      if ($month == 2) { if ( ( $year % 4 == 0 ) # normal leap year && ( ( $year % 100 != 0 ) # century year || ( $year % 400 == 0 ) # leap century ) ) { return 29; } }
      Also, you declare my $days = 0 but you don't use it.

      Update: All those parens are ugly, how about:

      if( 2 == $month ) { return 29 if 0 == $year % 4 and 0 != $year % 100 or 0 == $year % 400; }
      That works thanks to short circuitry and precedence. (yeah I could remove the 0 != part, but I wanted to retain explicit readability.)

      I think the leap year formula has become a frequently asked question, so I posted the answer here as well.

      Update: Chromatic's code will now work. It a slightly different way to look at it, using if and unless, but it works.

      Is it possible for a leap century to occur on a leap year? Couldn't you get 30 days in February as a result? I'm wondering if there isn't already a module that does this...

        Nope, you can't have a 30-day February specifically because the construct actually looks like:

        if ((($year % 4) = 0) && (($year % 100) != 0)) { $feb += 1; } #leap year elsif (($year % 400) = 0) { $feb +=1; } #leap century

        So, since a regular "leap year" doesn't occur at the end of a century, the two conditions are never simultaneously satisfied.

        Spud Zeppelin * spud@spudzeppelin.com

Re: simple stupid time question
by jptxs (Curate) on Sep 14, 2000 at 06:50 UTC

    a truly 'perlish' way is to grab a module :)

    I use Date::Business for this myself, but Date::Calc is an option too.

    -- I'm a solipsist, and so is everyone else. (think about it)

Re: simple stupid time question
by Foggy (Initiate) on Sep 14, 2000 at 07:03 UTC
    One nit in your code...it should be
    ... if($month == 1) { ...
    instead of 2 (since you decrement it to match the index)
RE: simple stupid time question
by turnstep (Parson) on Sep 14, 2000 at 14:49 UTC

    It would be nice to see something this small, simple, and often used put into perl itself at some point. Bob knows I've written a subrotine like the one above more than a few times. Yes, there are modules, but something with constants as basic as this should be accessible without the overhead of calling a module or writing a subroutine just to get a 12 member array (and a minor leap year calc). my ($0.02);

RE: simple stupid time question
by extremely (Priest) on Sep 15, 2000 at 03:46 UTC

    I always liked:

    sub leap { use Time::Local; my ($mo,$yr)=@_; #assumes month in 0-11 form ($yr++, $mo=0) if ++$mo>11; return (localtime(timelocal(0,0,0,1,$mo,$yr)-86400))[3]; }

    Seeing that someone else has done all the hard work for me.
    Plus it has bonus inscrutableness.

    --
    $you = new YOU;
    honk() if $you->love(perl)

Re: simple stupid time question
by tye (Sage) on Sep 15, 2000 at 20:06 UTC

    Given $mo and $yr set properly and not the way struct tm gives them (Jan is 1 not 0 and 2000 is 2000 not 100):

    (0,31,29-!(!($yr%4)&&$yr%100||not$yr%400),((31,30)x2,31)x2)[$mo]

    Just a lark! (not intended for production code)

            - tye (but my friends call me "Tye")