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;