Skip to content
This repository has been archived by the owner on Oct 15, 2022. It is now read-only.

Commit

Permalink
add/subtract days/weeks/months/years to/from a date
Browse files Browse the repository at this point in the history
  • Loading branch information
cj01101 committed May 9, 2012
1 parent 586dd1c commit 3656531
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 0 deletions.
84 changes: 84 additions & 0 deletions lib/DDG/Goodie/DateMath.pm
@@ -0,0 +1,84 @@
package DDG::Goodie::DateMath;
# ABSTRACT add/subtract days/weeks/months/years to/from a date

use DDG::Goodie;
use Date::Calc qw( Add_Delta_Days Add_Delta_YM This_Year );

triggers any => qw( plus minus + - );
zci is_cached => 1;
zci answer_type => 'date_math';

handle query_lc => sub {
my @param = split /\s+/;
return unless scalar @param == 4;

my ( $date, $action, $number, $unit ) = @param;

# check/tweak input

# default to this year:
my $md_re = '[01]?[0-9]/[0-3]?[0-9]';
$date .= '/' . This_Year() if $date =~ /^$md_re$/;
return unless $date =~ /^$md_re\/[0-9]{4}$/;

my %action_map = (
plus => '+',
'+' => '+',
minus => '-',
'-' => '-',
);
$action = $action_map{$action} || return;

return unless $number =~ /^\d+$/;
$number = 0 - $number if $action eq '-';

$unit =~ s/s$//g;

# calculate answer
my $sub_map = {
# sub parameters: year, month, day, number
day => sub {
return Add_Delta_Days( @_ );
},
week => sub {
$_[3] *= 7; # weeks to days
return Add_Delta_Days( @_ );
},
month => sub {
$_[4] = $_[3]; # months
$_[3] = 0; # 0 years
return Add_Delta_YM( @_ );
},
year => sub {
push @_, 0; # 0 months
return Add_Delta_YM( @_ );
},
};

my $sub = $sub_map->{$unit} || return;
my $answer;
eval {
$answer = format_ymd( $sub->( mdy_to_ymd_array( $date ), $number ) );
};
return if $@;

# output, using original @param
$param[0] = $date; # include the optional year
$param[3] = $unit;
$param[3] .= 's' if $param[2] > 1; # plural?
return "@param is $answer";
};

sub mdy_to_ymd_array
{
my @date = split '/', shift;
return ( $date[2], $date[0], $date[1] );
}

sub format_ymd
{
# ymd array to m/d/y
return join '/', $_[1], $_[2], $_[0];
}

1;
27 changes: 27 additions & 0 deletions t/DateMath.t
@@ -0,0 +1,27 @@
#!/usr/bin/env perl

use strict;
use warnings;
use Test::More;
use DDG::Test::Goodie;

zci answer_type => 'date_math';
zci is_cached => 1;

ddg_goodie_test(
[qw(
DDG::Goodie::DateMath
)],
'1/1/2012 plus 32 days' => test_zci( '1/1/2012 plus 32 days is 2/2/2012' ),
'1/1 plus 32 days' => test_zci( '1/1/2012 plus 32 days is 2/2/2012' ),
'1/1/2012 plus 5 weeks' => test_zci( '1/1/2012 plus 5 weeks is 2/5/2012' ),
'1/1/2012 plus 5 months' => test_zci( '1/1/2012 plus 5 months is 6/1/2012' ),
'1/1/2012 PLUS 5 years' => test_zci( '1/1/2012 plus 5 years is 1/1/2017' ),
'1/1/2012 plus 1 day' => test_zci( '1/1/2012 plus 1 day is 1/2/2012' ),
'1/1/2012 plus 1 days' => test_zci( '1/1/2012 plus 1 day is 1/2/2012' ),
'1/1/2012 + 1 day' => test_zci( '1/1/2012 + 1 day is 1/2/2012' ),
'1/1/2012 minus 10 days' => test_zci( '1/1/2012 minus 10 days is 12/22/2011' ),
);

done_testing;

0 comments on commit 3656531

Please sign in to comment.