diff --git a/dist.ini b/dist.ini index c24c4c92a1f..d48546c995d 100644 --- a/dist.ini +++ b/dist.ini @@ -23,6 +23,7 @@ Text::FIGlet = 2.19.3 Text::Unidecode = 0.04 Date::Calc = 6.3 Date::Hijri = 0.02 +Date::Jalali2 = 0.04 Date::Leapyear = 1.72 ; Dates role, et. al. DateTime = 0.74 diff --git a/lib/DDG/Goodie/CalendarConversion.pm b/lib/DDG/Goodie/CalendarConversion.pm new file mode 100644 index 00000000000..23e176d3de6 --- /dev/null +++ b/lib/DDG/Goodie/CalendarConversion.pm @@ -0,0 +1,88 @@ +package DDG::Goodie::CalendarConversion; +# ABSTRACT: convert between various calendars. + +use DDG::Goodie; +with 'DDG::GoodieRole::Dates'; + +use Date::Hijri; +use Date::Jalali2; + +use YAML::XS qw(Load); + +zci answer_type => "calendar_conversion"; +zci is_cached => 0; + +primary_example_queries '22/8/2003 to the hijri calendar'; +secondary_example_queries '23/6/1424 hijri to gregorian'; +description 'convert dates from the Gregorian calendar to the Hijri/Jalali calendars and back'; +name 'CalendarConversion'; +code_url 'https://github.com/duckduckgo/zeroclickinfo-goodies/blob/master/lib/DDG/Goodie/CalendarConversion.pm'; +category 'dates'; +topics 'special_interest'; +attribution github => ['http://github.com/mattlehning', 'mattlehning'], + github => ['http://github.com/ehsan', 'ehsan']; + +triggers any => 'hijri', 'gregorian', 'jalali'; + + +my $calendars = Load(scalar share('calendars.yml')->slurp); + +my $datestring_regex = datestring_regex(); + +sub format_date { + my ($d, $m, $y, $cal) = @_; + + return join(' ', $d, $calendars->{$cal}->[$m - 1], $y, '(' . ucfirst $cal . ')'); +} + +handle query_lc => sub { + return unless my ($datestring, $input_calendar, $output_calendar) = $_ =~ /^ + ($datestring_regex)\s+ + (?: + (?:(?:in|on(?:\s+the))?)\s* + ((?:gregorian|hijri|jalali)?)\s+ + (?:calendar|date|time)?\s* + (?:is\s+)? + )? + (?: + (?:(?:in|on|to)(?:\s+the|in)?)\s+ + )? + (gregorian|hijri|jalali)\s* + (?:calendar|date|time|years)? + $/x; + my $in_date = parse_datestring_to_date($datestring); + return unless $in_date; + my ($d, $m, $y) = ($in_date->day, $in_date->month, $in_date->year); + + $input_calendar ||= 'gregorian'; # gregorian is the default + return if ($input_calendar eq $output_calendar || !$output_calendar); + + my ($od, $om, $oy); + + if ($input_calendar eq "hijri") { + ($od, $om, $oy) = h2g($d, $m, $y); # To Gregorian; + ($od, $om, $oy) = g2j($od, $om, $oy) if ($output_calendar eq "jalali"); + } elsif ($input_calendar eq "gregorian") { + ($od, $om, $oy) = g2h($d, $m, $y) if ($output_calendar eq "hijri"); + ($od, $om, $oy) = g2j($d, $m, $y) if ($output_calendar eq "jalali"); + } elsif ($input_calendar eq "jalali") { + my $t = new Date::Jalali2($y, $m, $d, 1); + ($od, $om, $oy) = ($t->jal_day, $t->jal_month, $t->jal_year); + ($od, $om, $oy) = g2h($od, $om, $oy) if ($output_calendar eq "hijri"); + } + my $input_date = format_date($d, $m, $y, $input_calendar); + my $converted_date = format_date($od, $om, $oy, $output_calendar); + + return $input_date. ' is '. $converted_date, html => "
$input_date is $converted_date
"; +}; + +sub g2j { + my ($id, $im, $iy) = @_; + + my $t = new Date::Jalali2($iy, $im, $id, 0); + return ($t->jal_day, $t->jal_month, $t->jal_year); +} + + + +1; diff --git a/lib/DDG/Goodie/Hijri.pm b/lib/DDG/Goodie/Hijri.pm deleted file mode 100644 index 52bc2fad733..00000000000 --- a/lib/DDG/Goodie/Hijri.pm +++ /dev/null @@ -1,66 +0,0 @@ -package DDG::Goodie::Hijri; -# ABSTRACT: convert between Gregorian and Hiriji calendars. - -use DDG::Goodie; - -use Date::Hijri; - -zci answer_type => "conversion"; -primary_example_queries '22/8/2003 to the hijri calendar'; -secondary_example_queries '23/6/1424 to gregorian'; -description 'convert dates from the Gregorian calendar to the Hijri calendar and back'; -name 'Hijri'; -code_url 'https://github.com/duckduckgo/zeroclickinfo-goodies/blob/master/lib/DDG/Goodie/Hijri.pm'; -category 'dates'; -topics 'special_interest'; -attribution github => [ 'http://github.com/mattlehning', 'mattlehning' ]; - -triggers any => 'hijri', 'gregorian'; - -my %calendars = ( - 'gregorian' => ['Gregorian calendar', 'Gregorian calendar'], - 'hijri' => ['Hijri calendar','Hijri calendar'], -); - -# This function returns either the HTML version of the output or the text version. -sub output { - my ($calendar_first, $calendar_second, $input_date, $converted_date, $is_html) = @_; - - return "$input_date on the " . $calendars{$calendar_first}[$is_html] . " is $converted_date on the " . $calendars{$calendar_second}[$is_html] . '.'; -} - -handle query_lc => sub { - return unless my ($gd, $gm, $gy, $requested_calendar) = $_ =~ - /^ - (\d{0,2})(?:\/|,)(\d{0,2})(?:\/|,)(\d{3,4})\s+ - (?: - (?:on\s+the)\s+ - (?:gregorian|hijri)\s+ - (?:calendar|date|time)\s+ - is\s+ - )? - (?: - (?:(?:in|on|to)(?:\s+the|in)?)\s+ - )? - (gregorian|hijri)\s* - (?:calendar|date|time|years|months|days)? - $/x; - - return unless ($gd < 31 and $gm < 12); - - my $is_hijri = $requested_calendar eq 'hijri'; - - my ($hd, $hm, $hy) = $is_hijri ? g2h($gd, $gm, $gy) : h2g($gd, $gm, $gy); - my $input_date = "$gd/$gm/$gy"; - my $converted_date = "$hd/$hm/$hy"; - - # Check if the user wants to convert to either Hijri or Gregorian. - if($is_hijri) { - return output('gregorian', 'hijri', $input_date, $converted_date, 0), - html => output('gregorian', 'hijri', $input_date, $converted_date, 1); - } - return output('hijri', 'gregorian', $input_date, $converted_date, 0), - html => output('hijri', 'gregorian', $input_date, $converted_date, 1); -}; - -1; diff --git a/share/goodie/calendar_conversion/calendar_conversion.css b/share/goodie/calendar_conversion/calendar_conversion.css new file mode 100644 index 00000000000..3fb27502244 --- /dev/null +++ b/share/goodie/calendar_conversion/calendar_conversion.css @@ -0,0 +1,6 @@ +.zci--answer .zci--calendarconversion { + font-size: 1.5em; + font-weight: 300; + padding-top: .25em; + padding-bottom: .25em; +} diff --git a/share/goodie/calendar_conversion/calendars.yml b/share/goodie/calendar_conversion/calendars.yml new file mode 100644 index 00000000000..b7b70f97a8d --- /dev/null +++ b/share/goodie/calendar_conversion/calendars.yml @@ -0,0 +1,40 @@ +--- +gregorian: +- January +- Feburary +- March +- April +- May +- June +- July +- August +- September +- October +- November +- December +hijri: +- Muharram +- Safar +- Rabia Awal +- Rabia Thani +- Jumaada Awal +- Jumaada Thani +- Rajab +- Sha'ban +- Ramadan +- Shawwal +- Dhul-Qi'dah +- Dhul-Hijjah +jalali: +- Farvardin +- Ordibehesht +- Khordad +- Tir +- Mordad +- Shahrivar +- Mehr +- Aban +- Azar +- Dey +- Bahman +- Esfand diff --git a/t/CalendarConversion.t b/t/CalendarConversion.t new file mode 100644 index 00000000000..0d8360abb9b --- /dev/null +++ b/t/CalendarConversion.t @@ -0,0 +1,59 @@ +#!/usr/bin/env perl + +use strict; +use warnings; +use Test::More; +use DDG::Test::Goodie; + +zci answer_type => 'calendar_conversion'; +zci is_cached => 0; + +my @g22h = ( + '22 August 2003 (Gregorian) is 23 Jumaada Thani 1424 (Hijri)', + html => + "
22 August 2003 (Gregorian) is 23 Jumaada Thani 1424 (Hijri)
" +); +my @h23g = ( + '23 Jumaada Thani 1424 (Hijri) is 22 August 2003 (Gregorian)', + html => + "
23 Jumaada Thani 1424 (Hijri) is 22 August 2003 (Gregorian)
" +); +my @g22j = ( + '22 August 2003 (Gregorian) is 31 Mordad 1382 (Jalali)', + html => + "
22 August 2003 (Gregorian) is 31 Mordad 1382 (Jalali)
" +); + +ddg_goodie_test( + [qw(DDG::Goodie::CalendarConversion)], + '22/8/2003 to hijri' => test_zci(@g22h), + '22/8/2003 to the hijri calendar' => test_zci(@g22h), + '22,8,2003 to hijri' => test_zci(@g22h), + '23/6/1424 in hijri to gregorian years' => test_zci(@h23g), + '23/6/1424 hijri to gregorian' => test_zci(@h23g), + '22/8/2003 to jalali' => test_zci(@g22j), + '31/5/1382 jalali to gregorian' => test_zci( + '31 Mordad 1382 (Jalali) is 22 August 2003 (Gregorian)', + html => + "
31 Mordad 1382 (Jalali) is 22 August 2003 (Gregorian)
", + ), + '31/5/1382 jalali to hijri' => test_zci( + '31 Mordad 1382 (Jalali) is 23 Jumaada Thani 1424 (Hijri)', + html => + "
31 Mordad 1382 (Jalali) is 23 Jumaada Thani 1424 (Hijri)
" + ), + '23/6/1424 in hijri to jalali date' => test_zci( + '23 Jumaada Thani 1424 (Hijri) is 31 Mordad 1382 (Jalali)', + html => + "
23 Jumaada Thani 1424 (Hijri) is 31 Mordad 1382 (Jalali)
" + ), + 'August 22nd, 2003 to jalali' => test_zci(@g22j), + '22 Aug 2003 to Hijri' => test_zci(@g22h), + '22/8/2003 in the hijri calendar' => test_zci(@g22h), + '22nd Aug 2003 in jalali' => test_zci(@g22j), + '8-22-2003 in hijri years' => test_zci(@g22h), + 'August 22 2003 in jalali date' => test_zci(@g22j), + '22nd Aug 2003 in gregorian time' => undef, +); + +done_testing; diff --git a/t/Hijri.t b/t/Hijri.t deleted file mode 100644 index 5b6511525ed..00000000000 --- a/t/Hijri.t +++ /dev/null @@ -1,48 +0,0 @@ -#!/usr/bin/env perl - -use strict; -use warnings; -use Test::More; -use DDG::Test::Goodie; -use Date::Hijri; - -zci answer_type => 'conversion'; -zci is_cached => 0; - -ddg_goodie_test( - [qw(DDG::Goodie::Hijri)], - '22/8/2003 to hijri' => test_zci( - '22/8/2003 on the Gregorian calendar is 23/6/1424 on the Hijri calendar.', - html => '22/8/2003 on the ' - . 'Gregorian calendar ' - . 'is 23/6/1424 on the ' - . 'Hijri calendar.' - ), - '22/8/2003 to the hijri calendar' => test_zci( - '22/8/2003 on the Gregorian calendar is 23/6/1424 on the Hijri calendar.', - html => '22/8/2003 on the ' - . 'Gregorian calendar ' - . 'is 23/6/1424 on the ' - . 'Hijri calendar.' - ), - '22,8,2003 to hijri' => test_zci( - '22/8/2003 on the Gregorian calendar is 23/6/1424 on the Hijri calendar.', - html => '22/8/2003 on the ' - . 'Gregorian calendar ' - . 'is 23/6/1424 on the ' - . 'Hijri calendar.' - ), - '23/6/1424 to gregorian years' => test_zci( - '23/6/1424 on the Hijri calendar is 22/8/2003 on the Gregorian calendar.', - html => '23/6/1424 on the ' - . 'Hijri calendar ' - . 'is 22/8/2003 on the ' - . 'Gregorian calendar.' - ), - '23/6/1424 to gregorian' => test_zci( - '23/6/1424 on the Hijri calendar is 22/8/2003 on the Gregorian calendar.', - html => '23/6/1424 on the Hijri calendar is 22/8/2003 on the Gregorian calendar.' - ), -); - -done_testing;