Reputation: 869
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
Upvotes: 16
Views: 22347
Reputation: 132832
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');
Upvotes: 19
Reputation: 1314
While the DateTime class offers a constructor to do this, the most efficient way to get the last day of the month from an existing DateTime object is to request the object to calculate it. The class exposes an undocumented method _month_length() that calculates the last day of the month very efficiently. With your DateTime object called $date, you can try
$date->_month_length($date->year,$date->month);
This method is undocumented, so it may or may not be supported in your version of DateTime. Use with caution.
UPDATE
As a result of my request, starting from v1.144 DateTime added official support for month_length. When using this later version, you can use
$date->month_length($date->year,$date->month);
Upvotes: 2
Reputation: 8376
It is surprising, that neither DateTime
example uses the special constructor last_day_of_month
for that (example courtesy of brian d foy):
use DateTime;
use strict;
use 5.010;
my( $year, $month ) = qw( 2012 2 );
my $date = DateTime->new(
year => $year,
month => $month,
day => 1,
);
my $date2 = DateTime->last_day_of_month(
year => $date->year,
month => $date->month,
);
say $date->ymd('-');
say $date2->ymd('-');
Upvotes: 13
Reputation: 7516
As an alternative there is the core Perl module Time::Piece
.
For the current month and year:
perl -MTime::Piece -wE '$t=localtime;say $t->month_last_day'
31
More generally, something like:
use 5.010;
use Time::Piece;
my $MY = shift || die "Month and Year expected\n";
my $t = Time::Piece->strptime($MY, "%m%Y");
say $t->month_last_day;
$ ./mycode 022012
29
Upvotes: 8
Reputation: 385917
First day:
$dt->set_day(1);
Last day:
$dt->set_day(1)->add( months => 1 )->subtract( days => 1 );
Upvotes: 6