File Coverage

blib/lib/Date/Holidays/NL.pm
Criterion Covered Total %
statement 73 74 98.6
branch 29 30 96.6
condition 12 17 70.5
subroutine 11 11 100.0
pod 3 3 100.0
total 128 135 94.8


line stmt bran cond sub pod time code
1             package Date::Holidays::NL;
2             our $VERSION = '0.008';
3 2     2   322126 use strict;
  2         4  
  2         73  
4 2     2   9 use warnings;
  2         3  
  2         156  
5              
6             # ABSTRACT: The Netherlands official holidays
7              
8 2     2   10 use Exporter qw(import);
  2         5  
  2         98  
9              
10             our @EXPORT = qw(
11             holidays
12             is_holiday
13             is_holiday_dt
14             );
15              
16 2     2   8 use base qw(Date::Holidays::Abstract);
  2         4  
  2         2456  
17 2     2   18779 use DateTime::Event::Easter;
  2         1451056  
  2         186  
18 2     2   38 use DateTime;
  2         4  
  2         2070  
19              
20             my %FIXED_DATES = (
21             'newyears' => {
22             m => 1,
23             d => 1,
24             nl => 'Nieuwjaarsdag',
25             en => 'New years day',
26             },
27             'wimlex' => {
28             m => 4,
29             d => 27,
30             nl => 'Koningsdag',
31             en => 'Kings day',
32             # change day of week if it falls on a sunday
33             dow => { 7 => -1 },
34             year_started => 2014,
35             },
36             'minna-princess' => {
37             m => 8,
38             d => 31,
39             nl => 'Prinsessedag',
40             en => "Princess's day",
41              
42             # change day of week if it falls on a sunday
43             dow => { 7 => 1 },
44             year_started => 1885,
45             year_ended => 1890,
46             },
47             'minna-queen' => {
48             m => 8,
49             d => 31,
50             nl => 'Koninginnedag',
51             en => "Queen's day",
52              
53             # change day of week if it falls on a sunday
54             dow => { 7 => 1 },
55             year_started => 1891,
56             year_ended => 1948,
57             },
58             'juliana-beatrix' => {
59             m => 4,
60             d => 30,
61             nl => 'Koninginnedag',
62             en => "Queen's day",
63              
64             # change day of week if it falls on a sunday
65             dow => { 7 => 1 },
66             year_started => 1949,
67             year_ended => 1979,
68             },
69             'juliana-beatrix-2' => {
70             m => 4,
71             d => 30,
72             nl => 'Koninginnedag',
73             en => "Queen's day",
74              
75             # change day of week if it falls on a sunday
76             dow => { 7 => -1 },
77             year_started => 1980,
78             year_ended => 2013,
79             },
80             'liberation' => {
81             m => 5,
82             d => 5,
83             nl => 'Bevrijdingsdag',
84             en => 'Liberation day',
85             interval => 5, # Day off every five years
86             gov => 1, # Government works are having a day off tho
87             },
88             'xmas' => {
89             m => 12,
90             d => 25,
91             nl => 'Kerst',
92             en => 'Christmas',
93             },
94             'boxing' => {
95             m => 12,
96             d => 26,
97             nl => 'Tweede kerstdag',
98             en => 'Boxing day',
99             },
100             );
101              
102             my %EASTER_BASED = (
103             'goodfri' => {
104             d => -2,
105             nl => 'Goede vrijdag',
106             en => 'Good friday',
107             gov => 1,
108             },
109             'easter' => {
110             d => 0,
111             nl => 'Pasen',
112             en => 'Easter',
113             },
114             'easter2' => {
115             d => 1,
116             nl => 'Tweede paasdag',
117             en => 'Second day of easter',
118             },
119             'ascension' => {
120             d => 39,
121             nl => 'Hemelvaartsdag',
122             en => 'Ascension day',
123             },
124             pentecost => {
125             d => 49,
126             nl => 'Pinksteren',
127             en => 'Pentecost',
128             },
129             pentecost2 => {
130             d => 50,
131             nl => 'Tweede pinksterdag',
132             en => 'Pentecost',
133             }
134             );
135              
136             my %cache;
137              
138             sub holidays {
139 15     15 1 253214 my $year = shift;
140 15         31 my %args = @_;
141              
142 15   33     40 $year //= DateTime->now()->year;
143              
144 15         24 my $key = $year;
145 15 100       53 if ($args{gov}) {
146 2         3 $key .= 'gov';
147             }
148              
149 15 100       48 return $cache{$key} if $cache{$key};
150              
151 10         13 my %h;
152 10         47 foreach (keys %FIXED_DATES) {
153 90         680 my $holiday = $FIXED_DATES{$_};
154              
155 90 100 66     320 if (my $int = $holiday->{interval}) {
    50          
156 10 100 66     32 unless ($args{gov} && $holiday->{gov}) {
157 8 100       26 next if $year % $int != 0;
158             }
159             }
160             # Skip government holidays, currently good friday only
161             # https://wetten.overheid.nl/BWBR0002448/2010-10-10
162             elsif (!$args{gov} && $holiday->{gov}) {
163 0         0 next;
164             }
165              
166 83 100       165 if (my $start = $holiday->{year_started}) {
167 50 100       101 next if $year < $start;
168             }
169              
170 77 100       123 if (my $end = $holiday->{year_ended}) {
171 38 100       85 next if $year > $end;
172             }
173              
174 43         84 my $dt = _to_date($holiday->{d}, $holiday->{m}, $year);
175              
176 43 100       13166 if (my $dow = $holiday->{dow}) {
177 10         31 my $cur = $dt->dow();
178 10         48 foreach (keys %$dow) {
179 10 100       34 next unless $cur == $_;
180 3         11 $dt->add(days => $dow->{$_});
181 3         1935 last;
182             }
183             }
184              
185 43         123 _to_holidays(\%h, $dt, $holiday);
186             }
187              
188 10         39 my $dt = _to_date(1, 1, $year);
189 10         2973 foreach (keys %EASTER_BASED) {
190 60         797 my $holiday = $EASTER_BASED{$_};
191 60 100 100     250 if (!$args{gov} && $holiday->{gov}) {
192 8         16 next;
193             }
194             my $easter = DateTime::Event::Easter->new(
195             easter => 'western',
196             day => $holiday->{d}
197 52         187 );
198 52         9539 my $dt = $easter->following($dt);
199 52         108959 _to_holidays(\%h, $dt, $holiday);
200             }
201              
202 10         223 $cache{$key} = \%h;
203              
204 10         52 return \%h;
205             }
206              
207             sub _to_holidays {
208 95     95   196 my ($cache, $dt, $info) = @_;
209             $cache->{ sprintf("%02i", $dt->day) . sprintf("%02i", $dt->month) }
210 95         154 = [map { $info->{$_} } qw(nl en)];
  190         653  
211             }
212              
213             sub _to_date {
214 64     64   106 my ($day, $month, $year) = @_;
215 64         187 return DateTime->new(
216             day => $day,
217             month => $month,
218             year => $year,
219             hour => 0,
220             minute => 0,
221             second => 0,
222             time_zone => 'UTC',
223             );
224             }
225              
226             sub is_holiday {
227 11     11 1 623 my $year = shift;
228 11         19 my $month = shift;
229 11         16 my $day = shift;
230              
231 11         22 my $dt = _to_date($day, $month, $year);
232 11         4280 return is_holiday_dt($dt, @_);
233             }
234              
235             sub is_holiday_dt {
236 12     12 1 390 my $dt = shift;
237              
238 12         32 my %args = @_;
239              
240 12         36 my $holidays = holidays($dt->year, @_);
241 12         32 my $key = sprintf("%02i", $dt->day) . sprintf("%02i", $dt->month);
242              
243 12 100       139 if (exists $holidays->{$key}) {
244 10   100     78 my $lang = lc(delete $args{lang} // 'nl');
245 10 100 66     49 if ($lang eq 'en' || $lang eq 'eng') {
246 1         15 return $holidays->{$key}[1];
247             }
248             # default to dutch
249 9         86 return $holidays->{$key}[0];
250             }
251 2         22 return;
252             }
253              
254             'I always get my sin';
255              
256             __END__
257              
258             =pod
259              
260             =encoding UTF-8
261              
262             =head1 NAME
263              
264             Date::Holidays::NL - The Netherlands official holidays
265              
266             =head1 VERSION
267              
268             version 0.008
269              
270             =head1 SYNOPSIS
271              
272             use Date::Holidays::NL;
273              
274             if (my $thing = is_holiday(2020, 5, 5, lang => 'en')) {
275             print "It is $thing!", $/; # prints 'It is Liberation day!'
276             }
277              
278             =head1 DESCRIPTION
279              
280             A L<Date::Holidays> family member from the Netherlands
281              
282             =head1 METHODS
283              
284             This module implements the C<is_holiday>, C<is_holiday_dt> and C<holiday>
285             functions from L<Date::Holidays::Abstract>.
286              
287             All methods accept additional parameters. The most important is a flag called
288             C<gov>, when supplied you will get days that the government considers special
289             in regards to service terms. It essentially says that if a company or
290             government needs to contact you before or on that day it can be expedited to
291             the following work day. See the L<relevant
292             law|https://wetten.overheid.nl/BWBR0002448/2010-10-10> for more information.
293              
294             =head2 is_holiday(yyyy, mm, dd, %additional)
295              
296             is_holiday(
297             '2022', '05', '05',
298             gov => 1, # Important for government institutions
299             lang => 'en' # defaults to nl/nld, alternatively en/eng can be used.
300             );
301              
302             =head2 is_holiday_dt(dt, %additional)
303              
304             is_holiday_dt(
305             DateTime->new(
306             year => 2022,
307             month => 5,
308             day => 5,
309             time_zone => 'Europe/Amsterdam',
310             ),
311             gov => 1, # Important for government institutions
312             lang => 'en' # defaults to nl/nld, alternatively en/eng can be used.
313             );
314              
315             =head2 holidays(yyyy, gov => 1)
316              
317             holidays('2022', gov => 1);
318              
319             Similar API to the other functions, returns an hashref for the year.
320              
321             =head1 SEE ALSO
322              
323             =over
324              
325             =item L<https://wetten.overheid.nl/BWBR0002448/2010-10-10>
326              
327             =back
328              
329             =head1 AUTHOR
330              
331             Wesley Schwengle <waterkip@cpan.org>
332              
333             =head1 COPYRIGHT AND LICENSE
334              
335             This software is Copyright (c) 2020 by Wesley Schwengle.
336              
337             This is free software, licensed under:
338              
339             The (three-clause) BSD License
340              
341             =cut