File Coverage

blib/lib/DateTime/Event/Jewish/Parshah.pm
Criterion Covered Total %
statement 103 106 97.1
branch 49 56 87.5
condition 18 20 90.0
subroutine 12 12 100.0
pod 2 2 100.0
total 184 196 93.8


line stmt bran cond sub pod time code
1             package DateTime::Event::Jewish::Parshah;
2              
3             =head1 NAME
4              
5             DateTime::Event::Jewish::Parshah - Calculate leyning for next
6             shabbat
7              
8             =head1 SYNOPSIS
9              
10             use DateTime::Event::Jewish::Parshah qw(parshah);
11              
12             my $parshah = parshah(DateTime->today, $israel);
13              
14             =head1 DESCRIPTION
15              
16             Returns either a parshah name or a yom tov name for the Shabbat
17             after the date supplied. The optional I flag specifies
18             whether to calculate the leyning for Israel or for the diaspora.
19              
20              
21             =cut
22              
23 6     6   695430 use strict;
  6         11  
  6         211  
24 6     6   25 use warnings;
  6         8  
  6         133  
25 6     6   21 use DateTime;
  6         10  
  6         110  
26 6     6   27 use DateTime::Duration;
  6         7  
  6         101  
27 6     6   3587 use DateTime::Calendar::Hebrew;
  6         22592  
  6         187  
28 6     6   2353 use DateTime::Event::Jewish::Yomtov qw(@festival);
  6         11  
  6         806  
29 6     6   2032 use DateTime::Event::Jewish::Sedrah qw(@sedrah);
  6         12  
  6         615  
30 6     6   29 use base qw(Exporter);
  6         7  
  6         324  
31 6     6   24 use vars qw(@EXPORT_OK);
  6         7  
  6         4403  
32             @EXPORT_OK = qw(nextShabbat parshah);
33             our $VERSION = '0.01';
34              
35             our %YomTovMap;
36             our %IsraelYomTovMap;
37             our %YomTovYear;
38              
39             =head3 _initYomTov($year)
40              
41             Internal function that initialises the yom tov table for the
42             year in question.
43              
44             =cut
45              
46             sub _initYomTov {
47 1746     1746   2052 my $year = shift;
48 1746 100       4574 return if $YomTovYear{$year};
49 227         853 my $f = DateTime::Calendar::Hebrew->today;
50 227         245697 foreach my $yt (@festival)
51             {
52 4994         6919 my ($name, $day, $month, $diaspora) = @$yt;
53 4994         11840 $f->set(year=>$year, month=>$month, day=>$day);
54 4994         589977 my $fDays = $f->{rd_days};
55 4994         10795 $YomTovMap{$fDays} = $name;
56 4994 100       13378 $IsraelYomTovMap{$fDays} = $name unless $diaspora;
57             }
58 227         1030 $YomTovYear{$year} = 1;
59             }
60              
61              
62              
63             # (C) Raphael Mankin 2009
64              
65             # The algorithm for calculating the weekly parshah is taken
66             # from http://individual.utoronto.ca/kalendis/hebrew/parshah.htm
67              
68             =head3 nextShabbat($date)
69              
70             Returns the next Shabbat which is strictly after $date. The
71             returned object is a Hewbrew date.
72              
73             $date is some sort of DateTime object; it does not matter which.
74              
75             =cut
76              
77             sub nextShabbat {
78 1164     1164 1 5741 my $date = DateTime->from_object(object=>shift)->add(days=>1);
79 1164         941371 while ($date->day_of_week != 6) {
80 2329         630644 $date->add(days=>1);
81             }
82 1164         353636 return DateTime::Calendar::Hebrew->from_object(object=>$date);
83             }
84              
85             =head3 parshah($date ,[$israel])
86              
87             Returns the parshah name or a yomtov name for the Shabbat
88             strictly after $date.
89              
90             $date is some sort of DateTime object; it does not matter which.
91              
92             $israel is an optional flag to indicate that we should use the
93             logic for Israel rather than the Diaspora.
94              
95             See http://individual.utoronto.ca/kalendis/hebrew/parshah.htm for
96             the logic of this code.
97              
98             =cut
99              
100             sub parshah {
101 582     582 1 1647527 my $today = shift;
102 582   100     2595 my $israel = shift || 0;
103              
104 582         1518 my $targetShabbat = nextShabbat($today);
105 582         631335 my $thisYear = $targetShabbat->year();
106 582         3555 _initYomTov($thisYear-1);
107 582         1017 _initYomTov($thisYear);
108 582         1075 _initYomTov($thisYear+1);
109 582 100       1518 if ($israel) {
110 291 50       1099 if (exists $IsraelYomTovMap{$targetShabbat->{rd_days}}) {
111 0         0 return $IsraelYomTovMap{$targetShabbat->{rd_days}};
112             }
113             } else {
114 291 50       1321 if (exists $YomTovMap{$targetShabbat->{rd_days}}) {
115 0         0 return $YomTovMap{$targetShabbat->{rd_days}};
116             }
117             }
118 582         1800 my $thisMonth = $targetShabbat->month();
119 582         3046 my $thisDay = $targetShabbat->day();
120             # Get the date of last Simchat Torah, bearing in mind that
121             # the year begins in Nissan.
122 582 50 33     4961 my $simchatTorah =
123             DateTime::Calendar::Hebrew->new(month=>7,
124             day=>23-$israel,
125             year=>($thisMonth==7 && $thisDay<23-$israel )? $thisYear-1: $thisYear);
126              
127             # The next few dates only matter if we are in the right part of the year.
128             # Otherwise, the dates are not used and it is of no
129             # consequence which year we calculate. The calculation is
130             # relative to 'workingShabbat', not relative to
131             # 'targetShabbat'.
132             #
133             # The date of Pesach
134 582 50       51021 my $pesach = DateTime::Calendar::Hebrew->new(month=>1, day=>15,
135             year=>($thisMonth==7 ? $thisYear-1: $thisYear));
136             # The date of 9 Av
137 582 50       100057 my $tishaBAv = DateTime::Calendar::Hebrew->new(month=>5, day=>9,
138             year=>($thisMonth==7 ? $thisYear-1: $thisYear) );
139             # The date of RoshHashanah
140 582 50       110249 my $RoshHashanah= DateTime::Calendar::Hebrew->new(month=>7, day=>1,
141             year=>($thisMonth==7 ? $thisYear : $thisYear+1));
142 582         43916 my $workingShabbat =
143             nextShabbat($simchatTorah)->subtract_duration(DateTime::Duration->new(days=>7));
144 582         580061 my $startDay = $workingShabbat->{rd_days};
145 582         1225 my $endDay = $targetShabbat->{rd_days};
146 582         1287 my $parshahNumber = int(($endDay-$startDay)/7);
147              
148              
149             #print "Next Shabbat: " , $targetShabbat->ymd, "\n";
150              
151 582 50       1555 if ($parshahNumber < 22) { # No special Shabbattot
152 0         0 return $sedrah[$parshahNumber];
153             }
154              
155             # From week 22 onwards there are special cases
156 582         744 $parshahNumber = 21;
157 582         2176 $workingShabbat->add_duration(DateTime::Duration->new(days=>21*7));
158 582         465483 my $leapYear = DateTime::Calendar::Hebrew::_leap_year($simchatTorah->year);
159 582         4938 my $wDayPesach = $pesach->day_of_week;
160 582         3564 my $combined = 0;
161            
162             #print "leap year: $leapYear\tPesach $wDayPesach\n";
163            
164              
165             LOOP:
166 582         2614 while ($workingShabbat < $targetShabbat) {
167 3398         82998 $workingShabbat->add_duration(DateTime::Duration->new(days=> 7));
168             # If the Shabbat in question is yom tov or chol hamoed
169             # it does not count towards the parshah count.
170 3398 100 100     2951796 if ($israel && exists $IsraelYomTovMap{$workingShabbat->{rd_days}}) {next;}
  60         188  
171 3338 100 100     13051 if (!$israel && exists $YomTovMap{$workingShabbat->{rd_days}}) {next;}
  92         280  
172 3246         4395 my $workingDays = $workingShabbat->{rd_days};
173 3246 100       5139 $parshahNumber++ if ($combined);
174 3246         3037 $combined = 0;
175 3246         2597 $parshahNumber++;
176 3246 100       7755 if($parshahNumber==22) { #Vayakhel
177             # Combine Vayakhel/Pekudei if there are fewer than 4
178             # Shabbatot *before* the first day of Pesach
179 582         871 my $pesachDays = $pesach->{rd_days};
180 582 100       1521 $combined =1 if ($pesachDays - $workingDays < 22);
181 582         2422 next LOOP;
182             }
183 2664 100 100     8495 if($parshahNumber ==27 || # Tazria
184             $parshahNumber ==29) { # Acharei Mot
185 240 100       484 $combined = 1 if (!$leapYear);
186 240         806 next LOOP;
187             }
188 2424 100       3689 if($parshahNumber == 32) { # Behar
189 120 100       304 if ($israel) {
190             # In Israel we need to change the condition to
191             # not a leap year and Pesach not on Shabbat.
192             # Ths can only happen in a 354 day year that
193             # started on a thursday.
194 60 100 100     242 $combined = 1 if (!$leapYear && $wDayPesach != 7);
195             } else {
196             # if Pesach falls on Shabbat then Pesach8 is
197             # also on Shabbat. This is not relevant in
198             # Israel.
199 60 100       146 $combined = 1 if (!$leapYear);
200             }
201 120         452 next LOOP;
202             }
203 2304 100       3521 if($parshahNumber == 39) { # Chukat
204             # If Pesach falls on Thursday then Shavuot2 is Shabbat
205             # In Israel never combine because Shavuot can never be Shabbat
206 120 100 100     506 $combined = 1 if( $wDayPesach == 5 && !$israel);
207 120         541 next LOOP;
208             }
209 2184 100       3363 if($parshahNumber == 42) { # Mattot
210             # Devraim is always read on the Shabbat before
211             # Tisha B'Av. If 9 Av falls on Shabbat, then
212             # we read Devarim actually on 9 Av.
213 120         241 my $avDays = $tishaBAv->{rd_days};
214 120 100       327 $combined = 1 if (($avDays - $workingDays) < 14);
215 120         478 next LOOP;
216             }
217 2064 100       7510 if(51 == $parshahNumber ) { # Nitzavim
218             # Is there a Shabbat between YC and Succot?
219 60         122 my $roshDays = $RoshHashanah->{rd_days};
220 60 100       159 $combined = 1
221             if (($roshDays - $workingDays) > 3);
222 60         278 next LOOP;
223             }
224             }
225              
226 582         15341 my $parshah = $sedrah[$parshahNumber];
227 582 100       1217 $parshah .= "/" . $sedrah[$parshahNumber+1] if ($combined);
228              
229 582         6637 return $parshah;
230              
231             }
232              
233             =head1 BUGS
234              
235             DateTime::Calendar::Hebrew is not a sub-class of DateTime. It
236             does not implement the all functionality of DateTime, and where it
237             does implement it, it uses different names and interfaces.
238             In particular, none of the arithmetic works.
239              
240             =cut
241              
242             1;
243              
244             =head1 AUTHOR
245              
246             Raphael Mankin, C<< >>
247              
248             =head1 BUGS
249              
250             Please report any bugs or feature requests to C, or through
251             the web interface at L. I will be notified, and then you'll
252             automatically be notified of progress on your bug as I make changes.
253              
254              
255              
256              
257             =head1 SUPPORT
258              
259             You can find documentation for this module with the perldoc command.
260              
261             perldoc DateTime::Event::Jewish
262              
263              
264             You can also look for information at:
265              
266             =over 4
267              
268             =item * RT: CPAN's request tracker
269              
270             L
271              
272             =item * AnnoCPAN: Annotated CPAN documentation
273              
274             L
275              
276             =item * CPAN Ratings
277              
278             L
279              
280             =item * Search CPAN
281              
282             L
283              
284             =back
285              
286              
287             =head1 ACKNOWLEDGEMENTS
288              
289              
290             =head1 LICENSE AND COPYRIGHT
291              
292             Copyright 2010 Raphael Mankin.
293              
294             This program is free software; you can redistribute it and/or modify it
295             under the terms of either: the GNU General Public License as published
296             by the Free Software Foundation; or the Artistic License.
297              
298             See http://dev.perl.org/licenses/ for more information.
299              
300              
301             =cut
302              
303             1; # End of DateTime::Event::Parshah