File Coverage

blib/lib/Date/Holidays/BQ.pm
Criterion Covered Total %
statement 73 74 98.6
branch 27 30 90.0
condition 13 20 65.0
subroutine 11 11 100.0
pod 3 3 100.0
total 127 138 92.0


line stmt bran cond sub pod time code
1             package Date::Holidays::BQ;
2             our $VERSION = '0.003';
3 2     2   320066 use strict;
  2         4  
  2         77  
4 2     2   9 use warnings;
  2         4  
  2         136  
5              
6             # ABSTRACT: Bonaire's official holidays
7              
8 2     2   11 use Exporter qw(import);
  2         3  
  2         125  
9              
10             our @EXPORT = qw(
11             holidays
12             is_holiday
13             is_holiday_dt
14             );
15              
16 2     2   13 use base qw(Date::Holidays::Abstract);
  2         4  
  2         1320  
17 2     2   19442 use DateTime::Event::Easter;
  2         1460900  
  2         174  
18 2     2   43 use DateTime;
  2         12  
  2         2358  
19              
20             my %FIXED_DATES = (
21             newyears => {
22             m => 1,
23             d => 1,
24             pap => "A\x{00f1}a Nobo",
25             nl => 'Nieuwjaarsdag',
26             en => 'New years day',
27             },
28             rincon => {
29             m => 4,
30             d => 30,
31             pap => 'Dia di Rincon',
32             nl => 'Dag van Rincon',
33             en => 'Rincon day',
34             },
35             kingdom => {
36             m => 12,
37             d => 15,
38             pap => 'Dia di Reino',
39             nl => 'Dag van het koninkrijk',
40             en => 'Kingdom day',
41             },
42             flagday => {
43             m => 9,
44             d => 6,
45             pap => 'Dia di Boneiru',
46             nl => 'Bonairedag',
47             en => 'Bonaire Flag day',
48             },
49             wimlex => {
50             m => 4,
51             d => 27,
52             nl => 'Koningsdag',
53             en => 'Kings day',
54             pap => 'Dia di Rei',
55              
56             # change day of week if it falls on a sunday
57             dow => { 7 => -1 },
58             year_started => 2014,
59             },
60             'minna-princess' => {
61             m => 8,
62             d => 31,
63             nl => 'Prinsessedag',
64             en => "Princess's day",
65             pap => 'Dia di Prensesa',
66              
67             # change day of week if it falls on a sunday
68             dow => { 7 => 1 },
69             year_started => 1885,
70             year_ended => 1890,
71             },
72             'minna-queen' => {
73             m => 8,
74             d => 31,
75             nl => 'Koninginnedag',
76             en => "Queen's day",
77             pap => 'Dia di Reina',
78              
79             # change day of week if it falls on a sunday
80             dow => { 7 => 1 },
81             year_started => 1891,
82             year_ended => 1948,
83             },
84             'juliana-beatrix' => {
85             m => 4,
86             d => 30,
87             nl => 'Koninginnedag',
88             en => "Queen's day",
89             pap => 'Dia di Reina',
90              
91             # change day of week if it falls on a sunday
92             dow => { 7 => 1 },
93             year_started => 1949,
94             year_ended => 1979,
95             },
96             'juliana-beatrix-2' => {
97             m => 4,
98             d => 30,
99             nl => 'Koninginnedag',
100             en => "Queen's day",
101             pap => 'Dia di Reina',
102              
103             # change day of week if it falls on a sunday
104             dow => { 7 => -1 },
105             year_started => 1980,
106             year_ended => 2013,
107             },
108             # https://wetten.overheid.nl/BWBR0002448/2010-10-10
109             # This is a gov-only day
110             liberation => {
111             m => 5,
112             d => 5,
113             pap => 'Dia di liberation',
114             nl => 'Bevrijdingsdag',
115             en => 'Liberation day',
116             gov => 1,
117             },
118             labor => {
119             m => 5,
120             d => 1,
121             pap => 'Dia di Labor/Dia di Obrero',
122             nl => 'Dag van de arbeid',
123             en => 'Labor day',
124             },
125             xmas => {
126             m => 12,
127             d => 25,
128             pap => 'Pasku di Nacemento',
129             nl => 'Kerst',
130             en => 'Christmas',
131             },
132             boxing => {
133             m => 12,
134             d => 26,
135             pap => 'Di dos dia di Pasku di Nacemento',
136             nl => 'Tweede kerstdag',
137             en => 'Boxing day',
138             },
139             );
140              
141             my %EASTER_BASED = (
142             'carnaval' => {
143             d => -31 - 16 - 2, # 49
144             pap => 'Prome dia di Carnaval',
145             nl => 'Eerste carnavalsdag',
146             en => 'First day of carnaval',
147             },
148             goodfri => {
149             d => -2,
150             pap => 'Bierna Santo',
151             nl => 'Goede vrijdag',
152             en => 'Good friday',
153             },
154             easter => {
155             d => 0,
156             pap => 'Pasku Grandi',
157             nl => 'Pasen',
158             en => 'Easter',
159             },
160             easter2 => {
161             d => 1,
162             pap => 'Pasku Grandi',
163             nl => 'Tweede paasdag',
164             en => 'Second day of easter',
165             },
166             ascension => {
167             d => 39,
168             pap => 'Dia di Asuncion',
169             nl => 'Hemelvaartsdag',
170             en => 'Ascension day',
171             },
172             pentecost => {
173             d => 49,
174             pap => "Pentek\x{00f2}ste",
175             nl => 'Pinksteren',
176             en => 'Pentecost',
177             },
178             pentecost2 => {
179             d => 50,
180             pap => "Dia dos di Pentek\x{00f2}ste",
181             nl => 'Tweede pinksterdag',
182             en => 'Pentecost',
183             gov => 1,
184             },
185             );
186              
187             my %cache;
188              
189             sub holidays {
190 22     22 1 329676 my $year = shift;
191 22         64 my %args = @_;
192              
193 22   66     91 $year //= DateTime->now()->year;
194              
195 22         468 my $key = $year;
196 22 100       90 if ($args{gov}) {
197 3         9 $key .= 'gov';
198             }
199              
200 22 100       100 return $cache{$key} if $cache{$key};
201              
202 11         27 my %h;
203 11         96 foreach (keys %FIXED_DATES) {
204 143         1670 my $holiday = $FIXED_DATES{$_};
205              
206 143 100       394 if (my $end = $holiday->{year_ended}) {
207 44 100       140 next if $year > $end;
208             }
209 105 100       355 if (my $start = $holiday->{year_started}) {
210 17 100       58 next if $year < $start;
211             }
212              
213 99 50 66     499 if (my $int = $holiday->{interval}) {
    100          
214 0 0 0     0 next if !$args{gov} && $year % $int != 0;
215             }
216             # Skip government only holidays
217             # This is due to "Algemene termijnwet" which is also valid on the BES
218             # islands: https://wetten.overheid.nl/BWBR0002448/2010-10-10
219             elsif (!$args{gov} && $holiday->{gov}) {
220 10         26 next;
221             }
222              
223 89         241 my $dt = _to_date($holiday->{d}, $holiday->{m}, $year);
224              
225 89 100       37722 if (my $dow = $holiday->{dow}) {
226 11         66 my $cur = $dt->dow();
227 11         115 foreach (keys %$dow) {
228 11 100       62 next unless $cur == $_;
229 3         26 $dt->add(days => $dow->{$_});
230 3         3084 last;
231             }
232             }
233              
234 89         295 _to_holidays(\%h, $dt, $holiday);
235             }
236              
237 11         229 my $dt = _to_date(1, 1, $year);
238 11         4443 foreach (keys %EASTER_BASED) {
239 77         1329 my $holiday = $EASTER_BASED{$_};
240 77 100 100     521 next if !$args{gov} && $holiday->{gov};
241              
242             my $easter = DateTime::Event::Easter->new(
243             easter => 'western',
244             day => $holiday->{d}
245 67         339 );
246 67         16075 my $dt = $easter->following($dt);
247 67         173724 _to_holidays(\%h, $dt, $holiday);
248             }
249              
250 11         268 $cache{$key} = \%h;
251              
252 11         85 return \%h;
253             }
254              
255             sub _to_holidays {
256 156     156   378 my ($cache, $dt, $info) = @_;
257             $cache->{ sprintf("%02i", $dt->day) . sprintf("%02i", $dt->month) }
258 156         443 = [map { $info->{$_} } qw(pap nl en)];
  468         1635  
259             }
260              
261             sub _to_date {
262 118     118   258 my ($day, $month, $year) = @_;
263 118         1007 return DateTime->new(
264             day => $day,
265             month => $month,
266             year => $year,
267             hour => 0,
268             minute => 0,
269             second => 0,
270             time_zone => 'UTC',
271             );
272             }
273              
274             sub is_holiday {
275 18     18 1 7290 my $year = shift;
276 18         41 my $month = shift;
277 18         24 my $day = shift;
278              
279 18         56 my $dt = _to_date($day, $month, $year);
280 18         9898 return is_holiday_dt($dt, @_);
281             }
282              
283             sub is_holiday_dt {
284 19     19 1 326 my $dt = shift;
285              
286 19         61 my %args = @_;
287              
288 19         74 my $holidays = holidays($dt->year, @_);
289 19         111 my $key = sprintf("%02i", $dt->day) . sprintf("%02i", $dt->month);
290              
291 19 100       260 if (exists $holidays->{$key}) {
292 17   100     171 my $lang = lc(delete $args{lang} // 'pap');
293 17 100 66     99 if ($lang eq 'nl' || $lang eq 'nld') {
294 3         35 return $holidays->{$key}[1];
295             }
296 14 100 66     66 if ($lang eq 'en' || $lang eq 'eng') {
297 1         12 return $holidays->{$key}[2];
298             }
299              
300             # default to pap
301 13         150 return $holidays->{$key}[0];
302             }
303 2         41 return;
304             }
305              
306             "Diver's paradise";
307              
308             __END__
309              
310             =pod
311              
312             =encoding UTF-8
313              
314             =head1 NAME
315              
316             Date::Holidays::BQ - Bonaire's official holidays
317              
318             =head1 VERSION
319              
320             version 0.003
321              
322             =head1 SYNOPSIS
323              
324             use Date::Holidays::BQ;
325              
326             if (my $thing = is_holiday(2020, 4, 30, lang => 'en')) {
327             print "It is $thing!", $/; # prints 'It is Bonaire Flag day!'
328             }
329              
330             =head1 DESCRIPTION
331              
332             A L<Date::Holidays> family member from Bonaire
333              
334             =head1 METHODS
335              
336             This module implements the C<is_holiday> and C<holiday> functions from
337             L<Date::Holidays::Abstract>.
338              
339             =head2 is_holiday(yyyy, mm, dd, %additional)
340              
341             is_holiday(
342             '2020', '4', '30',
343             gov => 1, # Important for government institutions
344             lang => 'en' # defaults to pap, alternatively nl/nld or en/eng can be used.
345             );
346              
347             =head2 is_holiday_dt(dt, %additional)
348              
349             is_holiday_dt(
350             DateTime->new(
351             year => 2020,
352             month => 4,
353             day => 30,
354             time_zone => 'America/Curacao',
355             ),
356             gov => 1, # Important for government institutions
357             lang => 'en' # defaults to pap, alternatively nl/nld or en/eng can be used.
358             );
359              
360             =head2 holidays(yyyy, gov => 1)
361              
362             holidays('2022', gov => 1);
363              
364             Similar API to the other functions, returns an hashref for the year.
365              
366             =head1 UTF-8
367              
368             Be aware that we return UTF-8 when Papiamento is chosen. So make sure you set
369             your enconding to UTF-8, otherwise you may see weird things.
370              
371             =head1 SEE ALSO
372              
373             =over
374              
375             =item L<https://wetten.overheid.nl/BWBR0002448/2010-10-10>
376              
377             =back
378              
379             =head1 AUTHOR
380              
381             Wesley Schwengle <waterkip@cpan.org>
382              
383             =head1 COPYRIGHT AND LICENSE
384              
385             This software is Copyright (c) 2022 by Wesley Schwengle.
386              
387             This is free software, licensed under:
388              
389             The (three-clause) BSD License
390              
391             =cut