zeroclickinfo-goodies/lib/DDG/Goodie/DurationCalculator.pm

112 lines
2.9 KiB
Perl
Raw Permalink Normal View History

2016-06-08 08:27:19 -07:00
package DDG::Goodie::DurationCalculator;
# ABSTRACT: Finds duration between two times
use strict;
use DDG::Goodie;
with 'DDG::GoodieRole::Dates';
with 'DDG::GoodieRole::NumberStyler';
use DateTime::Duration;
2016-06-09 06:00:33 -07:00
use DateTime::Format::Human::Duration;
2016-06-08 08:27:19 -07:00
use Lingua::EN::Numericalize
zci answer_type => 'duration_calculator';
# Caching - http://docs.duckduckhack.com/backend-reference/api-reference.html#caching`
zci is_cached => 1;
# Triggers - http://docs.duckduckhack.com/walkthroughs/calculation.html#triggers
2016-06-09 04:23:05 -07:00
triggers any => qw(second minute hour day);
triggers any => qw(seconds minutes hours days);
triggers any => qw(plus minus + - add subtract);
2016-06-08 08:27:19 -07:00
my $number_re = number_style_regex();
my $action_re = qr/(?<action>plus|add|\+|\-|minus|subtract)/i;
my $unit_re = qr/(year|month|week|day|hour|minute|second|nanosecond)s?/i;
2016-06-13 23:48:22 -07:00
my $term_re = qr/(?<number>$number_re)\s(?<unit>$unit_re)/i;
my $operand_re = qr/($term_re\s?)*/i;
2016-06-08 08:27:19 -07:00
my $operation_re = qr/(?<operand1>$operand_re)$action_re\s+(?<operand2>$operand_re)?/i;
2016-06-09 04:23:05 -07:00
my $full_time_regex = qr/^($operation_re)[\?.]?$/i;
2016-06-08 08:27:19 -07:00
sub format_result {
2016-06-09 06:00:33 -07:00
my ($result) = @_;
2016-06-08 08:27:19 -07:00
2016-06-09 06:00:33 -07:00
my $span = DateTime::Format::Human::Duration->new();
2016-06-13 06:53:06 -07:00
my $start = DateTime->now();
my $end = $start->clone->add_duration($result);
2016-06-13 06:53:06 -07:00
return $span->format_duration_between($start, $end);
2016-06-08 08:27:19 -07:00
}
sub get_action_for {
my $action = shift;
2016-06-09 04:23:05 -07:00
return '+' if $action =~ /^(\+|plus)$/i;
return '-' if $action =~ /^(\-|minus)$/i;
2016-06-08 08:27:19 -07:00
}
sub get_values{
my ($operand) = @_;
2016-06-13 23:48:22 -07:00
my %modifiers;
while ($operand =~ /$term_re/g) {
my $number = $+{number};
my $unit = $+{unit};
$unit .= 's' unless $unit =~ /s$/;
2016-06-13 23:48:22 -07:00
return if exists $modifiers{$unit};
$modifiers{$unit} = $number;
}
my $dur = DateTime::Duration->new(%modifiers);
return $dur;
2016-06-08 08:27:19 -07:00
}
sub get_result {
my ($values1, $values2, $action) = @_;
2016-06-09 06:43:23 -07:00
return format_result ($values1 + $values2) if $action eq '+';
my $subtract = format_result ($values1 - $values2) if $action eq '-';
2016-06-28 22:11:41 -07:00
return "-($subtract)" if DateTime::Duration->compare($values1, $values2) < 0;
return $subtract;
2016-06-08 08:27:19 -07:00
}
handle query_lc => sub {
my $query = $_;
return unless $query =~ $full_time_regex;
my $action = $+{action};
my $operand1= $+{operand1};
my $operand2 = $+{operand2};
2016-06-13 23:48:22 -07:00
my $dur1 = get_values($operand1);
return unless defined $dur1;
my $dur2 = get_values($operand2);
return unless defined $dur2;
2016-06-09 06:00:33 -07:00
2016-06-08 08:27:19 -07:00
$action = get_action_for($action);
my $result = get_result($dur1, $dur2, $action);
my $format_query = $operand1.$action." ".$operand2;
2016-06-08 08:27:19 -07:00
return $result,
2016-06-13 23:48:22 -07:00
structured_answer => {
2016-06-08 08:27:19 -07:00
data => {
title => $result,
subtitle => $format_query,
2016-06-08 08:27:19 -07:00
},
templates => {
group => "text",
}
2016-06-13 23:48:22 -07:00
};
2016-06-08 08:27:19 -07:00
};
1;