File Coverage

blib/lib/Date/Holidays/DE.pm
Criterion Covered Total %
statement 15 169 8.8
branch 0 34 0.0
condition 0 6 0.0
subroutine 5 7 71.4
pod 0 1 0.0
total 20 217 9.2


line stmt bran cond sub pod time code
1             package Date::Holidays::DE;
2              
3 1     1   5401 use strict;
  1         3  
  1         30  
4 1     1   5 use warnings;
  1         2  
  1         36  
5              
6             # Stock modules
7 1     1   476 use Time::Local;
  1         2212  
  1         58  
8 1     1   484 use POSIX qw(strftime);
  1         7981  
  1         5  
9              
10             # Prerequisite
11 1     1   1961 use Date::Calc qw(Add_Delta_Days Easter_Sunday Day_of_Week This_Year);
  1         8367  
  1         1649  
12              
13             require Exporter;
14              
15             our @ISA = qw(Exporter);
16             our @EXPORT_OK = qw(holidays);
17             our $VERSION = '2.06';
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 0 0         if ($year >= 2023) {
146 0           push @{$holidays{'mv'}}, qw(frau);
  0            
147             }
148              
149             # Extras for Niedersachsen
150 0           @{$holidays{'ni'}} = qw();
  0            
151 0 0         if ($year >= 2018) {
152 0           push @{$holidays{'ni'}}, qw(refo);
  0            
153             }
154              
155             # Extras for Nordrhein-Westfalen
156 0           @{$holidays{'nw'}} = qw(fron alhe);
  0            
157              
158             # Extras for Rheinland-Pfalz
159 0           @{$holidays{'rp'}} = qw(fron alhe);
  0            
160              
161             # Extras for Saarland
162 0           @{$holidays{'sl'}} = qw(fron mari alhe);
  0            
163              
164             # Extras for Sachsen
165 0           @{$holidays{'sn'}} = qw(refo buss);
  0            
166              
167             # Extras for Sachsen-Anhalt
168 0           @{$holidays{'st'}} = qw(hl3k refo);
  0            
169              
170             # Extras for Schleswig-Holstein
171 0           @{$holidays{'sh'}} = qw();
  0            
172 0 0         if ($year >= 2018) {
173 0           push @{$holidays{'sh'}}, qw(refo);
  0            
174             }
175              
176             # Extras for Thueringen
177 0           @{$holidays{'th'}} = qw(refo);
  0            
178 0 0         if ($year >= 2019) {
179 0           push @{$holidays{'th'}}, qw(kind);
  0            
180             }
181              
182             # Fixed-date holidays
183             #
184 0           my %holiday;
185             # New year's day Jan 1
186 0           $holiday{'neuj'} = _date2timestamp($year, 1, 1);
187              
188             # Heilige 3 Koenige Jan 6
189 0           $holiday{'hl3k'} = _date2timestamp($year, 1, 6);
190              
191             # International Womens Day
192 0           $holiday{'frau'} = _date2timestamp($year, 3, 8);
193              
194             # First of May
195 0           $holiday{'1mai'} = _date2timestamp($year, 5, 1);
196              
197             # Liberation Day
198 0           $holiday{'befr'} = _date2timestamp($year, 5, 8);
199              
200             # Christmas eve and Christmas Dec 24-26
201 0           $holiday{'heil'} = _date2timestamp($year, 12, 24);
202 0           $holiday{'wei1'} = _date2timestamp($year, 12, 25);
203 0           $holiday{'wei2'} = _date2timestamp($year, 12, 26);
204              
205             # Augsburger Friedensfest
206 0           $holiday{'frie'} = _date2timestamp($year, 8, 8);
207              
208             # Assumption day Aug 15
209 0           $holiday{'mari'} = _date2timestamp($year, 8, 15);
210              
211             # International Childrens Day
212 0           $holiday{'kind'} = _date2timestamp($year, 9, 20);
213              
214             # Reunion day Jun 17 (1954-1990)
215 0 0 0       if (($year <= 1990) and ($year >= 1954)){
216 0           $holiday{'17ju'} = _date2timestamp($year, 6, 17);
217 0           push @{$holidays{'common'}}, '17ju';
  0            
218             }
219              
220             # Reunion day Oct 3 (since 1990)
221 0 0         if ($year >= 1990){
222 0           $holiday{'3okt'} = _date2timestamp($year, 10, 3);
223 0           push @{$holidays{'common'}}, '3okt';
  0            
224             }
225            
226             # Reformation day Oct 31
227 0           $holiday{'refo'} = _date2timestamp($year, 10, 31);
228              
229             # All Hallows Nov 1
230 0           $holiday{'alhe'} = _date2timestamp($year, 11, 1);
231              
232             # New Years Eve Dec 31
233 0           $holiday{'silv'} = _date2timestamp($year, 12, 31);
234              
235             # Holidays relative to Easter
236             #
237             # Fat Thursday = Easter Sunday minus 52 days
238 0           my ($j_weib, $m_weib, $t_weib) =
239             Date::Calc::Add_Delta_Days($year, $month, $day, -52);
240 0           $holiday{'weib'} = _date2timestamp($j_weib, $m_weib, $t_weib);
241              
242             # Carnival Monday = Easter Sunday minus 48 days
243 0           my ($j_romo, $m_romo, $t_romo) =
244             Date::Calc::Add_Delta_Days($year, $month, $day, -48);
245 0           $holiday{'romo'} = _date2timestamp($j_romo, $m_romo, $t_romo);
246              
247             # Shrove Tuesday = Easter Sunday minus 47 days
248 0           my ($j_fadi, $m_fadi, $t_fadi) =
249             Date::Calc::Add_Delta_Days($year, $month, $day, -47);
250 0           $holiday{'fadi'} = _date2timestamp($j_fadi, $m_fadi, $t_fadi);
251              
252             # Ash Wednesday = Easter Sunday minus 46 days
253 0           my ($j_asmi, $m_asmi, $t_asmi) =
254             Date::Calc::Add_Delta_Days($year, $month, $day, -46);
255 0           $holiday{'asmi'} = _date2timestamp($j_asmi, $m_asmi, $t_asmi);
256              
257             # Maundy Thursday = Easter Sunday minus 3 days
258 0           my ($j_grdo, $m_grdo, $t_grdo) =
259             Date::Calc::Add_Delta_Days($year, $month, $day, -3);
260 0           $holiday{'grdo'} = _date2timestamp($j_grdo, $m_grdo, $t_grdo);
261              
262             # Good Friday = Easter Sunday minus 2 days
263 0           my ($j_karf, $m_karf, $t_karf) =
264             Date::Calc::Add_Delta_Days($year, $month, $day, -2);
265 0           $holiday{'karf'} = _date2timestamp($j_karf, $m_karf, $t_karf);
266              
267             # Holy Saturday = Easter Sunday minus 1 day
268 0           my ($j_kars, $m_kars, $t_kars) =
269             Date::Calc::Add_Delta_Days($year, $month, $day, -1);
270 0           $holiday{'kars'} = _date2timestamp($j_kars, $m_kars, $t_kars);
271              
272             # Easter Sunday is just that
273 0           $holiday{'osts'} = _date2timestamp($year, $month, $day);
274              
275             # Easter Monday = Easter Sunday plus 1 day
276 0           my ($j_ostm, $m_ostm, $t_ostm) =
277             Date::Calc::Add_Delta_Days($year, $month, $day, 1);
278 0           $holiday{'ostm'} = _date2timestamp($j_ostm, $m_ostm, $t_ostm);
279              
280             # Whit Sunday = Easter Sunday plus 49 days
281 0           my ($j_pfis, $m_pfis, $t_pfis) =
282             Date::Calc::Add_Delta_Days($year, $month, $day, 49);
283 0           $holiday{'pfis'} = _date2timestamp($j_pfis, $m_pfis, $t_pfis);
284              
285             # Whit Monday = Easter Sunday plus 50 days
286 0           my ($j_pfim, $m_pfim, $t_pfim) =
287             Date::Calc::Add_Delta_Days($year, $month, $day, 50);
288 0           $holiday{'pfim'} = _date2timestamp($j_pfim, $m_pfim, $t_pfim);
289              
290             # Ascension Day = Easter Sunday plus 39 days
291 0           my ($j_himm, $m_himm, $t_himm) =
292             Date::Calc::Add_Delta_Days($year, $month, $day, 39);
293 0           $holiday{'himm'} = _date2timestamp($j_himm, $m_himm, $t_himm);
294              
295             # Corpus Christi = Easter Sunday plus 60 days
296 0           my ($j_fron, $m_fron, $t_fron) =
297             Date::Calc::Add_Delta_Days($year, $month, $day, 60);
298 0           $holiday{'fron'} = _date2timestamp($j_fron, $m_fron, $t_fron);
299              
300             # Only one holiday is relative to Christmas
301             #
302             # Penance day = Sunday before christmas minus 32 days
303             # Find sunday before christmas
304 0           my $tempdate;
305 0           for ($tempdate = 24; $tempdate > 16; $tempdate--){
306 0           my $dow = Day_of_Week($year, 12, $tempdate);
307             # 7 is Sunday
308 0 0         last if (7 == $dow);
309             # $tempdate now holds the last sunday before christmas.
310             }
311             # subtract 32 days from the Dec day stored in $tempdate
312 0           my ($j_buss, $m_buss, $t_buss) =
313             Date::Calc::Add_Delta_Days($year, 12, $tempdate, -32);
314 0           $holiday{'buss'} = _date2timestamp($j_buss, $m_buss, $t_buss);
315              
316             # store the sundays in advent and the two sundays before
317 0           my $sc=0;
318 0           foreach my $name ("adv4", "adv3", "adv2", "adv1", "toso", "votr") {
319 0           $holiday{$name} = _date2timestamp(
320             Date::Calc::Add_Delta_Days($year, 12, $tempdate, 7*$sc--)
321             );
322             }
323              
324             # Build list for returning
325             #
326 0           my %holidaylist;
327             # See what holidays shall be printed
328 0           my $wantall = 0;
329 0           foreach (@{$parameters{'WHERE'}}){
  0            
330 0 0         if ($_ eq 'all'){
331 0           $wantall = 1;
332             }
333             }
334 0 0         if (1 == $wantall){
335             # All holidays if 'all' is in the WHERE parameter list.
336 0           %holidaylist = %holiday;
337             }else{
338             # Only specified regions
339 0           foreach my $scope (@{$parameters{'WHERE'}}){
  0            
340 0           foreach my $alias(@{$holidays{$scope}}){
  0            
341 0           $holidaylist{$alias} = $holiday{$alias};
342             }
343             }
344             }
345             # Add the most obscure holidays that were requested through
346             # the ADD parameter
347 0 0         if ($parameters{'ADD'}){
348 0           foreach my $add(@{$parameters{'ADD'}}){
  0            
349 0           $holidaylist{$add} = $holiday{$add};
350             }
351             }
352              
353             # If WEEKENDS => 0 was passed, weed out holidays on weekends
354             #
355 0 0         unless (1 == $parameters{'WEEKENDS'}){
356             # Walk the list of holidays
357 0           foreach my $alias(keys(%holidaylist)){
358             # Get day of week. Since we're no longer
359             # in Date::Calc's world, use localtime()
360 0           my $dow = (localtime($holiday{$alias}))[6];
361             # dow 6 = Saturday, dow 0 = Sunday
362 0 0 0       if ((6 == $dow) or (0 == $dow)){
363             # Kick this day from the list
364 0           delete $holidaylist{$alias};
365             }
366             }
367             }
368              
369             # Sort values stored in the hash for returning
370             #
371 0           my @returnlist;
372 0           foreach(sort{$holidaylist{$a}<=>$holidaylist{$b}}(keys(%holidaylist))){
  0            
373             # Not all platforms have strftime(%s).
374             # Therefore, inject seconds manually into format string.
375 0           my $formatstring = $parameters{'FORMAT'};
376 0           $formatstring =~ s/%{0}%s/$holidaylist{$_}/g;
377             # Inject the holiday's alias name into the format string
378             # if it was requested by adding %#.
379 0           $formatstring =~ s/%{0}%#/$_/;
380             push @returnlist,
381 0           strftime($formatstring, localtime($holidaylist{$_}));
382             }
383 0           return \@returnlist;
384             }
385              
386             sub _date2timestamp{
387             # Turn Date::Calc's y/m/d format into a UNIX timestamp
388 0     0     my ($y, $m, $d) = @_;
389 0           my $timestamp = timelocal(0,0,0,$d,($m-1),$y);
390 0           return $timestamp;
391             }
392              
393             1;
394             __END__