File Coverage

blib/lib/Date/Utils/Hijri.pm
Criterion Covered Total %
statement 18 44 40.9
branch 0 8 0.0
condition 0 15 0.0
subroutine 6 14 42.8
pod 8 8 100.0
total 32 89 35.9


line stmt bran cond sub pod time code
1             package Date::Utils::Hijri;
2              
3             $Date::Utils::Hijri::VERSION = '0.01';
4              
5             =head1 NAME
6              
7             Date::Utils::Hijri - Hijri date specific routines as Moo Role.
8              
9             =head1 VERSION
10              
11             Version 0.01
12              
13             =cut
14              
15 1     1   20457 use 5.006;
  1         4  
  1         55  
16 1     1   638 use Data::Dumper;
  1         12659  
  1         89  
17 1     1   10 use List::Util qw/min/;
  1         7  
  1         112  
18 1     1   774 use POSIX qw/floor ceil/;
  1         7122  
  1         8  
19              
20 1     1   1998 use Moo::Role;
  1         26576  
  1         9  
21 1     1   983 use namespace::clean;
  1         13465  
  1         7  
22              
23             our $HIJRI_MONTHS = [
24             undef,
25             q/Muharram/, q/Safar/ , q/Rabi' al-awwal/, q/Rabi' al-thani/,
26             q/Jumada al-awwal/, q/Jumada al-thani/, q/Rajab/ , q/Sha'aban/,
27             q/Ramadan/ , q/Shawwal/ , q/Dhu al-Qi'dah/ , q/Dhu al-Hijjah/
28             ];
29              
30             our $HIJRI_DAYS = [
31             ' al-Ahad ',
32             ' al-Ithnayn ',
33             ' ath-Thulatha ',
34             ' al-Arbia ',
35             ' al-Khamis ',
36             ' al-Jumuah ',
37             ' as-Sabt ',
38             ];
39              
40             our $HIJRI_LEAP_YEAR_MOD = [
41             2, 5, 7, 10, 13, 16, 18, 21, 24, 26, 29
42             ];
43              
44             has hijri_epoch => (is => 'ro', default => sub { 1948439.5 });
45             has hijri_days => (is => 'ro', default => sub { $HIJRI_DAYS });
46             has hijri_months => (is => 'ro', default => sub { $HIJRI_MONTHS });
47             has hijri_leap_year_mod => (is => 'ro', default => sub { $HIJRI_LEAP_YEAR_MOD });
48              
49             with 'Date::Utils';
50              
51             =head1 DESCRIPTION
52              
53             Hijri date specific routines as Moo Role.
54              
55             =head1 METHODS
56              
57             =head2 hijri_to_julian($year, $month, $day)
58              
59             Returns Julian date of the given Hijri date.
60              
61             =cut
62              
63             sub hijri_to_julian {
64 0     0 1   my ($self, $year, $month, $day) = @_;
65              
66 0           return ($day + ceil(29.5 * ($month - 1)) + ($year - 1) * 354 + floor((3 + (11 * $year)) / 30) + $self->hijri_epoch) - 1;
67             }
68              
69             =head2 julian_to_hijri($julian_date)
70              
71             Returns Hijri date as list (year, month, day) equivalent of the given Julian date.
72              
73             =cut
74              
75             sub julian_to_hijri {
76 0     0 1   my ($self, $julian) = @_;
77              
78 0           $julian = floor($julian) + 0.5;
79 0           my $year = floor(((30 * ($julian - $self->hijri_epoch)) + 10646) / 10631);
80 0           my $month = min(12, ceil(($julian - (29 + $self->hijri_to_julian($year, 1, 1))) / 29.5) + 1);
81 0           my $day = ($julian - $self->hijri_to_julian($year, $month, 1)) + 1;
82              
83 0           return ($year, $month, $day);
84             }
85              
86             =head2 hijri_to_gregorian($year, $month, $day)
87              
88             Returns Gregorian date as list (year, month, day) equivalent of the given Hijri
89             date.
90              
91             =cut
92              
93             sub hijri_to_gregorian {
94 0     0 1   my ($self, $year, $month, $day) = @_;
95              
96 0           $self->validate_date($year, $month, $day);
97 0           return $self->julian_to_gregorian($self->hijri_to_julian($year, $month, $day));
98             }
99              
100             =head2 gregorian_to_hijri($year, $month, $day)
101              
102             Returns Hijri date as list (year, month, day) equivalent of the given Gregorian
103             date.
104              
105             =cut
106              
107             sub gregorian_to_hijri {
108 0     0 1   my ($self, $year, $month, $day) = @_;
109              
110 0           ($year, $month, $day) = $self->julian_to_hijri($self->gregorian_to_julian($year, $month, $day));
111 0           return ($year, $month, $day);
112             }
113              
114             =head2 is_hijri_leap_year($year)
115              
116             Returns 0 or 1 if the given Hijri year C<$year> is a leap year or not.
117              
118             =cut
119              
120             sub is_hijri_leap_year {
121 0     0 1   my ($self, $year) = @_;
122              
123 0           my $mod = $year % 30;
124 0 0         return 1 if grep/$mod/, @{$self->hijri_leap_year_mod};
  0            
125 0           return 0;
126             }
127              
128             =head2 days_in_hijri_year($year)
129              
130             Returns the number of days in the given year of Hijri Calendar.
131              
132             =cut
133              
134             sub days_in_hijri_year {
135 0     0 1   my ($self, $year) = @_;
136              
137 0 0         ($self->is_hijri_leap_year($year))
138             ?
139             (return 355)
140             :
141             (return 354);
142             }
143              
144             =head2 days_in_hijri_month_year($month, $year)
145              
146             Returns total number of days in the given Hijri month year.
147              
148             =cut
149              
150             sub days_in_hijri_month_year {
151 0     0 1   my ($self, $month, $year) = @_;
152              
153 0 0 0       return 30 if (($month % 2 == 1) || (($month == 12) && (is_hijri_leap_year($year))));
      0        
154 0           return 29;
155              
156             }
157              
158             =head2 validate_day($day)
159              
160             =cut
161              
162             sub validate_day {
163 0     0 1   my ($self, $day) = @_;
164              
165 0 0 0       die("ERROR: Invalid day [$day].\n")
      0        
      0        
166             unless (defined($day) && ($day =~ /^\d{1,2}$/) && ($day >= 1) && ($day <= 30));
167             }
168              
169             =head1 AUTHOR
170              
171             Mohammad S Anwar, C<< >>
172              
173             =head1 REPOSITORY
174              
175             L
176              
177             =head1 ACKNOWLEDGEMENTS
178              
179             Entire logic is based on the L written by John Walker.
180              
181             =head1 BUGS
182              
183             Please report any bugs / feature requests to C
184             , or through the web interface at L.
185             I will be notified, and then you'll automatically be notified of progress on your
186             bug as I make changes.
187              
188             =head1 SUPPORT
189              
190             You can find documentation for this module with the perldoc command.
191              
192             perldoc Date::Utils::Hijri
193              
194             You can also look for information at:
195              
196             =over 4
197              
198             =item * RT: CPAN's request tracker
199              
200             L
201              
202             =item * AnnoCPAN: Annotated CPAN documentation
203              
204             L
205              
206             =item * CPAN Ratings
207              
208             L
209              
210             =item * Search CPAN
211              
212             L
213              
214             =back
215              
216             =head1 LICENSE AND COPYRIGHT
217              
218             Copyright (C) 2015 Mohammad S Anwar.
219              
220             This program is free software; you can redistribute it and / or modify it under
221             the terms of the the Artistic License (2.0). You may obtain a copy of the full
222             license at:
223              
224             L
225              
226             Any use, modification, and distribution of the Standard or Modified Versions is
227             governed by this Artistic License.By using, modifying or distributing the Package,
228             you accept this license. Do not use, modify, or distribute the Package, if you do
229             not accept this license.
230              
231             If your Modified Version has been derived from a Modified Version made by someone
232             other than you,you are nevertheless required to ensure that your Modified Version
233             complies with the requirements of this license.
234              
235             This license does not grant you the right to use any trademark, service mark,
236             tradename, or logo of the Copyright Holder.
237              
238             This license includes the non-exclusive, worldwide, free-of-charge patent license
239             to make, have made, use, offer to sell, sell, import and otherwise transfer the
240             Package with respect to any patent claims licensable by the Copyright Holder that
241             are necessarily infringed by the Package. If you institute patent litigation
242             (including a cross-claim or counterclaim) against any party alleging that the
243             Package constitutes direct or contributory patent infringement,then this Artistic
244             License to you shall terminate on the date that such litigation is filed.
245              
246             Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND
247             CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED
248             WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
249             NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL LAW. UNLESS
250             REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT,
251             INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE
252             OF THE PACKAGE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
253              
254             =cut
255              
256             1; # End of Date::Utils::Hijri