File Coverage

blib/lib/Date/Utils/Bahai.pm
Criterion Covered Total %
statement 59 59 100.0
branch 9 16 56.2
condition 7 21 33.3
subroutine 14 14 100.0
pod 7 7 100.0
total 96 117 82.0


line stmt bran cond sub pod time code
1             package Date::Utils::Bahai;
2              
3             $Date::Utils::Bahai::VERSION = '0.03';
4              
5             =head1 NAME
6              
7             Date::Utils::Bahai - Bahai date specific routines as Moo Role.
8              
9             =head1 VERSION
10              
11             Version 0.03
12              
13             =cut
14              
15 2     2   23832 use 5.006;
  2         7  
  2         70  
16 2     2   1404 use Data::Dumper;
  2         12815  
  2         143  
17 2     2   1129 use POSIX qw/floor/;
  2         11412  
  2         18  
18 2     2   3599 use Astro::Utils;
  2         218774  
  2         157  
19              
20 2     2   541 use Moo::Role;
  2         13488  
  2         14  
21 2     2   1045 use namespace::clean;
  2         6274  
  2         14  
22              
23             our $BAHAI_MONTHS = [
24             '',
25             'Baha', 'Jalal', 'Jamal', 'Azamat', 'Nur', 'Rahmat',
26             'Kalimat', 'Kamal', 'Asma', 'Izzat', 'Mashiyyat', 'Ilm',
27             'Qudrat', 'Qawl', 'Masail', 'Sharaf', 'Sultan', 'Mulk',
28             'Ala'
29             ];
30              
31             our $BAHAI_CYCLES = [
32             '',
33             'Alif', 'Ba', 'Ab', 'Dal', 'Bab', 'Vav',
34             'Abad', 'Jad', 'Baha', 'Hubb', 'Bahhaj', 'Javab',
35             'Ahad', 'Vahhab', 'Vidad', 'Badi', 'Bahi', 'Abha',
36             'Vahid'
37             ];
38              
39             our $BAHAI_DAYS = [
40             ' Jamal ',
41             ' Kamal ',
42             ' Fidal ',
43             ' Idal ',
44             ' Istijlal ',
45             ' Istiqlal ',
46             ' Jalal '
47             ];
48              
49             has bahai_epoch => (is => 'ro', default => sub { 2394646.5 });
50             has bahai_days => (is => 'ro', default => sub { $BAHAI_DAYS });
51             has bahai_months => (is => 'ro', default => sub { $BAHAI_MONTHS });
52             has bahai_cycles => (is => 'ro', default => sub { $BAHAI_CYCLES });
53              
54             with 'Date::Utils';
55              
56             =head1 DESCRIPTION
57              
58             Bahai date specific routines as Moo Role.
59              
60             =head1 METHODS
61              
62             =head2 bahai_to_gregorian($major, $cycle, $year, $month, $day)
63              
64             Returns Gregorian date as list (year, month, day) equivalent of the given bahai
65             date.
66              
67             =cut
68              
69             sub bahai_to_gregorian {
70 1     1 1 285 my ($self, $major, $cycle, $year, $month, $day) = @_;
71              
72 1         4 return $self->julian_to_gregorian($self->bahai_to_julian($major, $cycle, $year, $month, $day));
73             }
74              
75             =head2 gregorian_to_bahai($year, $month, $day)
76              
77             Returns Bahai date component as list (majaor, cycle, year, month, day) equivalent
78             of the given gregorian date.
79              
80             =cut
81              
82             sub gregorian_to_bahai {
83 1     1 1 464 my ($self, $year, $month, $day) = @_;
84              
85 1         7 return $self->julian_to_bahai($self->gregorian_to_julian($year, $month, $day));
86             }
87              
88             =head2 bahai_to_julian($major, $cycle, $year, $month, $day)
89              
90             Returns julian date of the given bahai date.
91              
92             =cut
93              
94             sub bahai_to_julian {
95 8     8 1 733 my ($self, $major, $cycle, $year, $month, $day) = @_;
96              
97 8         27 my ($g_year) = $self->julian_to_gregorian($self->bahai_epoch);
98 8         297 my $gy = (361 * ($major - 1)) +
99             (19 * ($cycle - 1)) +
100             ($year - 1) + $g_year;
101              
102 8         17 my ($gm, $gd) = _vernal_equinox_month_day($gy);
103              
104 8 50       22 return $self->gregorian_to_julian($gy, $gm, $gd)
    100          
105             +
106             (19 * ($month - 1))
107             +
108             (($month != 20) ? 0 : ($self->is_gregorian_leap_year($gy + 1) ? -14 : -15))
109             +
110             $day;
111             }
112              
113             =head2 julian_to_bahai($julian_date)
114              
115             Returns Bahai date component as list (majaor, cycle, year, month, day) equivalent
116             of the given Julian date C<$julian_date>.
117              
118             =cut
119              
120             sub julian_to_bahai {
121 2     2 1 762 my ($self, $julian_date) = @_;
122              
123 2         7 $julian_date = floor($julian_date) + 0.5;
124 2         26 my $gregorian_year = ($self->julian_to_gregorian($julian_date))[0];
125 2         695 my $start_year = ($self->julian_to_gregorian($self->bahai_epoch))[0];
126              
127 2         62 my $j1 = $self->gregorian_to_julian($gregorian_year, 1, 1);
128 2         12 my ($gm, $gd) = _vernal_equinox_month_day($gregorian_year);
129 2         7 my $j2 = $self->gregorian_to_julian($gregorian_year, $gm, $gd);
130              
131 2 50 33     41 my $bahai_year = $gregorian_year - ($start_year + ((($j1 <= $julian_date) && ($julian_date <= $j2)) ? 1 : 0));
132 2         8 my ($major, $cycle, $year) = $self->get_major_cycle_year($bahai_year);
133              
134 2         6 my $days = $julian_date - $self->bahai_to_julian($major, $cycle, $year, 1, 1);
135 2         34 my $bld = $self->bahai_to_julian($major, $cycle, $year, 20, 1);
136 2 50       45 my $month = ($julian_date >= $bld) ? 20 : (floor($days / 19) + 1);
137 2         6 my $day = ($julian_date + 1) - $self->bahai_to_julian($major, $cycle, $year, $month, 1);
138              
139 2         39 return ($major, $cycle, $year, $month, $day);
140             }
141              
142             =head2 get_major_cycle_year($bahai_year)
143              
144             Returns the attribute as list major, cycle & year as in Kull-i-Shay) of the given
145             Bahai year C<$bahai_year>.
146              
147             =cut
148              
149             sub get_major_cycle_year {
150 3     3 1 6 my ($self, $bahai_year) = @_;
151              
152 3         11 my $major = floor($bahai_year / 361) + 1;
153 3         8 my $cycle = floor(($bahai_year % 361) / 19) + 1;
154 3         5 my $year = ($bahai_year % 19) + 1;
155              
156 3         6 return ($major, $cycle, $year);
157             }
158              
159             =head2 validate_month($month)
160              
161             Dies if the given C<$month> is not a valid Bahai month.
162              
163             =cut
164              
165             sub validate_month {
166 1     1 1 487 my ($self, $month) = @_;
167              
168 1 50 33     28 die("ERROR: Invalid month [$month].\n")
      33        
      33        
169             unless (defined($month) && ($month =~ /^\d{1,2}$/) && ($month >= 1) && ($month <= 19));
170             }
171              
172             =head2 validate_day($day)
173              
174             Dies if the given C<$day> is not a valid Bahai day.
175              
176             =cut
177              
178             sub validate_day {
179 1     1 1 263 my ($self, $day) = @_;
180              
181 1 50 33     20 die ("ERROR: Invalid day [$day].\n")
      33        
      33        
182             unless (defined($day) && ($day =~ /^\d{1,2}$/) && ($day >= 1) && ($day <= 19));
183             }
184              
185             #
186             #
187             # PRIVATE METHODS
188              
189             sub _vernal_equinox_month_day {
190 10     10   9 my ($year) = @_;
191              
192             # Source: Wikipedia
193             # In 2014, the Universal House of Justice selected Tehran, the birthplace of
194             # Baha'u'lláh, as the location to which the date of the vernal equinox is to
195             # be fixed, thereby "unlocking" the Badi calendar from the Gregorian calendar.
196             # For determining the dates, astronomical tables from reliable sources are
197             # used.
198             # In the same message the Universal House of Justice decided that the
199             # birthdays of the Bab and Baha'u'lláh will be celebrated on "the first and
200             # the second day following the occurrence of the eighth new moon after
201             # Naw-Ruz" (also with the use of astronomical tables) and fixed the dates of
202             # the Bahaí Holy Days in the Baha'í calendar, standardizing dates for Baha'ís
203             # worldwide. These changes came into effect as of sunset on 20 March 2015.The
204             # changes take effect from the next Bahai New Year, from sunset on March 20,
205             # 2015.
206              
207 10         11 my $month = 3;
208 10         6 my $day = 20;
209              
210 10 50       27 if ($year >= 2015) {
211 10         28 my $equinox_date = calculate_equinox('mar', 'utc', $year);
212 10 50       9178 if ($equinox_date =~ /\d{4}\-(\d{2})\-(\d{2})\s/) {
213 10         24 $month = $1;
214 10         18 $day = $2;
215             }
216             }
217              
218 10         22 return ($month, $day);
219             }
220              
221             =head1 AUTHOR
222              
223             Mohammad S Anwar, C<< >>
224              
225             =head1 REPOSITORY
226              
227             L
228              
229             =head1 ACKNOWLEDGEMENTS
230              
231             Entire logic is based on the L written by John Walker.
232              
233             =head1 BUGS
234              
235             Please report any bugs / feature requests to C
236             , or through the web interface at L.
237             I will be notified, and then you'll automatically be notified of progress on your
238             bug as I make changes.
239              
240             =head1 SUPPORT
241              
242             You can find documentation for this module with the perldoc command.
243              
244             perldoc Date::Utils::Bahai
245              
246             You can also look for information at:
247              
248             =over 4
249              
250             =item * RT: CPAN's request tracker
251              
252             L
253              
254             =item * AnnoCPAN: Annotated CPAN documentation
255              
256             L
257              
258             =item * CPAN Ratings
259              
260             L
261              
262             =item * Search CPAN
263              
264             L
265              
266             =back
267              
268             =head1 LICENSE AND COPYRIGHT
269              
270             Copyright (C) 2015 Mohammad S Anwar.
271              
272             This program is free software; you can redistribute it and / or modify it under
273             the terms of the the Artistic License (2.0). You may obtain a copy of the full
274             license at:
275              
276             L
277              
278             Any use, modification, and distribution of the Standard or Modified Versions is
279             governed by this Artistic License.By using, modifying or distributing the Package,
280             you accept this license. Do not use, modify, or distribute the Package, if you do
281             not accept this license.
282              
283             If your Modified Version has been derived from a Modified Version made by someone
284             other than you,you are nevertheless required to ensure that your Modified Version
285             complies with the requirements of this license.
286              
287             This license does not grant you the right to use any trademark, service mark,
288             tradename, or logo of the Copyright Holder.
289              
290             This license includes the non-exclusive, worldwide, free-of-charge patent license
291             to make, have made, use, offer to sell, sell, import and otherwise transfer the
292             Package with respect to any patent claims licensable by the Copyright Holder that
293             are necessarily infringed by the Package. If you institute patent litigation
294             (including a cross-claim or counterclaim) against any party alleging that the
295             Package constitutes direct or contributory patent infringement,then this Artistic
296             License to you shall terminate on the date that such litigation is filed.
297              
298             Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND
299             CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED
300             WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
301             NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL LAW. UNLESS
302             REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT,
303             INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE
304             OF THE PACKAGE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
305              
306             =cut
307              
308             1; # End of Date::Utils::Bahai