How do I find a date which is 3 days earlier than a given date in Perl where the format is YYYY-MM-DD?
views:
487answers:
7See perldoc POSIX
for the function mktime()
.
It will help you convert dates and times to a simple number, which is the Unix time (the number of seconds since January 1, 1970, I believe). Then, just subtract 3 (days) times 24 (hours in a day) times 60 (minutes in an hour) times 60 (seconds in a minute), or 259200 seconds from that number, and use localtime()
to convert that number of seconds back to a string representation.
This is probably the best solution*, because it will handle month and year changes automatically. Any other solution will probably end up being more complicated after factoring in checking to see if we ran out of days in a month, or ran out of months in a year.
EDIT: *Outside of looking on CPAN
.
Date::Calc can be used for such calculations:
#!/usr/bin/perl
use strict;
use warnings;
use Date::Calc qw(Add_Delta_Days);
my ( $yyyy, $mm, $dd ) = ( 2009, 9, 2 );
my @date = Add_Delta_Days( $yyyy, $mm, $dd, -3 );
print join( '-', @date );
Date::Calc
is the champion module here:
use strict;
use warnings;
use Date::Calc qw(Add_Delta_YMD);
my $startDate = '2000-01-01';
my ($startYear, $startMonth, $startDay) = $startDate =~ m/(\d{4}-(\d{2})-\d{2})/;
# 1 year, 2 months, 3 days, after startDate
my $endDate = join('-', Add_Delta_YMD($startYear, $startMonth, $startDay, 1, 2, 3));
The module has a huge number of time conversion routines, particularly those dealing with deltas. DateTime
and Date::Manip
are also worth checking out.
There are so many options that it is moderately embarrassing. It depends in part on what other calculations you might need in the future, and whether times and time zones will ever be a factor, and similar things.
You could look at any of these
Date::Calc
Date::Manip
DateTime::*
- see also datetime.perl.org (though that site did not seem to be responding on 2009-09-01T22:30-07:00)
to name but three (sets of) modules. I'd suggest Date::Calc
or Date::Manip
for simplicity - but if you're going to need to get fancy in future, the DateTime
modules may be better.
The neat thing about mktime
is that it will handle any time of offset. It uses January=0; and Year 2009 = 109 in this scheme. Thus, printed month - 1 and full year - 1900.
use POSIX qw<mktime>;
my ( $year, $month, $day ) = split '-', $date;
my $three_day_prior = mktime( 0, 0, 0, $day - 3, $month - 1, $year - 1900 );
mktime
is useful for finding the last day of the month as well. You just go to day 0 of the next month.
mktime( 0, 0, 0, 0, $month, $year - 1900 );
DateTime is the canonical way for dealing with dates in modern Perl:
use DateTime;
my ($year, $month, $day) = split '-', '2009-09-01';
my $date = DateTime->new( year => $year, month => $month, day => $day );
$date->subtract( days => 3 );
# $date is now three days earlier (2009-08-29T00:00:00)
/I3az/