File Coverage

blib/lib/Date/HijriDate.pm
Criterion Covered Total %
statement 6 189 3.1
branch 0 44 0.0
condition 0 12 0.0
subroutine 2 6 33.3
pod 0 4 0.0
total 8 255 3.1


line stmt bran cond sub pod time code
1             #=Copyright Infomation
2             #==========================================================
3             #Module Name : Date::HijriDate
4             #Program Author : Dr. Ahmed Amin Elsheshtawy, Ph.D. Physics, E.E.
5             #Home Page : http://www.islamware.com, http://www.mewsoft.com
6             #Contact Email : support@islamware.com, support@mewsoft.com
7             #Copyrights © 2013 IslamWare. All rights reserved.
8             #==========================================================
9             package Date::HijriDate;
10              
11 1     1   21178 use strict;
  1         2  
  1         31  
12 1     1   840 use POSIX;
  1         6905  
  1         10  
13              
14             require Exporter;
15             our @ISA = 'Exporter';
16             our @EXPORT = qw(hijri_date hijri_now hijri_time);
17              
18             our $VERSION = '1.01';
19              
20             our %weekday = (
21             'en' => ["Ahad","Ithnin","Thulatha","Arbaa","Khams","Jumuah","Sabt"],
22              
23             'ar' => ["الأحد","الأثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"]
24             );
25              
26             our %month = (
27             'en' => ["Muharram","Safar","Rabi'ul Awwal","Rabi'ul Akhir", "Jumadal Ula","Jumadal Akhira",
28             "Rajab","Sha'ban", "Ramadan","Shawwal","Dhul Qa'ada","Dhul Hijja"],
29              
30             'ar' => ["محرم","صفر","ربيع الأول","ربيع الثاني", "جمادي الأول","جمادي الثاني",
31             "رجب","شعبان", "رمضان","شوال","ذو القعدة","ذو الحجة"]
32             );
33             #=========================================================#
34             #Arithmetical calendar type
35             #Ic [‛15’, civil]
36             #Ia [‛15’, astronomical]
37             #IIc [‛16’, civil]
38             #IIa [‛16’, astronomical = “MS HijriCalendar”]
39             #IIIc [Fātimid, civil]
40             #IIIa [Fātimid, astronomical]
41             #IVc [Habash al-Hāsib, civil]
42             #IVa [Habash al-Hāsib, astronomical]
43              
44             # generalized modulo function (n mod m) also valid for negative values of n
45             sub gmod {
46 0     0 0   my ($n, $m) = @_;
47 0           return (($n % $m) + $m) % $m;
48             }
49              
50             sub hijri_time {
51 0     0 0   my ($time, $caltype, $lang) = @_;
52 0           my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $dst) = localtime($time);
53 0           return hijri_date($mday, $mon, $year+1900, $caltype, $lang);
54             }
55              
56             sub hijri_now {
57 0     0 0   my ($caltype, $lang) = @_;
58 0           my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $dst) = localtime(time);
59 0           return hijri_date($mday, $mon, $year+1900, $caltype, $lang);
60             }
61              
62             sub hijri_date {
63 0     0 0   my ($day, $month, $year, $caltype, $lang) = @_;
64 0           my (%ret);
65            
66             # $month: 0-11
67             # $year: yyyy
68             # $caltype: 0= Julian, 1=Gregorian
69            
70 0           $caltype += 0;
71              
72 0 0         if (!exists $weekday{$lang}) {
73 0           $lang = 'en';
74             }
75              
76 0           my $m = $month + 1;
77 0           my $y = $year;
78              
79             # append January and February to the previous year (i.e. regard March as
80             # the first month of the year in order to simplify leapday corrections)
81              
82 0 0         if ($m < 3) {
83 0           $y -= 1;
84 0           $m += 12;
85             }
86              
87             # determine offset between Julian and Gregorian calendar
88 0           my $jgc;
89 0 0         if ($y < 1583) {$jgc = 0};
  0            
90              
91 0 0         if ($y == 1582) {
92 0 0         if ($m > 10) {$jgc = 10;}
  0            
93 0 0 0       if ($m == 10 && $day < 5 ) {$jgc = 0;}
  0            
94 0 0 0       if ($m == 10 && $day > 14) {$jgc = 10;}
  0            
95 0 0 0       if ($m == 10 && $day > 4 && $day < 15) {
      0        
96 0 0         if ($caltype == 0) {
97 0           $jgc = 10;
98 0           $day += 10;
99             }
100 0 0         if ($caltype == 1) {
101 0           $jgc = 0;
102 0           $day -= 10;
103             }
104             }
105             }
106              
107 0 0         if ($y > 1582) {
108 0           $a = floor($y/100);
109 0           $jgc = $a - floor($a/4) - 2;
110             }
111              
112             # compute Chronological Julian Day Number (CJDN)
113            
114 0           my $cjdn = floor(365.25*($y + 4716)) + floor(30.6001*($m+1)) + $day - $jgc - 1524;
115              
116             # output calendar type (0 = Julian; 1 = Gregorian)
117            
118 0 0         if ($cjdn < 2299161) {
119 0           $jgc = 0;
120 0           $ret{caltype} = 0;
121             }
122              
123 0 0         if ($cjdn > 2299160) {
124 0           $ret{caltype} = 1;
125 0           $a = floor(($cjdn - 1867216.25)/36524.25);
126 0           $jgc = $a - floor($a/4) + 1;
127             }
128            
129 0           $b = $cjdn + $jgc + 1524;
130 0           my $c = floor(($b - 122.1)/365.25);
131 0           my $d = floor(365.25*$c);
132 0           $month = floor(($b - $d)/30.6001);
133 0           $day = ($b - $d) - floor(30.6001*$month);
134              
135 0 0         if ($month > 13) {
136 0           $c += 1;
137 0           $month -= 12;
138             }
139              
140 0           $month -= 1;
141 0           $year = $c - 4716;
142              
143             # output Western calendar date
144 0           $ret{day} = $day;
145 0           $ret{month} = $month - 1;
146 0           $ret{year} = $year;
147              
148             # compute weekday
149 0           my $wd = gmod($cjdn+1, 7) + 1;
150              
151             #output Julian Day Number and weekday
152 0           $ret{julday} = $cjdn;
153 0           $ret{wkday} = $wd - 1;
154 0           $ret{itoday} = $weekday{$lang}->[$wd - 1];
155            
156             # set mean length and epochs (astronomical & civilian) of the tabular Islamic year
157            
158 0           my $iyear = 10631/30;
159 0           my $epochastro = 1948084;
160 0           my $epochcivil = 1948085;
161              
162             # compute and output Islamic calendar date (type I)
163            
164 0           my $shift1 = 8.01/60; # rets in years 2, 5, 7, 10, 13, 15, 18, 21, 24, 26 & 29 as leap years
165            
166 0           my $z = $cjdn - $epochcivil;
167 0           my $cyc = floor($z/10631);
168 0           $z = $z - 10631*$cyc;
169 0           my $j = floor(($z - $shift1)/$iyear);
170 0           my $iy = 30*$cyc + $j;
171 0           $z = $z - floor($j*$iyear + $shift1);
172 0           my $im = floor(($z + 28.5001)/29.5);
173 0 0         if ($im == 13) {$im = 12;}
  0            
174 0           my $id = $z - floor(29.5001*$im - 29);
175              
176 0           $ret{iday1} = $id;
177 0           $ret{imonth1} = $im - 1;
178 0           $ret{iyear1} = $iy;
179 0           $ret{iname1} = $month{$lang}->[$im - 1];
180            
181 0           $z = $cjdn - $epochastro;
182 0           $cyc = floor($z/10631);
183 0           $z = $z - 10631*$cyc;
184 0           $j = floor(($z - $shift1)/$iyear);
185 0           $iy = 30*$cyc + $j;
186 0           $z = $z - floor($j*$iyear + $shift1);
187 0           $im = floor(($z + 28.5001)/29.5);
188 0 0         if ($im == 13) {$im = 12;}
  0            
189 0           $id = $z - floor(29.5001*$im - 29);
190              
191 0           $ret{iday2} = $id;
192 0           $ret{imonth2} = $im - 1;
193 0           $ret{iyear2} = $iy;
194 0           $ret{iname2} = $month{$lang}->[$im - 1];
195              
196             #compute and output Islamic calendar date (type II)
197              
198 0           my $shift2 = 6.01/60; # rets in years 2, 5, 7, 10, 13, 16, 18, 21, 24, 26 & 29 as leap years
199              
200 0           $z = $cjdn - $epochcivil;
201 0           $cyc = floor($z/10631);
202 0           $z = $z - 10631*$cyc;
203 0           $j = floor(($z - $shift2)/$iyear);
204 0           $iy = 30*$cyc + $j;
205 0           $z = $z - floor($j*$iyear + $shift2);
206 0           $im = floor(($z+28.5001)/29.5);
207 0 0         if ($im == 13) {$im = 12;}
  0            
208 0           $id = $z - floor(29.5001*$im - 29);
209              
210 0           $ret{iday3} = $id;
211 0           $ret{imonth3} = $im - 1;
212 0           $ret{iyear3} = $iy;
213 0           $ret{iname3} = $month{$lang}->[$im - 1];
214            
215 0           $z = $cjdn - $epochastro;
216 0           $cyc = floor($z/10631);
217 0           $z = $z - 10631*$cyc;
218 0           $j = floor(($z - $shift2)/$iyear);
219 0           $iy = 30*$cyc + $j;
220 0           $z = $z - floor($j*$iyear + $shift2);
221 0           $im = floor(($z + 28.5001)/29.5);
222 0 0         if ($im == 13) {$im = 12;}
  0            
223 0           $id = $z - floor(29.5001*$im - 29);
224              
225 0           $ret{iday4} = $id;
226 0           $ret{imonth4} = $im - 1;
227 0           $ret{iyear4} = $iy;
228 0           $ret{iname4} = $month{$lang}->[$im - 1];
229              
230             # compute and output Islamic calendar date (type III)
231              
232 0           my $shift3 = 0.01/60; # rets in years 2, 5, 8, 10, 13, 16, 19, 21, 24, 27 & 29 as leap years
233              
234 0           $z = $cjdn - $epochcivil;
235 0           $cyc = floor($z/10631);
236 0           $z = $z - 10631*$cyc;
237 0           $j = floor(($z - $shift3)/$iyear);
238 0           $iy = 30*$cyc + $j;
239 0           $z = $z - floor($j*$iyear + $shift3);
240 0           $im = floor(($z + 28.5001)/29.5);
241 0 0         if ($im == 13) {$im = 12;}
  0            
242 0           $id = $z - floor(29.5001*$im-29);
243              
244 0           $ret{iday5} = $id;
245 0           $ret{imonth5} = $im - 1;
246 0           $ret{iyear5} = $iy;
247 0           $ret{iname5} = $month{$lang}->[$im - 1];
248            
249 0           $z = $cjdn - $epochastro;
250 0           $cyc = floor($z/10631);
251 0           $z = $z - 10631*$cyc;
252 0           $j = floor(($z - $shift3)/$iyear);
253 0           $iy = 30*$cyc + $j;
254 0           $z = $z - floor($j*$iyear + $shift3);
255 0           $im = floor(($z + 28.5001)/29.5);
256 0 0         if ($im == 13) {$im = 12;}
  0            
257 0           $id = $z - floor(29.5001*$im - 29);
258              
259 0           $ret{iday6} = $id;
260 0           $ret{imonth6} = $im - 1;
261 0           $ret{iyear6} = $iy;
262 0           $ret{iname6} = $month{$lang}->[$im - 1];
263              
264             # compute and output Islamic calendar date (type IV)
265            
266 0           my $shift4 = -2.01/60; # rets in years 2, 5, 8, 11, 13, 16, 19, 21, 24, 27 & 30 as leap years
267              
268 0           $z = $cjdn - $epochcivil;
269 0           $cyc = floor($z/10631);
270 0           $z = $z - 10631*$cyc;
271 0           $j = floor(($z - $shift4)/$iyear);
272 0           $iy = 30*$cyc + $j;
273 0           $z = $z - floor($j*$iyear + $shift4);
274 0           $im = floor(($z+28.5001)/29.5);
275 0 0         if ($im == 13) {$im = 12;}
  0            
276 0           $id = $z - floor(29.5001*$im - 29);
277              
278 0           $ret{iday7} = $id;
279 0           $ret{imonth7} = $im - 1;
280 0           $ret{iyear7} = $iy;
281 0           $ret{iname7} = $month{$lang}->[$im - 1];
282              
283 0           $z = $cjdn - $epochastro;
284 0           $cyc = floor($z/10631);
285 0           $z = $z - 10631*$cyc;
286 0           $j = floor(($z - $shift4)/$iyear);
287 0           $iy = 30*$cyc + $j;
288 0           $z = $z - floor($j*$iyear + $shift4);
289 0           $im = floor(($z+28.5001)/29.5);
290 0 0         if ($im == 13) {$im = 12;}
  0            
291 0           $id = $z - floor(29.5001*$im - 29);
292              
293 0           $ret{iday8} = $id;
294 0           $ret{imonth8} = $im - 1;
295 0           $ret{iyear8} = $iy;
296 0           $ret{iname8} = $month{$lang}->[$im - 1];
297            
298 0           return %ret;
299             }
300             #=========================================================#
301             1;
302              
303             =head1 NAME
304              
305             Date::HijriDate - Hijri Islamic Dates Calendar
306              
307             =head1 SYNOPSIS
308              
309             use Date::HijriDate;
310              
311             my $day = 8; # day of the month
312             my $month = 11; # month 0..11
313             my $year = 2013; # yyyy format
314             my $caltype = 1; # (0 = Julian; 1 = Gregorian)
315             my $lang = "en"; # available languages: en, ar
316             my %ret;
317            
318             # get Hijri date for specific Gregorian day
319             #%ret = hijri_date($day, $month, $year, $caltype, $lang);
320            
321             # get current time in Hijri
322             #%ret = hijri_now($caltype, $lang);
323              
324             # get Hijri time for the specific time stamp
325             %ret = hijri_time(time, $caltype, $lang);
326              
327             # Western date
328             $ret{month}++; # returned month 0..11
329             print "Western date: $ret{day}-$ret{month}-$ret{year}\n";
330            
331             #Arithmetical calendar type day month year (AH)
332             print "'Arithmetical calendar type' day month 'year (AH)' 'month name'\n";
333            
334             # all returned month 0..11
335              
336             #Method 1 civil, astronomical
337             $ret{imonth1}++; $ret{imonth2}++;
338             print "Ic [15, civil] $ret{iday1}-$ret{imonth1}-$ret{iyear1} $ret{iname1}\n";
339             print "Ia [15, astronomical] $ret{iday2}-$ret{imonth2}-$ret{iyear2} $ret{iname2}\n";
340            
341             #Method 2 civil, astronomical
342             $ret{imonth3}++; $ret{imonth4}++;
343             print "IIc [16, civil] $ret{iday3}-$ret{imonth3}-$ret{iyear3} $ret{iname3}\n";
344             print "IIa [16, astronomical='MS HijriCalendar'] $ret{iday4}-$ret{imonth4}-$ret{iyear4} $ret{iname4}\n";
345            
346             #Method 3 civil, astronomical
347             $ret{imonth5}++; $ret{imonth6}++;
348             print "IIIc [Fātimid, civil] $ret{iday5}-$ret{imonth5}-$ret{iyear5} $ret{iname5}\n";
349             print "IIIa [Fātimid, astronomical] $ret{iday6}-$ret{imonth6}-$ret{iyear6} $ret{iname6}\n";
350            
351             #Method 4 civil, astronomical
352             $ret{imonth7}++; $ret{imonth8}++;
353             print "IVc [Habash al-Hāsib, civil] $ret{iday7}-$ret{imonth7}-$ret{iyear7} $ret{iname7}\n";
354             print "IVa [Habash al-Hāsib, astronomical] $ret{iday8}-$ret{imonth8}-$ret{iyear8} $ret{iname8}\n";
355            
356             print "Julian day: $ret{julday}\n";
357             print "Weekday number 0..7, 0=Sunday: $ret{wkday}\n";
358             print "Hijri day name: $ret{itoday}\n";
359             print "Calender type: ". (($ret{caltype} == 1)? "Gregorian" : "Julian") . "\n";
360             print "\n\n";
361              
362             # print all dates information for all 8 calculation methods
363             foreach my $k(sort keys %ret) {
364             print "$k = $ret{$k}\n";
365             }
366            
367             # output
368              
369             Western date: 9-12-2013
370             'Arithmetical calendar type' day-month-'year (AH)' 'month name'
371             Ic [15, civil] 5-2-1435 Safar
372             Ia [15, astronomical] 6-2-1435 Safar
373             IIc [16, civil] 5-2-1435 Safar
374             IIa [16, astronomical='MS HijriCalendar'] 6-2-1435 Safar
375             IIIc [Fātimid, civil] 5-2-1435 Safar
376             IIIa [Fātimid, astronomical] 6-2-1435 Safar
377             IVc [Habash al-Hāsib, civil] 5-2-1435 Safar
378             IVa [Habash al-Hāsib, astronomical] 6-2-1435 Safar
379             Julian day: 2456636
380             Weekday number 0..7, 0=Sunday: 1
381             Hijri day name: Ithnin
382             Calender type: Gregorian
383              
384             =head1 DESCRIPTION
385              
386             This module calculates Islamic Hijri calender dates using civil and astronomical 8 methods.
387              
388             Arithmetical calendar type:
389             Ic [15, civil]
390             Ia [15, astronomical]
391             IIc [16, civil]
392             IIa [16, astronomical = "MS HijriCalendar"]
393             IIIc [Fātimid, civil]
394             IIIa [Fātimid, astronomical]
395             IVc [Habash al-Hāsib, civil]
396             IVa [Habash al-Hāsib, astronomical]
397              
398             Exports three methods hijri_time, hijri_now, and hijri_date.
399             All methods return date information in a single hash.
400              
401             %ret = hijri_time($time, $caltype, $lang);
402             $time: unix time stamp;
403             $caltype: 0 = Julian, 1 = Gregorian
404             $lang: en, ar only currently supported for weekday and month names.
405            
406             %ret = hijri_now($caltype, $lang)
407             return current Hijri time
408              
409             %ret = hijri_date($day, $month, $year, $caltype, $lang)
410             return Hijri date for a given western date.
411             $month: 0..11
412             $year: yyyy format
413              
414             =head1 SEE ALSO
415              
416             L
417             L
418             L
419             L
420              
421             =head1 AUTHOR
422              
423             Ahmed Amin Elsheshtawy,
424             Website: http://www.islamware.com http://www.mewsoft.com
425              
426             =head1 COPYRIGHT AND LICENSE
427              
428             Copyright (C) 2013 by Dr. Ahmed Amin Elsheshtawy webmaster@islamware.com,
429             L
430             L
431              
432             This library is free software; you can redistribute it and/or modify
433             it under the same terms as Perl itself.
434              
435             =cut
436