File Coverage

blib/lib/Date/Holidays/DE.pm
Criterion Covered Total %
statement 15 162 9.2
branch 0 30 0.0
condition 0 6 0.0
subroutine 5 7 71.4
pod 0 1 0.0
total 20 206 9.7


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