perldatetime

How can I get the first and last day of the month with Perl's DateTime?


Is there a way to figure out the first day of the month (min day) and the last day of a month (max day), given the month as input, using DateTime in perl?

So far, I figured out how to pass in a first date, last date to give me a range of days.

But what I want to do now is just pass in a month as an argument, say 201203 and return min, maxday.

Is that possible with DateTime?

Also, I want to change the date format mask from YYYYMMDD to YYYY-MM-DD.

    use strict;
    use warnings;
    use DateTime;

    unless(@ARGV==2)
    {
        print "Usage: myperlscript first_date last_date\n";
        exit(1);
    }

    my ($first_date,$last_date)=@ARGV;

    my $date=DateTime->new(
    {
      year=>substr($first_date,0,4),
      month=>substr($first_date,4,2),
      day=>substr($first_date,6,2)
    });


while($date->ymd('') le $last_date)
{
  print $date->ymd('') . "\n";
  #$date->add(days=>1); #every day
  $date->add(days=>30);
}

Expected Results:

2012-03-01
2012-03-31

Solution

  • DateTime does date math for you. You can tell ymd which character you want to use as the separator:

    use DateTime;
    
    my( $year, $month ) = qw( 2012 2 );
    
    my $date = DateTime->new(
        year  =>  $year,
        month => $month,
        day   => 1,
    );
    
    my $date2 = $date->clone;
    
    $date2->add( months => 1 )->subtract( days => 1 );
    
    say $date->ymd('-');
    say $date2->ymd('-');
    

    That's general date math, but @w.k's answer also points out that there is a last_day_of_month method that does what you need. And, the OP point out that there is now a month_length method.

    There are many examples in "Last day of the month. Any shorter" on Perlmonks, which I found by Googling "perl datetime last day of month".


    And here's a Time::Moment example. It's a leaner, faster subset of DateTime:

    use v5.10;
    use Time::Moment;
    
    my( $year, $month ) = qw( 2012 2 );
    
    my $tm = Time::Moment->new(
        year  =>  $year,
        month => $month,
        day   => 1,
    );
    
    my $tm2 = $tm->plus_months( 1 )->minus_days( 1 );
    
    say $tm->strftime('%Y-%m-%d');
    say $tm2->strftime('%Y-%m-%d');