File Coverage

blib/lib/Date/Holidays/DE.pm
Criterion Covered Total %
statement 15 166 9.0
branch 0 32 0.0
condition 0 6 0.0
subroutine 5 7 71.4
pod 0 1 0.0
total 20 212 9.4


line stmt bran cond sub pod time code
1             package Date::Holidays::DE;
2              
3 1     1   5494 use strict;
  1         2  
  1         29  
4 1     1   6 use warnings;
  1         1  
  1         26  
5              
6             # Stock modules
7 1     1   501 use Time::Local;
  1         2282  
  1         60  
8 1     1   523 use POSIX qw(strftime);
  1         8552  
  1         5  
9              
10             # Prerequisite
11 1     1   1947 use Date::Calc qw(Add_Delta_Days Easter_Sunday Day_of_Week This_Year);
  1         8376  
  1         1668  
12              
13             require Exporter;
14              
15             our @ISA = qw(Exporter);
16             our @EXPORT_OK = qw(holidays);
17             our $VERSION = '2.05';
18              
19             sub holidays{
20 0     0 0   my %parameters = (
21             YEAR => This_Year(),
22             WHERE => ['common'],
23             FORMAT => "%s",
24             WEEKENDS => 1,
25             @_,
26             );
27              
28             # Easter is the key to everything
29 0           my ($year, $month, $day) = Easter_Sunday($parameters{'YEAR'});
30              
31             # Aliases for holidays
32             #
33             # neuj = Neujahr
34             # hl3k = Dreikoenigstag
35             # romo = Rosenmontag
36             # fadi = Faschingsdienstag
37             # asmi = Aschermittwoch
38             # frau = Internationaler Frauentag
39             # befr = Tag der Befreiung
40             # grdo = Gruendonnerstag
41             # karf = Karfreitag
42             # kars = Karsamstag
43             # osts = Ostersonntag
44             # ostm = Ostermontag
45             # pfis = Pfingstsonntag
46             # pfim = Pfingstmontag
47             # himm = Himmelfahrtstag
48             # fron = Fronleichnam
49             # 1mai = Maifeiertag
50             # 17ju = Tag der deutschen Einheit (>= 1954, <= 1990)
51             # frie = Augsburger Friedensfest
52             # mari = Mariae Himmelfahrt
53             # kind = Weltkindertag
54             # 3okt = Tag der deutschen Einheit (>= 1990)
55             # refo = Reformationstag
56             # alhe = Allerheiligen
57             # buss = Buss- und Bettag
58             # votr = Volkstrauertag
59             # toso = Totensonntag
60             # adv1 = 1. Advent
61             # adv2 = 2. Advent
62             # adv3 = 3. Advent
63             # adv4 = 4. Advent
64             # heil = Heiligabend
65             # wei1 = 1. Weihnachtstag
66             # wei2 = 2. Weihnachtstag
67             # silv = Silvester
68              
69             # Aliases for German federal states
70             # See http://www.bmi.bund.de/cae/servlet/contentblob/150560/publicationFile/13610/feiertage_de.pdf
71             #
72             # bw = Baden-Wuerttemberg
73             # by = Freistaat Bayern
74             # be = Berlin
75             # bb = Brandenburg
76             # hb = Freie Hansestadt Bremen
77             # hh = Freie und Hansestadt Hamburg
78             # he = Hessen
79             # mv = Mecklenburg-Vorpommern
80             # ni = Niedersachsen
81             # nw = Nordrhein-Westfalen
82             # rp = Rheinland-Pfalz
83             # sl = Saarland
84             # sn = Freistaat Sachsen
85             # st = Sachsen-Anhalt
86             # sh = Schleswig-Holstein
87             # th = Freistaat Thueringen
88            
89              
90             # Sort out who has which holidays
91             #
92 0           my %holidays;
93             # Common holidays througout Germany
94             # 17ju/3okt are added to the list later, during date calculation
95 0           @{$holidays{'common'}} = qw(neuj karf ostm 1mai
  0            
96             pfim himm wei1 wei2);
97              
98             # 500th reformation day in 2017 will be a common federal holiday
99             # Deep link to Wikipedia as of today, 2016-01-06:
100             # https://de.wikipedia.org/w/index.php?title=Reformationstag&oldid=148889526#Bundesweiter_Feiertag_2017_.28einmalig.29
101 0 0         if (2017 == $year){
102 0           push @{$holidays{'common'}}, 'refo';
  0            
103             }
104              
105             # Now the extra holidays for the federal states.
106             # As if things weren't bad enough, some holidays are only valid
107             # in certain parts of single states. These will have to be
108             # specified through the ADD parameter.
109              
110             # Extras for Baden-Wuerttemberg
111 0           @{$holidays{'bw'}} = qw(hl3k fron alhe);
  0            
112              
113             # Extras for Bayern
114 0           @{$holidays{'by'}} = qw(hl3k fron alhe);
  0            
115              
116             # Extras for Berlin
117 0           @{$holidays{'be'}} = qw();
  0            
118 0 0         if ($year >= 2019) {
119 0           push @{$holidays{'be'}}, qw(frau);
  0            
120             }
121 0 0         if ($year == 2020) {
122 0           push @{$holidays{'be'}}, qw(befr);
  0            
123             }
124              
125             # Extras for Brandenburg
126 0           @{$holidays{'bb'}} = qw(osts pfis refo);
  0            
127              
128             # Extras for Bremen
129 0           @{$holidays{'hb'}} = qw();
  0            
130 0 0         if ($year >= 2018) {
131 0           push @{$holidays{'hb'}}, qw(refo);
  0            
132             }
133              
134             # Extras for Hamburg
135 0           @{$holidays{'hh'}} = qw();
  0            
136 0 0         if ($year >= 2018) {
137 0           push @{$holidays{'hh'}}, qw(refo);
  0            
138             }
139              
140             # Extras for Hessen
141 0           @{$holidays{'he'}} = qw(fron);
  0            
142              
143             # Extras for Meck-Pomm
144 0           @{$holidays{'mv'}} = qw(refo);
  0            
145              
146             # Extras for Niedersachsen
147 0           @{$holidays{'ni'}} = qw();
  0            
148 0 0         if ($year >= 2018) {
149 0           push @{$holidays{'ni'}}, qw(refo);
  0            
150             }
151              
152             # Extras for Nordrhein-Westfalen
153 0           @{$holidays{'nw'}} = qw(fron alhe);
  0            
154              
155             # Extras for Rheinland-Pfalz
156 0           @{$holidays{'rp'}} = qw(fron alhe);
  0            
157              
158             # Extras for Saarland
159 0           @{$holidays{'sl'}} = qw(fron mari alhe);
  0            
160              
161             # Extras for Sachsen
162 0           @{$holidays{'sn'}} = qw(refo buss);
  0            
163              
164             # Extras for Sachsen-Anhalt
165 0           @{$holidays{'st'}} = qw(hl3k refo);
  0            
166              
167             # Extras for Schleswig-Holstein
168 0           @{$holidays{'sh'}} = qw();
  0            
169 0 0         if ($year >= 2018) {
170 0           push @{$holidays{'sh'}}, qw(refo);
  0            
171             }
172              
173             # Extras for Thueringen
174 0           @{$holidays{'th'}} = qw(refo);
  0            
175 0 0         if ($year >= 2019) {
176 0           push @{$holidays{'th'}}, qw(kind);
  0            
177             }
178              
179             # Fixed-date holidays
180             #
181 0           my %holiday;
182             # New year's day Jan 1
183 0           $holiday{'neuj'} = _date2timestamp($year, 1, 1);
184              
185             # Heilige 3 Koenige Jan 6
186 0           $holiday{'hl3k'} = _date2timestamp($year, 1, 6);
187              
188             # International Womens Day
189 0           $holiday{'frau'} = _date2timestamp($year, 3, 8);
190              
191             # First of May
192 0           $holiday{'1mai'} = _date2timestamp($year, 5, 1);
193              
194             # Liberation Day
195 0           $holiday{'befr'} = _date2timestamp($year, 5, 8);
196              
197             # Christmas eve and Christmas Dec 24-26
198 0           $holiday{'heil'} = _date2timestamp($year, 12, 24);
199 0           $holiday{'wei1'} = _date2timestamp($year, 12, 25);
200 0           $holiday{'wei2'} = _date2timestamp($year, 12, 26);
201              
202             # Augsburger Friedensfest
203 0           $holiday{'frie'} = _date2timestamp($year, 8, 8);
204              
205             # Assumption day Aug 15
206 0           $holiday{'mari'} = _date2timestamp($year, 8, 15);
207              
208             # International Childrens Day
209 0           $holiday{'kind'} = _date2timestamp($year, 9, 20);
210              
211             # Reunion day Jun 17 (1954-1990)
212 0 0 0       if (($year <= 1990) and ($year >= 1954)){
213 0           $holiday{'17ju'} = _date2timestamp($year, 6, 17);
214 0           push @{$holidays{'common'}}, '17ju';
  0            
215             }
216              
217             # Reunion day Oct 3 (since 1990)
218 0 0         if ($year >= 1990){
219 0           $holiday{'3okt'} = _date2timestamp($year, 10, 3);
220 0           push @{$holidays{'common'}}, '3okt';
  0            
221             }
222            
223             # Reformation day Oct 31
224 0           $holiday{'refo'} = _date2timestamp($year, 10, 31);
225              
226             # All Hallows Nov 1
227 0           $holiday{'alhe'} = _date2timestamp($year, 11, 1);
228              
229             # New Years Eve Dec 31
230 0           $holiday{'silv'} = _date2timestamp($year, 12, 31);
231              
232             # Holidays relative to Easter
233             #
234             # Fat Thursday = Easter Sunday minus 52 days
235 0           my ($j_weib, $m_weib, $t_weib) =
236             Date::Calc::Add_Delta_Days($year, $month, $day, -52);
237 0           $holiday{'weib'} = _date2timestamp($j_weib, $m_weib, $t_weib);
238              
239             # Carnival Monday = Easter Sunday minus 48 days
240 0           my ($j_romo, $m_romo, $t_romo) =
241             Date::Calc::Add_Delta_Days($year, $month, $day, -48);
242 0           $holiday{'romo'} = _date2timestamp($j_romo, $m_romo, $t_romo);
243              
244             # Shrove Tuesday = Easter Sunday minus 47 days
245 0           my ($j_fadi, $m_fadi, $t_fadi) =
246             Date::Calc::Add_Delta_Days($year, $month, $day, -47);
247 0           $holiday{'fadi'} = _date2timestamp($j_fadi, $m_fadi, $t_fadi);
248              
249             # Ash Wednesday = Easter Sunday minus 46 days
250 0           my ($j_asmi, $m_asmi, $t_asmi) =
251             Date::Calc::Add_Delta_Days($year, $month, $day, -46);
252 0           $holiday{'asmi'} = _date2timestamp($j_asmi, $m_asmi, $t_asmi);
253              
254             # Maundy Thursday = Easter Sunday minus 3 days
255 0           my ($j_grdo, $m_grdo, $t_grdo) =
256             Date::Calc::Add_Delta_Days($year, $month, $day, -3);
257 0           $holiday{'grdo'} = _date2timestamp($j_grdo, $m_grdo, $t_grdo);
258              
259             # Good Friday = Easter Sunday minus 2 days
260 0           my ($j_karf, $m_karf, $t_karf) =
261             Date::Calc::Add_Delta_Days($year, $month, $day, -2);
262 0           $holiday{'karf'} = _date2timestamp($j_karf, $m_karf, $t_karf);
263              
264             # Holy Saturday = Easter Sunday minus 1 day
265 0           my ($j_kars, $m_kars, $t_kars) =
266             Date::Calc::Add_Delta_Days($year, $month, $day, -1);
267 0           $holiday{'kars'} = _date2timestamp($j_kars, $m_kars, $t_kars);
268              
269             # Easter Sunday is just that
270 0           $holiday{'osts'} = _date2timestamp($year, $month, $day);
271              
272             # Easter Monday = Easter Sunday plus 1 day
273 0           my ($j_ostm, $m_ostm, $t_ostm) =
274             Date::Calc::Add_Delta_Days($year, $month, $day, 1);
275 0           $holiday{'ostm'} = _date2timestamp($j_ostm, $m_ostm, $t_ostm);
276              
277             # Whit Sunday = Easter Sunday plus 49 days
278 0           my ($j_pfis, $m_pfis, $t_pfis) =
279             Date::Calc::Add_Delta_Days($year, $month, $day, 49);
280 0           $holiday{'pfis'} = _date2timestamp($j_pfis, $m_pfis, $t_pfis);
281              
282             # Whit Monday = Easter Sunday plus 50 days
283 0           my ($j_pfim, $m_pfim, $t_pfim) =
284             Date::Calc::Add_Delta_Days($year, $month, $day, 50);
285 0           $holiday{'pfim'} = _date2timestamp($j_pfim, $m_pfim, $t_pfim);
286              
287             # Ascension Day = Easter Sunday plus 39 days
288 0           my ($j_himm, $m_himm, $t_himm) =
289             Date::Calc::Add_Delta_Days($year, $month, $day, 39);
290 0           $holiday{'himm'} = _date2timestamp($j_himm, $m_himm, $t_himm);
291              
292             # Corpus Christi = Easter Sunday plus 60 days
293 0           my ($j_fron, $m_fron, $t_fron) =
294             Date::Calc::Add_Delta_Days($year, $month, $day, 60);
295 0           $holiday{'fron'} = _date2timestamp($j_fron, $m_fron, $t_fron);
296              
297             # Only one holiday is relative to Christmas
298             #
299             # Penance day = Sunday before christmas minus 32 days
300             # Find sunday before christmas
301 0           my $tempdate;
302 0           for ($tempdate = 24; $tempdate > 16; $tempdate--){
303 0           my $dow = Day_of_Week($year, 12, $tempdate);
304             # 7 is Sunday
305 0 0         last if (7 == $dow);
306             # $tempdate now holds the last sunday before christmas.
307             }
308             # subtract 32 days from the Dec day stored in $tempdate
309 0           my ($j_buss, $m_buss, $t_buss) =
310             Date::Calc::Add_Delta_Days($year, 12, $tempdate, -32);
311 0           $holiday{'buss'} = _date2timestamp($j_buss, $m_buss, $t_buss);
312              
313             # store the sundays in advent and the two sundays before
314 0           my $sc=0;
315 0           foreach my $name ("adv4", "adv3", "adv2", "adv1", "toso", "votr") {
316 0           $holiday{$name} = _date2timestamp(
317             Date::Calc::Add_Delta_Days($year, 12, $tempdate, 7*$sc--)
318             );
319             }
320              
321             # Build list for returning
322             #
323 0           my %holidaylist;
324             # See what holidays shall be printed
325 0           my $wantall = 0;
326 0           foreach (@{$parameters{'WHERE'}}){
  0            
327 0 0         if ($_ eq 'all'){
328 0           $wantall = 1;
329             }
330             }
331 0 0         if (1 == $wantall){
332             # All holidays if 'all' is in the WHERE parameter list.
333 0           %holidaylist = %holiday;
334             }else{
335             # Only specified regions
336 0           foreach my $scope (@{$parameters{'WHERE'}}){
  0            
337 0           foreach my $alias(@{$holidays{$scope}}){
  0            
338 0           $holidaylist{$alias} = $holiday{$alias};
339             }
340             }
341             }
342             # Add the most obscure holidays that were requested through
343             # the ADD parameter
344 0 0         if ($parameters{'ADD'}){
345 0           foreach my $add(@{$parameters{'ADD'}}){
  0            
346 0           $holidaylist{$add} = $holiday{$add};
347             }
348             }
349              
350             # If WEEKENDS => 0 was passed, weed out holidays on weekends
351             #
352 0 0         unless (1 == $parameters{'WEEKENDS'}){
353             # Walk the list of holidays
354 0           foreach my $alias(keys(%holidaylist)){
355             # Get day of week. Since we're no longer
356             # in Date::Calc's world, use localtime()
357 0           my $dow = (localtime($holiday{$alias}))[6];
358             # dow 6 = Saturday, dow 0 = Sunday
359 0 0 0       if ((6 == $dow) or (0 == $dow)){
360             # Kick this day from the list
361 0           delete $holidaylist{$alias};
362             }
363             }
364             }
365              
366             # Sort values stored in the hash for returning
367             #
368 0           my @returnlist;
369 0           foreach(sort{$holidaylist{$a}<=>$holidaylist{$b}}(keys(%holidaylist))){
  0            
370             # Not all platforms have strftime(%s).
371             # Therefore, inject seconds manually into format string.
372 0           my $formatstring = $parameters{'FORMAT'};
373 0           $formatstring =~ s/%{0}%s/$holidaylist{$_}/g;
374             # Inject the holiday's alias name into the format string
375             # if it was requested by adding %#.
376 0           $formatstring =~ s/%{0}%#/$_/;
377             push @returnlist,
378 0           strftime($formatstring, localtime($holidaylist{$_}));
379             }
380 0           return \@returnlist;
381             }
382              
383             sub _date2timestamp{
384             # Turn Date::Calc's y/m/d format into a UNIX timestamp
385 0     0     my ($y, $m, $d) = @_;
386 0           my $timestamp = timelocal(0,0,0,$d,($m-1),$y);
387 0           return $timestamp;
388             }
389              
390             1;
391             __END__