File Coverage

blib/lib/Date/Holidays/AU.pm
Criterion Covered Total %
statement 743 743 100.0
branch 218 218 100.0
condition 36 36 100.0
subroutine 101 101 100.0
pod 2 2 100.0
total 1100 1100 100.0


line stmt bran cond sub pod time code
1             package Date::Holidays::AU;
2              
3 1     1   6221 use strict;
  1         2  
  1         41  
4 1     1   5 use warnings;
  1         9  
  1         51  
5              
6 1     1   723 use Time::Local();
  1         3624  
  1         63  
7 1     1   574 use Date::Easter();
  1         1004  
  1         30  
8 1     1   7 use Exporter();
  1         2  
  1         17  
9 1     1   4 use Carp();
  1         2  
  1         25  
10              
11 1     1   4 use base qw(Exporter);
  1         3  
  1         12490  
12             our @EXPORT_OK = qw(is_holiday holidays);
13             our $VERSION = '0.38';
14              
15 9     9   768 sub _DEFAULT_STATE { return 'VIC' }
16 2     2   74 sub _LOCALTIME_YEAR_IDX { return 5 }
17 2     2   7 sub _LOCALTIME_BASE_YEAR { return 1900 }
18 171     171   493 sub _AUSTRALIA_DAY_IN_JANUARY { return 26 }
19 171     171   357 sub _THIRD_DAY_OF_EASTER { return 3 }
20 171     171   1048 sub _FOURTH_DAY_OF_EASTER { return 4 }
21 171     171   418 sub _ANZAC_DAY_IN_APRIL { return 25 }
22 169     169   287 sub _CHRISTMAS_DAY_IN_DECEMBER { return 25 }
23 6     6   12 sub _JANUARY_MONTH_NUMBER { return 1 }
24 5     5   18 sub _FEBRUARY_MONTH_NUMBER { return 2 }
25 90     90   202 sub _MARCH_MONTH_NUMBER { return 3 }
26 171     171   381 sub _APRIL_MONTH_NUMBER { return 4 }
27 33     33   71 sub _MAY_MONTH_NUMBER { return 5 }
28 160     160   307 sub _JUNE_MONTH_NUMBER { return 6 }
29 29     29   60 sub _AUGUST_MONTH_NUMBER { return 8 }
30 57     57   142 sub _OCTOBER_MONTH_NUMBER { return 10 }
31 42     42   75 sub _NOVEMBER_MONTH_NUMBER { return 11 }
32 169     169   235 sub _DECEMBER_MONTH_NUMBER { return 12 }
33 171     171   385 sub _YEAR_OF_QUEEN_ELIZABETHS_DEATH { return 2022 }
34 1     1   3 sub _DAYS_IN_JANUARY { return 31 }
35 4     4   10 sub _DAYS_IN_FEBRUARY_NON_LEAP_YEAR { return 28 }
36 2     2   5 sub _DAYS_IN_FEBRUARY_LEAP_YEAR { return 29 }
37 1     1   3 sub _DAYS_IN_MARCH { return 31 }
38 1     1   3 sub _DAYS_IN_APRIL { return 30 }
39 1     1   3 sub _DAYS_IN_MAY { return 31 }
40 1     1   3 sub _DAYS_IN_JUNE { return 30 }
41 1     1   3 sub _DAYS_IN_JULY { return 31 }
42 1     1   3 sub _DAYS_IN_AUGUST { return 31 }
43 1     1   4 sub _DAYS_IN_SEPTEMBER { return 30 }
44 1     1   3 sub _DAYS_IN_OCTOBER { return 31 }
45 1     1   3 sub _DAYS_IN_NOVEMBER { return 30 }
46 1     1   3 sub _DAYS_IN_DECEMBER { return 31 }
47 3193     3193   6073 sub _MONDAY { return 1 }
48 93     93   225 sub _TUESDAY { return 2 }
49 191     191   427 sub _WEDNESDAY { return 3 }
50 16     16   40 sub _THURSDAY { return 4 }
51 469     469   977 sub _FRIDAY { return 5 }
52 598     598   1290 sub _SATURDAY { return 6 }
53 479     479   1160 sub _SUNDAY { return 0 }
54 15     15   57 sub _STARTING_YEAR_FOR_NSW_ADDITIONAL_DAY { return 2012 }
55 3     3   9 sub _FRIDAY_XMAX_ADDNL_DAY_INCREMENT { return 3 }
56 49     49   185 sub _SATURDAY_CHRISTMAS_DAY_INCREMENT { return 2 }
57 21     21   96 sub _FRIDAY_BOXING_DAY_INCREMENT { return 2 }
58 49     49   169 sub _SATURDAY_BOXING_DAY_INCREMENT { return 3 }
59 1     1   4 sub _SATURDAY_XMAX_ADDNL_DAY_INCREMENT { return 4 }
60 1     1   2 sub _SUNDAY_XMAX_ADDNL_DAY_INCREMENT { return 3 }
61 3     3   12 sub _YEARS_IN_ONE_CENTURY { return 100 }
62 2     2   7 sub _YEARS_IN_FOUR_CENTURIES { return 400 }
63 4     4   16 sub _NUMBER_OF_YEARS_FOR_A_LEAP_YEAR { return 4 }
64              
65             my %allowed_states = (
66             VIC => 1,
67             WA => 1,
68             NT => 1,
69             QLD => 1,
70             TAS => 1,
71             NSW => 1,
72             SA => 1,
73             ACT => 1,
74             );
75              
76             my %tas_local_holidays = (
77             burnieshow => \&_compute_burnie_show,
78             launcestonshow => \&_compute_launceston_show,
79             flindersislandshow => \&_compute_flinders_island_show,
80             hobartshow => \&_compute_hobart_show,
81             recreationday => \&_compute_recreation_day,
82             devonportshow => \&_compute_devonport_show,
83             agfest => \&_compute_agfest,
84             devonportcup => \&_compute_devonport_cup,
85             hobartregatta => \&_compute_hobart_regatta,
86             launcestoncup => \&_compute_launceston_cup,
87             kingislandshow => \&_compute_king_island_show,
88             );
89              
90             my %state_specific_holidays = (
91             ACT => \&_get_act_holidays,
92             NSW => \&_get_nsw_holidays,
93             NT => \&_get_nt_holidays,
94             QLD => \&_get_qld_holidays,
95             SA => \&_get_sa_holidays,
96             TAS => \&_get_tas_holidays,
97             VIC => \&_get_vic_holidays,
98             WA => \&_get_wa_holidays,
99             );
100              
101             sub _get_tas_holidays {
102 44     44   185 my ( $state, $year, %params ) = @_;
103 44 100       114 if ( exists $params{holidays} ) {
104 32 100 100     181 if ( ( ref $params{holidays} )
105             && ( ( ref $params{holidays} ) eq 'ARRAY' ) )
106             {
107             }
108             else {
109 2         374 Carp::croak(q[Holidays parameter must be a reference to an array]);
110             }
111             }
112             else {
113 12         34 $params{holidays} = [];
114             }
115 42         76 my %holidays;
116 42         97 foreach my $allowed ( @{ $params{holidays} } ) {
  42         92  
117 34         78 $allowed = lc $allowed;
118 34         376 $allowed =~ s/\s*//smxg;
119 34         211 my %local_holidays = $tas_local_holidays{$allowed}($year);
120 34         148 while ( my ( $holiday, $name ) = ( each %local_holidays ) ) {
121 34         174 $holidays{$holiday} = $name;
122             }
123             }
124 42         167 foreach my $holiday ( _compute_eight_hours_day($year) )
125             { # TAS eight hours day
126 42         165 $holidays{$holiday} = 'Eight Hours Day';
127             }
128 42         281 return %holidays;
129             }
130              
131             sub _get_act_holidays {
132 8     8   34 my ( $state, $year, %params ) = @_;
133 8         17 my %holidays;
134 8         34 foreach my $holiday ( _compute_canberra_day($year) ) { # canberra day
135 8         32 $holidays{$holiday} = 'Canberra Day';
136             }
137 8 100 100     37 if ( ( exists $params{include_bank_holiday} )
138             && ( $params{include_bank_holiday} ) )
139             {
140 1         8 foreach my $holiday ( _compute_nsw_act_bank_holiday($year) )
141             { # ACT bank holiday
142 1         7 $holidays{$holiday} = 'Bank Holiday';
143             }
144             }
145 8         31 foreach my $holiday ( _compute_nsw_sa_act_labour_day($year) )
146             { # ACT labour day
147 8         27 $holidays{$holiday} = 'Labour Day';
148             }
149 8         51 return %holidays;
150             }
151              
152             sub _get_vic_holidays {
153 36     36   154 my ( $state, $year, %params ) = @_;
154 36         59 my %holidays;
155 36         107 foreach my $holiday ( _compute_vic_labour_day($year) ) { # VIC labour day
156 36         122 $holidays{$holiday} = 'Labour Day';
157             }
158 36         141 foreach my $holiday ( _compute_vic_grand_final_eve_day($year) )
159             { # VIC grand final day
160 16         45 $holidays{$holiday} = 'Grand Final Eve';
161             }
162 35 100 100     133 if ( ( exists $params{no_melbourne_cup} )
163             && ( $params{no_melbourne_cup} ) )
164             {
165             }
166             else {
167 34         116 foreach my $holiday ( _compute_melbourne_cup_day($year) )
168             { # Melbourne Cup day
169 34         98 $holidays{$holiday} = 'Melbourne Cup Day';
170             }
171             }
172 35         196 return %holidays;
173             }
174              
175             sub _get_nsw_holidays {
176 18     18   65 my ( $state, $year, %params ) = @_;
177 18         29 my %holidays;
178 18 100 100     58 if ( ( exists $params{include_bank_holiday} )
179             && ( $params{include_bank_holiday} ) )
180             {
181 3         14 foreach my $holiday ( _compute_nsw_act_bank_holiday($year) )
182             { # NSW bank holiday
183 3         13 $holidays{$holiday} = 'Bank Holiday';
184             }
185             }
186 18         65 foreach my $holiday ( _compute_nsw_sa_act_labour_day($year) )
187             { # NSW labour day
188 18         53 $holidays{$holiday} = 'Labour Day';
189             }
190 18         78 return %holidays;
191             }
192              
193             sub _get_qld_holidays {
194 11     11   52 my ( $state, $year, %params ) = @_;
195 11         22 my %holidays;
196 11         47 foreach my $holiday ( _compute_qld_labour_day($year) ) { # QLD labour day
197 11         49 $holidays{$holiday} = 'Labour Day';
198             }
199 11 100 100     89 if ( ( exists $params{no_show_day} )
200             && ( $params{no_show_day} ) )
201             {
202             }
203             else {
204 10         47 foreach my $holiday ( _compute_qld_show_day($year) )
205             { # Queensland Show day
206 10         93 $holidays{$holiday} = 'Queensland Show Day';
207             }
208             }
209 11         84 return %holidays;
210             }
211              
212             sub _get_nt_holidays {
213 16     16   59 my ( $state, $year, %params ) = @_;
214 16         24 my %holidays;
215 16         61 foreach my $holiday ( _compute_nt_may_day($year) ) { # NT May day
216 16         57 $holidays{$holiday} = 'May Day';
217             }
218 16         52 foreach
219             my $holiday_hashref ( _compute_nt_show_day_hash( $year, \%params ) )
220             { # NT regional show days
221             $holidays{ $holiday_hashref->{date} } =
222 15         47 $holiday_hashref->{name};
223             }
224 15         63 foreach my $holiday ( _compute_nt_picnic_day($year) ) { # NT picnic day
225 15         43 $holidays{$holiday} = 'Picnic Day';
226             }
227 15         91 return %holidays;
228             }
229              
230             sub _get_sa_holidays {
231 7     7   26 my ( $state, $year, %params ) = @_;
232 7         12 my %holidays;
233 7         25 foreach my $holiday ( _compute_sa_adelaide_cup_day($year) )
234             { # adelaide cup day
235 3         9 $holidays{$holiday} = 'Adelaide Cup Day';
236             }
237 7         29 foreach my $holiday ( _compute_sa_volunteers_day($year) )
238             { # SA Volunteers day
239 4         17 $holidays{$holiday} = 'Volunteers Day';
240             }
241 7         36 foreach my $holiday ( _compute_nsw_sa_act_labour_day($year) )
242             { # SA labour day
243 7         22 $holidays{$holiday} = 'Labour Day';
244             }
245 7         53 return %holidays;
246             }
247              
248             sub _get_wa_holidays {
249 35     35   178 my ( $state, $year, %params ) = @_;
250 35         89 my %holidays;
251 35         138 foreach my $holiday ( _compute_wa_labour_day($year) ) { # WA labour day
252 35         150 $holidays{$holiday} = 'Labour Day';
253             }
254 35         137 foreach my $holiday ( _compute_wa_foundation_day($year) )
255             { # WA Foundation day
256 35         126 $holidays{$holiday} = 'Foundation Day';
257             }
258 35         252 return %holidays;
259             }
260              
261             sub holidays {
262 178     178 1 356855 my (%params) = @_;
263 178 100 100     1108 if ( ( exists $params{year} ) && ( defined $params{year} ) ) {
264             }
265             else {
266 2         7 $params{year} = (localtime)[ _LOCALTIME_YEAR_IDX() ];
267 2         10 $params{year} += _LOCALTIME_BASE_YEAR();
268             }
269 178 100       1350 if ( $params{year} !~ /^\d{1,4}$/smx ) {
270 2         291 Carp::croak(
271             q[Year must be numeric and from one to four digits, eg '2004']);
272             }
273 176         376 my $year = $params{year};
274 176 100       460 if ( !defined $params{state} ) {
275 4         10 Carp::carp( 'State not defined, setting state to default: '
276             . _DEFAULT_STATE() );
277 4         22 $params{state} = _DEFAULT_STATE();
278             }
279              
280 176         517 my $state = uc $params{state};
281 176 100       607 if ( !$allowed_states{$state} ) {
282 1         142 Carp::croak(
283             q[State must be one of 'VIC','WA','NT','QLD','TAS','NSW','SA','ACT']
284             );
285             }
286 175         688 my %holidays = $state_specific_holidays{$state}( $state, $year, %params );
287 171         814 foreach my $holiday ( _compute( 1, 1, $year, { 'day_in_lieu' => 1 } ) )
288             { # new years day
289 244 100       483 if ( $holiday eq '0101' ) {
290 171         486 $holidays{$holiday} = 'New Years Day';
291             }
292             else {
293 73         211 $holidays{$holiday} = 'New Years Day Holiday';
294             }
295             }
296 171         523 foreach my $holiday (
297             _compute(
298             _AUSTRALIA_DAY_IN_JANUARY(),
299             1, $year, { 'day_in_lieu' => 1 }
300             )
301             )
302             { # australia day
303 189 100       396 if ( $holiday eq '0126' ) {
304 171         494 $holidays{$holiday} = 'Australia Day';
305             }
306             else {
307 18         60 $holidays{$holiday} = 'Australia Day Holiday';
308             }
309             }
310 171         543 my %easter_day_name = (
311             0 => 'Good Friday',
312             1 => 'Easter Saturday',
313             2 => 'Easter Sunday',
314             _THIRD_DAY_OF_EASTER() => 'Easter Monday',
315             _FOURTH_DAY_OF_EASTER() => 'Easter Tuesday',
316             );
317 171         316 my $count = 0;
318 171         462 foreach my $holiday ( _compute_easter( $year, $state ) ) { # easter
319 726         1894 $holidays{$holiday} = $easter_day_name{$count};
320 726         1015 $count += 1;
321             }
322 171         445 my %extra_holidays = (
323             _get_anzac_holidays( $state, $year ),
324             _get_royal_bday_holidays( $state, $year )
325             );
326              
327 169         623 while ( my ( $holiday, $name ) = ( each %extra_holidays ) ) {
328 354         1210 $holidays{$holiday} = $name;
329             }
330              
331 169         501 foreach my $holiday_hashref ( _compute_christmas_hash( $year, $state ) )
332             { # christmas day + boxing day
333 518         1534 $holidays{ $holiday_hashref->{date} } = $holiday_hashref->{name};
334             }
335 169         1218 return ( \%holidays );
336             }
337              
338             sub _get_anzac_holidays {
339 171     171   364 my ( $state, $year ) = @_;
340 171         260 my %holidays;
341 171         626 my %states_with_anzac_day_holiday_in_lieu = (
342             ACT => 2026,
343             NSW => 2026,
344             WA => 1,
345             );
346              
347 171 100 100     632 if ( ( defined $states_with_anzac_day_holiday_in_lieu{$state} )
348             && ( $states_with_anzac_day_holiday_in_lieu{$state} <= $year ) )
349             {
350 38         118 foreach my $holiday (
351             _compute(
352             _ANZAC_DAY_IN_APRIL(), _APRIL_MONTH_NUMBER(),
353             $year, { 'day_in_lieu' => 1 }
354             )
355             )
356             { # ANZAC day
357 55 100       148 if ( $holiday eq '0425' ) {
358 38         126 $holidays{$holiday} = 'Anzac Day';
359             }
360             else {
361 17         62 $holidays{$holiday} = 'Anzac Day Holiday';
362             }
363             }
364             }
365             else {
366 133         278 foreach my $holiday (
367             _compute( _ANZAC_DAY_IN_APRIL(), _APRIL_MONTH_NUMBER(), $year ) )
368             { # ANZAC day
369 133         366 $holidays{$holiday} = 'Anzac Day';
370             }
371             }
372 171         895 return %holidays;
373             }
374              
375             sub _get_royal_bday_holidays {
376 171     171   384 my ( $state, $year ) = @_;
377 171         269 my %holidays;
378 171 100       420 if ( $state eq 'WA' ) {
    100          
379 35         176 foreach my $holiday ( _compute_wa_royal_bday($year) )
380             { # WA Queens Birthday day
381 33 100       102 if ( $year <= _YEAR_OF_QUEEN_ELIZABETHS_DEATH() ) {
382 26         118 $holidays{$holiday} = q[Queen's Birthday];
383             }
384             else {
385 7         24 $holidays{$holiday} = q[King's Birthday];
386             }
387             }
388             }
389             elsif ( $state eq 'QLD' ) {
390 11         49 foreach my $holiday ( _compute_qld_royal_bday($year) )
391             { # QLD Queens Birthday day
392 11 100       33 if ( $year <= _YEAR_OF_QUEEN_ELIZABETHS_DEATH() ) {
393 8         42 $holidays{$holiday} = q[Queen's Birthday];
394             }
395             else {
396 3         65 $holidays{$holiday} = q[King's Birthday];
397             }
398             }
399             }
400             else {
401 125         317 foreach my $holiday ( _compute_royal_bday($year) )
402             { # King's Birthday day
403 125 100       354 if ( $year <= _YEAR_OF_QUEEN_ELIZABETHS_DEATH() ) {
404 109         345 $holidays{$holiday} = q[Queen's Birthday];
405             }
406             else {
407 16         70 $holidays{$holiday} = q[King's Birthday];
408             }
409             }
410             }
411 169         743 return %holidays;
412             }
413              
414             sub is_holiday {
415 170     170 1 4925 my ( $year, $month, $day, $state, $params ) = @_;
416 170 100       595 if ( !defined $state ) {
417 1         4 $state = _DEFAULT_STATE();
418             }
419 170         319 my $concat = $state;
420 170         297 foreach my $key ( sort { $a cmp $b } keys %{$params} ) {
  1         5  
  170         650  
421 49 100       158 next if ( !$params->{$key} );
422 44 100       115 if ( ref $params->{$key} ) {
423 32 100       115 if ( ( ref $params->{$key} ) eq 'ARRAY' ) {
424 30         87 $concat .= '_' . $key;
425 30         96 foreach my $element ( @{ $params->{$key} } ) {
  30         79  
426 34         102 $concat .= '_' . $element;
427             }
428             }
429             }
430             else {
431 12         36 $concat .= '_' . $key . '_' . $params->{$key};
432             }
433 44         110 $concat = lc $concat;
434 44         977 $concat =~ s/\s*//smxg;
435             }
436 170         386 my $holidays = holidays( 'year' => $year, 'state' => $state, %{$params} );
  170         434  
437 164         518 my $date = sprintf '%02d%02d', $month, $day;
438 164 100       425 if ( $holidays->{$date} ) {
439 123         1395 return 1;
440             }
441             else {
442 41         426 return 0;
443             }
444             }
445              
446             my @days_in_month = (
447             _DAYS_IN_JANUARY(), 0,
448             _DAYS_IN_MARCH(), _DAYS_IN_APRIL(),
449             _DAYS_IN_MAY(), _DAYS_IN_JUNE(),
450             _DAYS_IN_JULY(), _DAYS_IN_AUGUST(),
451             _DAYS_IN_SEPTEMBER(), _DAYS_IN_OCTOBER(),
452             _DAYS_IN_NOVEMBER(), _DAYS_IN_DECEMBER(),
453             ); # feb will be calculated locally
454              
455             sub _compute_christmas_hash {
456 169     169   371 my ( $year, $state ) = @_;
457 169         329 my $day = _CHRISTMAS_DAY_IN_DECEMBER();
458 169         376 my $month = _DECEMBER_MONTH_NUMBER();
459 169         445 my $date = Time::Local::timelocal( 0, 0, 0, $day, ( $month - 1 ), $year );
460 169         9976 my ( $sec, $min, $hour, undef, undef, undef, $wday, $yday, $isdst ) =
461             localtime $date;
462 169         349 my $boxing_day = 'Boxing Day';
463 169 100       460 if ( $state eq 'SA' ) {
464 7         14 $boxing_day = 'Proclamation Day';
465             }
466 169         280 my @holidays;
467 169         849 push @holidays,
468             {
469             'name' => 'Christmas Day',
470             'date' => sprintf '%02d%02d',
471             $month, $day,
472             };
473 169         552 push @holidays,
474             {
475             'name' => $boxing_day,
476             'date' => sprintf '%02d%02d',
477             $month, ( $day + 1 ),
478             };
479 169 100       401 if ( $wday == _FRIDAY() ) { # Christmas is on a Friday
    100          
    100          
480 21         81 push @holidays,
481             {
482             'name' => "$boxing_day Holiday",
483             'date' => sprintf '%02d%02d',
484             $month, ( $day + _FRIDAY_BOXING_DAY_INCREMENT() ),
485             };
486 21 100 100     91 if ( ( $state eq 'NSW' )
487             && ( $year >= _STARTING_YEAR_FOR_NSW_ADDITIONAL_DAY() ) )
488             {
489 3         9 push @holidays,
490             {
491             'name' => 'Additional Day',
492             'date' => sprintf '%02d%02d',
493             $month, ( $day + _FRIDAY_XMAX_ADDNL_DAY_INCREMENT() ),
494             };
495             }
496             }
497             elsif ( $wday == _SATURDAY() ) { # Christmas is on a Saturday
498 49         161 push @holidays,
499             {
500             'name' => 'Christmas Day Holiday',
501             'date' => sprintf '%02d%02d',
502             $month, ( $day + _SATURDAY_CHRISTMAS_DAY_INCREMENT() ),
503             };
504 49         212 push @holidays,
505             {
506             'name' => "$boxing_day Holiday",
507             'date' => sprintf '%02d%02d',
508             $month, ( $day + _SATURDAY_BOXING_DAY_INCREMENT() ),
509             };
510 49 100 100     185 if ( ( $state eq 'NSW' )
511             && ( $year >= _STARTING_YEAR_FOR_NSW_ADDITIONAL_DAY() ) )
512             {
513 1         4 push @holidays,
514             {
515             'name' => 'Additional Day',
516             'date' => sprintf '%02d%02d',
517             $month, ( $day + _SATURDAY_XMAX_ADDNL_DAY_INCREMENT() ),
518             };
519             }
520             }
521             elsif ( $wday == _SUNDAY() ) { # Christmas is on a Sunday
522 56         227 push @holidays,
523             {
524             'name' => 'Christmas Day Holiday',
525             'date' => sprintf '%02d%02d',
526             $month, ( $day + 2 ),
527             };
528 56 100 100     207 if ( ( $state eq 'NSW' )
529             && ( $year >= _STARTING_YEAR_FOR_NSW_ADDITIONAL_DAY() ) )
530             {
531 1         5 push @holidays,
532             {
533             'name' => 'Additional Day',
534             'date' => sprintf '%02d%02d',
535             $month, ( $day + _SUNDAY_XMAX_ADDNL_DAY_INCREMENT() ),
536             };
537             }
538             }
539 169         629 return @holidays;
540             }
541              
542             sub _compute_nt_show_day_hash {
543 16     16   35 my ( $year, $params ) = @_;
544 16         154 my %nt_show_day = (
545             alicesprings =>
546             { name => 'Alice Springs Show Day', month => 6, num_fridays => 1 },
547             tennantcreek =>
548             { name => 'Tennant Creek Show Day', month => 6, num_fridays => 2 },
549             katherine =>
550             { name => 'Katherine Show Day', month => 6, num_fridays => 3 },
551             darwin => { name => 'Darwin Show Day', month => 6, num_fridays => 4 },
552             borroloola =>
553             { name => 'Borrolooda Show Day', month => 7, num_fridays => 4 },
554             );
555 16         36 my ( $month, $num_fridays, $name );
556 16 100 100     70 if ( ( exists $params->{region} ) && ( defined $params->{region} ) ) {
557 5         10 my $region = lc $params->{region};
558 5         38 $region =~ s/\s*//smxg;
559 5 100       12 if ( $nt_show_day{$region} ) {
560 4         5 $name = $nt_show_day{$region}{name};
561 4         6 $month = $nt_show_day{$region}{month};
562 4         6 $num_fridays = $nt_show_day{$region}{num_fridays};
563             }
564             else {
565 1         221 Carp::croak('Unknown region');
566             }
567             }
568             else {
569 11         41 $name = $nt_show_day{darwin}{name};
570 11         24 $month = $nt_show_day{darwin}{month};
571 11         20 $num_fridays = $nt_show_day{darwin}{num_fridays};
572             }
573 15         25 my $day = 1;
574 15         41 my $date = Time::Local::timelocal( 0, 0, 0, $day, $month, $year );
575 15         594 my $fridays = 0;
576 15         29 my ( $sec, $min, $hour, $wday, $yday, $isdst );
577 15         31 while ( $fridays < $num_fridays ) {
578 294         10594 ( $sec, $min, $hour, undef, undef, undef, $wday, $yday, $isdst ) =
579             localtime $date;
580 294 100       418 if ( $wday == _FRIDAY() ) {
581 54         63 $fridays += 1;
582             }
583 294 100       398 if ( $fridays < $num_fridays ) {
584 279         315 $day += 1;
585 279         385 $date = Time::Local::timelocal( 0, 0, 0, $day, $month, $year );
586             }
587             }
588 15         90 my @holidays = (
589             {
590             name => $name,
591             date => sprintf '%02d%02d',
592             ( $month + 1 ), $day,
593             }
594             );
595 15         109 return @holidays;
596             }
597              
598             sub _compute_qld_show_day
599             { # second wednesday in august, except when there are five wednesdays in august when it is the third wednesday
600 10     10   29 my ($year) = @_;
601 10         19 my $day = 1;
602 10         28 my $month = _AUGUST_MONTH_NUMBER() - 1;
603 10         37 my $date = Time::Local::timelocal( 0, 0, 0, $day, $month, $year );
604 10         542 my $wednesdays = 0;
605 10         47 my ( $sec, $min, $hour, $wday, $yday, $isdst );
606 10         0 my $num_wednesdays;
607 10         98 ( $sec, $min, $hour, undef, undef, undef, $wday, $yday, $isdst ) =
608             localtime $date;
609              
610 10 100 100     26 if ( ( $wday >= _MONDAY() ) && ( $wday <= _WEDNESDAY() ) ) {
611 5         15 $num_wednesdays = 3;
612             }
613             else {
614 5         10 $num_wednesdays = 2;
615             }
616 10         32 while ( $wednesdays < $num_wednesdays ) {
617 141         7524 ( $sec, $min, $hour, undef, undef, undef, $wday, $yday, $isdst ) =
618             localtime $date;
619 141 100       297 if ( $wday == _WEDNESDAY() ) {
620 25         40 $wednesdays += 1;
621             }
622 141 100       269 if ( $wednesdays < $num_wednesdays ) {
623 131         163 $day += 1;
624 131         242 $date = Time::Local::timelocal( 0, 0, 0, $day, $month, $year );
625             }
626             }
627 10         66 return ( sprintf '%02d%02d', ( $month + 1 ), $day );
628             }
629              
630             sub _compute_devonport_show
631             { # friday nearest last day in november, but not later than first day in december
632 4     4   10 my ($year) = @_;
633 4         8 my $month = _NOVEMBER_MONTH_NUMBER() - 1;
634 4         9 my $day = $days_in_month[$month];
635 4         10 my $date = Time::Local::timelocal( 0, 0, 0, $day, $month, $year );
636 4         205 my ( $sec, $min, $hour, $wday, $yday, $isdst );
637 4         27 ( $sec, $min, $hour, undef, undef, undef, $wday, $yday, $isdst ) =
638             localtime $date;
639 4 100       13 if ( $wday == _THURSDAY() ) { # thursday
640 1         1 $day = 1;
641 1         4 $month = _NOVEMBER_MONTH_NUMBER();
642             }
643             else {
644 3         18 my %adjustment = ( 0 => 2, 1 => 3, 2 => 4, 3 => 5, 5 => 0, 6 => 1 );
645 3         8 $day -= $adjustment{$wday};
646             }
647 4         14 my $formatted_date = sprintf '%02d%02d', ( $month + 1 ), $day;
648 4         13 return ( $formatted_date, 'Devonport Show' );
649             }
650              
651             sub _compute_devonport_cup
652             { # wednesday not earlier than fifth and not later than the eleventh of January
653 6     6   14 my ($year) = @_;
654 6         15 my $day = _FRIDAY();
655 6         18 my $month = _JANUARY_MONTH_NUMBER() - 1;
656 6         30 my $date = Time::Local::timelocal( 0, 0, 0, $day, $month, $year );
657 6         438 my ( $sec, $min, $hour, $wday, $yday, $isdst );
658 6         61 ( $sec, $min, $hour, undef, undef, undef, $wday, $yday, $isdst ) =
659             localtime $date;
660 6         28 while ( $wday != _WEDNESDAY() ) {
661 20         36 $day += 1;
662 20         65 $date = Time::Local::timelocal( 0, 0, 0, $day, $month, $year );
663 20         1261 ( $sec, $min, $hour, undef, undef, undef, $wday, $yday, $isdst ) =
664             localtime $date;
665             }
666 6         31 my $formatted_date = sprintf '%02d%02d', ( $month + 1 ), $day;
667 6         27 return ( $formatted_date, 'Devonport Cup' );
668             }
669              
670             sub _compute_launceston_cup { # last wednesday in feb
671 4     4   16 my ($year) = @_;
672 4         16 my $month = _FEBRUARY_MONTH_NUMBER() - 1;
673 4         16 my $day = _DAYS_IN_FEBRUARY_NON_LEAP_YEAR();
674              
675 4 100       19 if ( $year % _NUMBER_OF_YEARS_FOR_A_LEAP_YEAR() ) {
676             }
677             else {
678 3 100       12 if ( $year % _YEARS_IN_ONE_CENTURY() ) {
679 1         7 $day = _DAYS_IN_FEBRUARY_LEAP_YEAR();
680             }
681             else {
682 2 100       7 if ( $year % _YEARS_IN_FOUR_CENTURIES() ) {
683             }
684             else {
685 1         7 $day = _DAYS_IN_FEBRUARY_LEAP_YEAR();
686             }
687             }
688             }
689 4         21 my $date = Time::Local::timelocal( 0, 0, 0, $day, $month, $year );
690 4         505 my $wednesdays = 0;
691 4         13 my ( $sec, $min, $hour, $wday, $yday, $isdst );
692 4         19 while ( $wednesdays < 1 ) {
693 15         833 ( $sec, $min, $hour, undef, undef, undef, $wday, $yday, $isdst ) =
694             localtime $date;
695 15 100       42 if ( $wday == _WEDNESDAY() ) {
696 4         11 $wednesdays += 1;
697             }
698 15 100       37 if ( $wednesdays < 1 ) {
699 11         35 $day -= 1;
700 11         26 $date = Time::Local::timelocal( 0, 0, 0, $day, $month, $year );
701             }
702             }
703 4         23 my $formatted_date = sprintf '%02d%02d', ( $month + 1 ), $day;
704 4         25 return ( $formatted_date, 'Launceston Cup' );
705             }
706              
707             sub _compute_eight_hours_day { # second monday in march
708 42     42   95 my ($year) = @_;
709 42         66 my $day = 1;
710 42         96 my $month = _MARCH_MONTH_NUMBER() - 1;
711 42         133 my $date = Time::Local::timelocal( 0, 0, 0, $day, $month, $year );
712 42         2464 my $mondays = 0;
713 42         97 my ( $sec, $min, $hour, $wday, $yday, $isdst );
714 42         116 while ( $mondays < 2 ) {
715 397         17389 ( $sec, $min, $hour, undef, undef, undef, $wday, $yday, $isdst ) =
716             localtime $date;
717 397 100       784 if ( $wday == _MONDAY() ) {
718 84         128 $mondays += 1;
719             }
720 397 100       702 if ( $mondays < 2 ) {
721 355         416 $day += 1;
722 355         686 $date = Time::Local::timelocal( 0, 0, 0, $day, $month, $year );
723             }
724             }
725 42         204 return ( sprintf '%02d%02d', ( $month + 1 ), $day );
726             }
727              
728             sub _compute_king_island_show { # first tuesday in march
729 1     1   4 my ($year) = @_;
730 1         3 my $day = 1;
731 1         5 my $month = _MARCH_MONTH_NUMBER() - 1;
732 1         6 my $date = Time::Local::timelocal( 0, 0, 0, $day, $month, $year );
733 1         87 my $tuesdays = 0;
734 1         4 my ( $sec, $min, $hour, $wday, $yday, $isdst );
735 1         5 while ( $tuesdays < 1 ) {
736 2         92 ( $sec, $min, $hour, undef, undef, undef, $wday, $yday, $isdst ) =
737             localtime $date;
738 2 100       9 if ( $wday == _TUESDAY() ) {
739 1         2 $tuesdays += 1;
740             }
741 2 100       8 if ( $tuesdays < 1 ) {
742 1         20 $day += 1;
743 1         6 $date = Time::Local::timelocal( 0, 0, 0, $day, $month, $year );
744             }
745             }
746 1         7 my $formatted_date = sprintf '%02d%02d', ( $month + 1 ), $day;
747 1         6 return ( $formatted_date, 'King Island Show' );
748             }
749              
750             sub _compute_hobart_regatta { # second monday in feb
751 1     1   4 my ($year) = @_;
752 1         3 my $day = 1;
753 1         5 my $month = _FEBRUARY_MONTH_NUMBER() - 1;
754 1         46 my $date = Time::Local::timelocal( 0, 0, 0, $day, $month, $year );
755 1         91 my $mondays = 0;
756 1         3 my ( $sec, $min, $hour, $wday, $yday, $isdst );
757 1         7 while ( $mondays < 2 ) {
758 9         571 ( $sec, $min, $hour, undef, undef, undef, $wday, $yday, $isdst ) =
759             localtime $date;
760 9 100       115 if ( $wday == _MONDAY() ) {
761 2         5 $mondays += 1;
762             }
763 9 100       27 if ( $mondays < 2 ) {
764 8         15 $day += 1;
765 8         21 $date = Time::Local::timelocal( 0, 0, 0, $day, $month, $year );
766             }
767             }
768 1         8 my $formatted_date = sprintf '%02d%02d', ( $month + 1 ), $day;
769 1         6 return ( $formatted_date, 'Hobart Regatta' );
770             }
771              
772             sub _compute_canberra_day { # third monday in march
773 8     8   22 my ($year) = @_;
774 8         17 my $day = 1;
775 8         22 my $month = _MARCH_MONTH_NUMBER() - 1;
776 8         27 my $date = Time::Local::timelocal( 0, 0, 0, $day, $month, $year );
777 8         619 my $mondays = 0;
778 8         19 my ( $sec, $min, $hour, $wday, $yday, $isdst );
779 8         25 while ( $mondays < 3 ) {
780 151         7052 ( $sec, $min, $hour, undef, undef, undef, $wday, $yday, $isdst ) =
781             localtime $date;
782 151 100       290 if ( $wday == _MONDAY() ) {
783 24         32 $mondays += 1;
784             }
785 151 100       283 if ( $mondays < 3 ) {
786 143         220 $day += 1;
787 143         269 $date = Time::Local::timelocal( 0, 0, 0, $day, $month, $year );
788             }
789             }
790 8         45 return ( sprintf '%02d%02d', ( $month + 1 ), $day );
791             }
792              
793             sub _compute_recreation_day { # first monday in november
794 3     3   10 my ($year) = @_;
795 3         6 my $day = 1;
796 3         10 my $month = _NOVEMBER_MONTH_NUMBER() - 1;
797 3         13 my $date = Time::Local::timelocal( 0, 0, 0, $day, $month, $year );
798 3         217 my $mondays = 0;
799 3         9 my ( $sec, $min, $hour, $wday, $yday, $isdst );
800 3         51 while ( $mondays < 1 ) {
801 8         365 ( $sec, $min, $hour, undef, undef, undef, $wday, $yday, $isdst ) =
802             localtime $date;
803 8 100       24 if ( $wday == _MONDAY() ) {
804 3         6 $mondays += 1;
805             }
806 8 100       24 if ( $mondays < 1 ) {
807 5         9 $day += 1;
808 5         16 $date = Time::Local::timelocal( 0, 0, 0, $day, $month, $year );
809             }
810             }
811 3         13 my $formatted_date = sprintf '%02d%02d', ( $month + 1 ), $day;
812 3         14 return ( $formatted_date, 'Recreation Day' );
813             }
814              
815             sub _compute_melbourne_cup_day { # first tuesday in november
816 34     34   82 my ($year) = @_;
817 34         71 my $day = 1;
818 34         89 my $month = _NOVEMBER_MONTH_NUMBER() - 1;
819 34         100 my $date = Time::Local::timelocal( 0, 0, 0, $day, $month, $year );
820 34         1653 my $tuesdays = 0;
821 34         92 my ( $sec, $min, $hour, $wday, $yday, $isdst );
822 34         79 while ( $tuesdays < 1 ) {
823 91         2883 ( $sec, $min, $hour, undef, undef, undef, $wday, $yday, $isdst ) =
824             localtime $date;
825 91 100       193 if ( $wday == _TUESDAY() ) {
826 34         45 $tuesdays += 1;
827             }
828 91 100       225 if ( $tuesdays < 1 ) {
829 57         72 $day += 1;
830 57         124 $date = Time::Local::timelocal( 0, 0, 0, $day, $month, $year );
831             }
832             }
833 34         123 return ( sprintf '%02d%02d', ( $month + 1 ), $day );
834             }
835              
836             sub _compute_wa_foundation_day { # first monday in june
837 35     35   93 my ($year) = @_;
838 35         56 my $day = 1;
839 35         86 my $month = _JUNE_MONTH_NUMBER() - 1;
840 35         105 my $date = Time::Local::timelocal( 0, 0, 0, $day, $month, $year );
841 35         2129 my $mondays = 0;
842 35         107 my ( $sec, $min, $hour, $wday, $yday, $isdst );
843 35         140 while ( $mondays < 1 ) {
844 160         7981 ( $sec, $min, $hour, undef, undef, undef, $wday, $yday, $isdst ) =
845             localtime $date;
846 160 100       359 if ( $wday == _MONDAY() ) {
847 35         53 $mondays += 1;
848             }
849 160 100       358 if ( $mondays < 1 ) {
850 125         191 $day += 1;
851 125         287 $date = Time::Local::timelocal( 0, 0, 0, $day, $month, $year );
852             }
853             }
854 35         201 return ( sprintf '%02d%02d', ( $month + 1 ), $day );
855             }
856              
857             sub _compute_qld_royal_bday { # first monday in october
858 11     11   33 my ($year) = @_;
859 11         21 my $day = 1;
860 11         57 my $month = _OCTOBER_MONTH_NUMBER() - 1;
861 11         35 my $date = Time::Local::timelocal( 0, 0, 0, $day, $month, $year );
862 11         571 my $mondays = 0;
863 11         26 my ( $sec, $min, $hour, $wday, $yday, $isdst );
864 11         36 while ( $mondays < 1 ) {
865 39         1409 ( $sec, $min, $hour, undef, undef, undef, $wday, $yday, $isdst ) =
866             localtime $date;
867 39 100       83 if ( $wday == _MONDAY() ) {
868 11         18 $mondays += 1;
869             }
870 39 100       84 if ( $mondays < 1 ) {
871 28         41 $day += 1;
872 28         54 $date = Time::Local::timelocal( 0, 0, 0, $day, $month, $year );
873             }
874             }
875 11         58 return ( sprintf '%02d%02d', ( $month + 1 ), $day );
876             }
877              
878             sub _compute_royal_bday { # second monday in june
879 125     125   269 my ($year) = @_;
880 125         167 my $day = 1;
881 125         220 my $month = _JUNE_MONTH_NUMBER() - 1;
882 125         281 my $date = Time::Local::timelocal( 0, 0, 0, $day, $month, $year );
883 125         5386 my $mondays = 0;
884 125         206 my ( $sec, $min, $hour, $wday, $yday, $isdst );
885 125         323 while ( $mondays < 2 ) {
886 1546         63580 ( $sec, $min, $hour, undef, undef, undef, $wday, $yday, $isdst ) =
887             localtime $date;
888 1546 100       2709 if ( $wday == _MONDAY() ) {
889 250         279 $mondays += 1;
890             }
891 1546 100       2583 if ( $mondays < 2 ) {
892 1421         1721 $day += 1;
893 1421         2264 $date = Time::Local::timelocal( 0, 0, 0, $day, $month, $year );
894             }
895             }
896 125         533 return ( sprintf '%02d%02d', ( $month + 1 ), $day );
897             }
898              
899             sub _compute_sa_volunteers_day { # third monday in may up excluding 2006
900 7     7   14 my ($year) = @_;
901 7 100       23 if ( $year == 2006 ) {
902 3         6 return ();
903             }
904 4         5 my $day = 1;
905 4         17 my $month = _MAY_MONTH_NUMBER() - 1;
906 4         42 my $date = Time::Local::timelocal( 0, 0, 0, $day, $month, $year );
907 4         280 my $mondays = 0;
908 4         9 my ( $sec, $min, $hour, $wday, $yday, $isdst );
909 4         13 while ( $mondays < 3 ) {
910 66         2479 ( $sec, $min, $hour, undef, undef, undef, $wday, $yday, $isdst ) =
911             localtime $date;
912 66 100       112 if ( $wday == _MONDAY() ) {
913 12         18 $mondays += 1;
914             }
915 66 100       99 if ( $mondays < 3 ) {
916 62         121 $day += 1;
917 62         108 $date = Time::Local::timelocal( 0, 0, 0, $day, $month, $year );
918             }
919             }
920 4         28 return ( sprintf '%02d%02d', ( $month + 1 ), $day );
921             }
922              
923             sub _compute_sa_adelaide_cup_day { # second monday in march in 2006
924 7     7   17 my ($year) = @_;
925 7 100       21 if ( $year != 2006 ) {
926 4         9 return ();
927             }
928 3         5 my $day = 1;
929 3         7 my $month = _MARCH_MONTH_NUMBER() - 1;
930 3         7 my $date = Time::Local::timelocal( 0, 0, 0, $day, $month, $year );
931 3         147 my $mondays = 0;
932 3         8 my ( $sec, $min, $hour, $wday, $yday, $isdst );
933 3         8 while ( $mondays < 2 ) {
934 39         1270 ( $sec, $min, $hour, undef, undef, undef, $wday, $yday, $isdst ) =
935             localtime $date;
936 39 100       55 if ( $wday == _MONDAY() ) {
937 6         6 $mondays += 1;
938             }
939 39 100       53 if ( $mondays < 2 ) {
940 36         34 $day += 1;
941 36         62 $date = Time::Local::timelocal( 0, 0, 0, $day, $month, $year );
942             }
943             }
944 3         16 return ( sprintf '%02d%02d', ( $month + 1 ), $day );
945             }
946              
947             sub _compute_vic_labour_day { # second monday in march
948 36     36   87 my ($year) = @_;
949 36         61 my $day = 1;
950 36         89 my $month = _MARCH_MONTH_NUMBER() - 1;
951 36         118 my $date = Time::Local::timelocal( 0, 0, 0, $day, $month, $year );
952 36         2489 my $mondays = 0;
953 36         73 my ( $sec, $min, $hour, $wday, $yday, $isdst );
954 36         93 while ( $mondays < 2 ) {
955 412         16588 ( $sec, $min, $hour, undef, undef, undef, $wday, $yday, $isdst ) =
956             localtime $date;
957 412 100       722 if ( $wday == _MONDAY() ) {
958 72         105 $mondays += 1;
959             }
960 412 100       805 if ( $mondays < 2 ) {
961 376         430 $day += 1;
962 376         632 $date = Time::Local::timelocal( 0, 0, 0, $day, $month, $year );
963             }
964             }
965 36         204 return ( sprintf '%02d%02d', ( $month + 1 ), $day );
966             }
967              
968             sub _compute_qld_labour_day { # first monday in may
969 11     11   34 my ($year) = @_;
970 11         26 my $day = 1;
971 11         35 my $month = _MAY_MONTH_NUMBER() - 1;
972 11         49 my $date = Time::Local::timelocal( 0, 0, 0, $day, $month, $year );
973 11         870 my $mondays = 0;
974 11         27 my $which_week = 1;
975 11         32 my ( $sec, $min, $hour, $wday, $yday, $isdst );
976 11         58 while ( $mondays < $which_week ) {
977 42         2073 ( $sec, $min, $hour, undef, undef, undef, $wday, $yday, $isdst ) =
978             localtime $date;
979 42 100       98 if ( $wday == _MONDAY() ) {
980 11         21 $mondays += 1;
981             }
982 42 100       280 if ( $mondays < $which_week ) {
983 31         45 $day += 1;
984 31         69 $date = Time::Local::timelocal( 0, 0, 0, $day, $month, $year );
985             }
986             }
987 11         78 return ( sprintf '%02d%02d', ( $month + 1 ), $day );
988             }
989              
990             sub _compute_vic_grand_final_eve_day { # i have no words ...
991 36     36   143 my ($year) = @_;
992 36         87 my ( $day, $month );
993 36         805 my %grand_final_eve_day = (
994             2015 => { day => 2, month => 9 },
995             2016 => { day => 30, month => 8 },
996             2017 => { day => 29, month => 8 },
997             2018 => { day => 28, month => 8 },
998             2019 => { day => 27, month => 8 },
999             2020 => { day => 23, month => 9 }, # Technically "Thank you" day.
1000             2021 => { day => 24, month => 8 },
1001             2022 => { day => 23, month => 8 },
1002             2023 => { day => 29, month => 8 },
1003             2024 => { day => 27, month => 8 },
1004             2025 => { day => 26, month => 8 },
1005             2026 => { day => 25, month => 8 },
1006             );
1007 36 100       134 if ( $year < 2015 ) {
    100          
1008 19         141 return ();
1009             }
1010             elsif ( $grand_final_eve_day{$year} ) {
1011 16         32 $day = $grand_final_eve_day{$year}{day};
1012 16         28 $month = $grand_final_eve_day{$year}{month};
1013             }
1014             else {
1015 1         221 Carp::croak(
1016             q[Don't know how to calculate Grand Final Eve Day in VIC for this year]
1017             );
1018             }
1019 16         111 return ( sprintf '%02d%02d', ( $month + 1 ), $day );
1020             }
1021              
1022             sub _compute_wa_labour_day { # first monday in march
1023 35     35   91 my ($year) = @_;
1024 35         91 my $day = 1;
1025 35         53 my $month = 2;
1026 35         155 my $date = Time::Local::timelocal( 0, 0, 0, $day, $month, $year );
1027 35         3207 my $mondays = 0;
1028 35         86 my ( $sec, $min, $hour, $wday, $yday, $isdst );
1029 35         122 while ( $mondays < 1 ) {
1030 132         6605 ( $sec, $min, $hour, undef, undef, undef, $wday, $yday, $isdst ) =
1031             localtime $date;
1032 132 100       324 if ( $wday == _MONDAY() ) {
1033 35         61 $mondays += 1;
1034             }
1035 132 100       313 if ( $mondays < 1 ) {
1036 97         168 $day += 1;
1037 97         229 $date = Time::Local::timelocal( 0, 0, 0, $day, $month, $year );
1038             }
1039             }
1040 35         221 return ( sprintf '%02d%02d', ( $month + 1 ), $day );
1041             }
1042              
1043             sub _compute_nt_may_day { # first monday in may
1044 16     16   31 my ($year) = @_;
1045 16         26 my $day = 1;
1046 16         38 my $month = _MAY_MONTH_NUMBER() - 1;
1047 16         41 my $date = Time::Local::timelocal( 0, 0, 0, $day, $month, $year );
1048 16         905 my $mondays = 0;
1049 16         31 my ( $sec, $min, $hour, $wday, $yday, $isdst );
1050 16         70 while ( $mondays < 1 ) {
1051 38         1050 ( $sec, $min, $hour, undef, undef, undef, $wday, $yday, $isdst ) =
1052             localtime $date;
1053 38 100       71 if ( $wday == _MONDAY() ) {
1054 16         24 $mondays += 1;
1055             }
1056 38 100       84 if ( $mondays < 1 ) {
1057 22         28 $day += 1;
1058 22         62 $date = Time::Local::timelocal( 0, 0, 0, $day, $month, $year );
1059             }
1060             }
1061 16         71 return ( sprintf '%02d%02d', ( $month + 1 ), $day );
1062             }
1063              
1064             sub _compute_agfest { # friday following first thursday in may
1065 2     2   7 my ($year) = @_;
1066 2         3 my $day = 1;
1067 2         8 my $month = _MAY_MONTH_NUMBER() - 1;
1068 2         8 my $date = Time::Local::timelocal( 0, 0, 0, $day, $month, $year );
1069 2         134 my $thursdays = 0;
1070 2         6 my ( $sec, $min, $hour, $wday, $yday, $isdst );
1071 2         8 while ( $thursdays < 1 ) {
1072 12         672 ( $sec, $min, $hour, undef, undef, undef, $wday, $yday, $isdst ) =
1073             localtime $date;
1074 12 100       29 if ( $wday == _THURSDAY() ) {
1075 2         5 $thursdays += 1;
1076             }
1077 12 100       24 if ( $thursdays < 1 ) {
1078 10         14 $day += 1;
1079 10         25 $date = Time::Local::timelocal( 0, 0, 0, $day, $month, $year );
1080             }
1081             }
1082 2         11 my $formatted_date = sprintf '%02d%02d', ( $month + 1 ), ( $day + 1 );
1083 2         10 return ( $formatted_date, 'Agfest' );
1084             }
1085              
1086             sub _compute_burnie_show { # friday preceding first saturday in october
1087 8     8   24 my ($year) = @_;
1088 8         17 my $day = 1;
1089 8         21 my $month = _OCTOBER_MONTH_NUMBER() - 1;
1090 8         41 my $date = Time::Local::timelocal( 0, 0, 0, $day, $month, $year );
1091 8         510 my $saturdays = 0;
1092 8         17 my ( $sec, $min, $hour, $wday, $yday, $isdst );
1093 8         21 while ( $saturdays < 1 ) {
1094 15         331 ( $sec, $min, $hour, undef, undef, undef, $wday, $yday, $isdst ) =
1095             localtime $date;
1096 15 100       29 if ( $wday == _SATURDAY() ) {
1097 8         16 $saturdays += 1;
1098             }
1099 15 100       36 if ( $saturdays < 1 ) {
1100 7         8 $day += 1;
1101 7         14 $date = Time::Local::timelocal( 0, 0, 0, $day, $month, $year );
1102             }
1103             }
1104 8         10 my $formatted_date;
1105 8 100       22 if ( $day == 1 ) {
1106 1         10 $formatted_date = sprintf '%02d%02d', $month,
1107             $days_in_month[ $month - 1 ];
1108             }
1109             else {
1110 7         27 $formatted_date = sprintf '%02d%02d', ( $month + 1 ), ( $day - 1 );
1111             }
1112 8         28 return ( $formatted_date, 'Burnie Show' );
1113             }
1114              
1115             sub _compute_launceston_show { # thursday preceding second saturday in october
1116 1     1   2 my ($year) = @_;
1117 1         3 my $day = 1;
1118 1         2 my $month = _OCTOBER_MONTH_NUMBER() - 1;
1119 1         4 my $date = Time::Local::timelocal( 0, 0, 0, $day, $month, $year );
1120 1         61 my $saturdays = 0;
1121 1         3 my ( $sec, $min, $hour, $wday, $yday, $isdst );
1122 1         4 while ( $saturdays < 2 ) {
1123 9         252 ( $sec, $min, $hour, undef, undef, undef, $wday, $yday, $isdst ) =
1124             localtime $date;
1125 9 100       13 if ( $wday == _SATURDAY() ) {
1126 2         3 $saturdays += 1;
1127             }
1128 9 100       13 if ( $saturdays < 2 ) {
1129 8         8 $day += 1;
1130 8         13 $date = Time::Local::timelocal( 0, 0, 0, $day, $month, $year );
1131             }
1132             }
1133 1         3 my $formatted_date = sprintf '%02d%02d', ( $month + 1 ), ( $day - 2 );
1134 1         4 return ( $formatted_date, 'Launceston Show' );
1135             }
1136              
1137             sub _compute_flinders_island_show { # friday preceding third saturday in october
1138 1     1   5 my ($year) = @_;
1139 1         4 my $day = 1;
1140 1         3 my $month = _OCTOBER_MONTH_NUMBER() - 1;
1141 1         4 my $date = Time::Local::timelocal( 0, 0, 0, $day, $month, $year );
1142 1         61 my $saturdays = 0;
1143 1         2 my ( $sec, $min, $hour, $wday, $yday, $isdst );
1144 1         5 while ( $saturdays < 3 ) {
1145 16         506 ( $sec, $min, $hour, undef, undef, undef, $wday, $yday, $isdst ) =
1146             localtime $date;
1147 16 100       22 if ( $wday == _SATURDAY() ) {
1148 3         3 $saturdays += 1;
1149             }
1150 16 100       23 if ( $saturdays < 3 ) {
1151 15         14 $day += 1;
1152 15         19 $date = Time::Local::timelocal( 0, 0, 0, $day, $month, $year );
1153             }
1154             }
1155 1         4 my $formatted_date = sprintf '%02d%02d', ( $month + 1 ), ( $day - 1 );
1156 1         4 return ( $formatted_date, 'Flinders Island Show' );
1157             }
1158              
1159             sub _compute_hobart_show { # thursday preceding fourth saturday in october
1160 3     3   12 my ($year) = @_;
1161 3         6 my $day = 1;
1162 3         12 my $month = _OCTOBER_MONTH_NUMBER() - 1;
1163 3         12 my $date = Time::Local::timelocal( 0, 0, 0, $day, $month, $year );
1164 3         208 my $saturdays = 0;
1165 3         7 my ( $sec, $min, $hour, $wday, $yday, $isdst );
1166 3         13 while ( $saturdays < 4 ) {
1167 69         3521 ( $sec, $min, $hour, undef, undef, undef, $wday, $yday, $isdst ) =
1168             localtime $date;
1169 69 100       160 if ( $wday == _SATURDAY() ) {
1170 12         19 $saturdays += 1;
1171             }
1172 69 100       152 if ( $saturdays < 4 ) {
1173 66         86 $day += 1;
1174 66         128 $date = Time::Local::timelocal( 0, 0, 0, $day, $month, $year );
1175             }
1176             }
1177 3         15 my $formatted_date = sprintf '%02d%02d', ( $month + 1 ), ( $day - 2 );
1178 3         17 return ( $formatted_date, 'Hobart Show' );
1179             }
1180              
1181             sub _compute_nt_picnic_day { # first monday in august
1182 15     15   30 my ($year) = @_;
1183 15         21 my $day = 1;
1184 15         32 my $month = _AUGUST_MONTH_NUMBER() - 1;
1185 15         45 my $date = Time::Local::timelocal( 0, 0, 0, $day, $month, $year );
1186 15         533 my $mondays = 0;
1187 15         26 my ( $sec, $min, $hour, $wday, $yday, $isdst );
1188 15         31 while ( $mondays < 1 ) {
1189 21         271 ( $sec, $min, $hour, undef, undef, undef, $wday, $yday, $isdst ) =
1190             localtime $date;
1191 21 100       42 if ( $wday == _MONDAY() ) {
1192 15         19 $mondays += 1;
1193             }
1194 21 100       50 if ( $mondays < 1 ) {
1195 6         7 $day += 1;
1196 6         10 $date = Time::Local::timelocal( 0, 0, 0, $day, $month, $year );
1197             }
1198             }
1199 15         52 return ( sprintf '%02d%02d', ( $month + 1 ), $day );
1200             }
1201              
1202             sub _compute_nsw_act_bank_holiday { # first monday in august
1203 4     4   13 my ($year) = @_;
1204 4         8 my $day = 1;
1205 4         14 my $month = _AUGUST_MONTH_NUMBER() - 1;
1206 4         16 my $date = Time::Local::timelocal( 0, 0, 0, $day, $month, $year );
1207 4         277 my $mondays = 0;
1208 4         10 my ( $sec, $min, $hour, $wday, $yday, $isdst );
1209 4         16 while ( $mondays < 1 ) {
1210 10         302 ( $sec, $min, $hour, undef, undef, undef, $wday, $yday, $isdst ) =
1211             localtime $date;
1212 10 100       23 if ( $wday == _MONDAY() ) {
1213 4         8 $mondays += 1;
1214             }
1215 10 100       25 if ( $mondays < 1 ) {
1216 6         7 $day += 1;
1217 6         13 $date = Time::Local::timelocal( 0, 0, 0, $day, $month, $year );
1218             }
1219             }
1220 4         25 return ( sprintf '%02d%02d', ( $month + 1 ), $day );
1221             }
1222              
1223             sub _compute_nsw_sa_act_labour_day { # first monday in october
1224 33     33   72 my ($year) = @_;
1225 33         77 my $day = 1;
1226 33         68 my $month = _OCTOBER_MONTH_NUMBER() - 1;
1227 33         82 my $date = Time::Local::timelocal( 0, 0, 0, $day, $month, $year );
1228 33         1679 my $mondays = 0;
1229 33         58 my ( $sec, $min, $hour, $wday, $yday, $isdst );
1230 33         88 while ( $mondays < 1 ) {
1231 113         3320 ( $sec, $min, $hour, undef, undef, undef, $wday, $yday, $isdst ) =
1232             localtime $date;
1233 113 100       202 if ( $wday == _MONDAY() ) {
1234 33         48 $mondays += 1;
1235             }
1236 113 100       222 if ( $mondays < 1 ) {
1237 80         117 $day += 1;
1238 80         138 $date = Time::Local::timelocal( 0, 0, 0, $day, $month, $year );
1239             }
1240             }
1241 33         129 return ( sprintf '%02d%02d', ( $month + 1 ), $day );
1242             }
1243              
1244             sub _compute_wa_royal_bday
1245             { # monday closest to 30 september??? Formula unknown. Seems to have a 9 day spread???
1246 35     35   82 my ($year) = @_;
1247 35         71 my ( $day, $month );
1248 35         1724 my %wa_royal_bday = (
1249             2004 => { day => 4, month => 9 },
1250             2005 => { day => 26, month => 8 },
1251             2006 => { day => 2, month => 9 },
1252             2007 => { day => 1, month => 9 },
1253             2008 => { day => 29, month => 8 },
1254             2009 => { day => 28, month => 8 },
1255             2010 => { day => 27, month => 8 },
1256             2011 => { day => 28, month => 8 },
1257             2012 => { day => 1, month => 9 },
1258             2013 => { day => 30, month => 8 },
1259             2014 => { day => 29, month => 8 },
1260             2015 => { day => 28, month => 8 },
1261             2016 => { day => 26, month => 8 },
1262             2017 => { day => 25, month => 8 },
1263             2018 => { day => 24, month => 8 },
1264             2019 => { day => 30, month => 8 },
1265             2020 => { day => 28, month => 8 },
1266             2021 => { day => 27, month => 8 },
1267             2022 => { day => 26, month => 8 },
1268             2023 => { day => 25, month => 8 },
1269             2024 => { day => 23, month => 8 },
1270             2025 => { day => 29, month => 8 },
1271             2026 => { day => 28, month => 8 },
1272             2027 => { day => 27, month => 8 },
1273             );
1274 35 100       151 if ( $wa_royal_bday{$year} ) {
    100          
1275 33         83 $day = $wa_royal_bday{$year}{day};
1276 33         89 $month = $wa_royal_bday{$year}{month};
1277             }
1278             elsif ( $year <= _YEAR_OF_QUEEN_ELIZABETHS_DEATH() ) {
1279 1         375 Carp::croak(
1280             q[Don't know how to calculate Queen's Birthday in WA for this year]
1281             );
1282             }
1283             else {
1284 1         252 Carp::croak(
1285             q[Don't know how to calculate King's Birthday in WA for this year]);
1286             }
1287 33         541 return ( sprintf '%02d%02d', ( $month + 1 ), $day );
1288             }
1289              
1290             sub _compute_easter {
1291 171     171   359 my ( $year, $state ) = @_;
1292 171         572 my ( $month, $day ) = Date::Easter::gregorian_easter($year);
1293 171         4026 my $date = Time::Local::timelocal( 0, 0, 0, $day, ( $month - 1 ), $year );
1294 171         8559 my ( $sec, $min, $hour, $wday, $yday, $isdst );
1295 171         1448 ( $sec, $min, $hour, $day, $month, $year, $wday, $yday, $isdst ) =
1296             localtime $date;
1297 171         328 my @holidays;
1298              
1299             # good friday + easter saturday
1300 171 100       395 if ( $month == 2 ) { # march
1301 61         278 push @holidays, sprintf '%02d%02d', ( $month + 1 ), ( $day - 2 );
1302 61         182 push @holidays, sprintf '%02d%02d', ( $month + 1 ), ( $day - 1 );
1303             }
1304             else { # april
1305 110 100       335 if ( $day == 2 ) {
    100          
1306 1         4 push @holidays,
1307             sprintf '%02d%02d', $month, $days_in_month[ $month - 1 ];
1308 1         3 push @holidays, sprintf '%02d%02d', ( $month + 1 ), 1;
1309             }
1310             elsif ( $day == 1 ) {
1311 2         13 push @holidays,
1312             sprintf '%02d%02d', $month, ( $days_in_month[ $month - 1 ] - 1 );
1313 2         8 push @holidays,
1314             sprintf '%02d%02d', $month, ( $days_in_month[ $month - 1 ] );
1315             }
1316             else {
1317 107         446 push @holidays, sprintf '%02d%02d', ( $month + 1 ), ( $day - 2 );
1318 107         309 push @holidays, sprintf '%02d%02d', ( $month + 1 ), ( $day - 1 );
1319             }
1320             }
1321              
1322             # easter sunday
1323 171         503 push @holidays, sprintf '%02d%02d', ( $month + 1 ), $day;
1324              
1325             # easter monday
1326 171 100       340 if ( $month == 2 ) { # march
1327 61 100       227 if ( $day == $days_in_month[$month] ) {
1328 4         17 push @holidays, sprintf '%02d%02d', ( $month + 2 ), 1;
1329             }
1330             else {
1331 57         149 push @holidays, sprintf '%02d%02d', ( $month + 1 ), ( $day + 1 );
1332             }
1333             }
1334             else {
1335 110         343 push @holidays, sprintf '%02d%02d', ( $month + 1 ), ( $day + 1 );
1336             }
1337 171 100       429 if ( $state eq 'TAS' ) {
1338 42 100       133 if ( $month == 2 ) { # march
1339 5 100       21 if ( $day == $days_in_month[$month] ) {
    100          
1340 1         3 push @holidays, sprintf '%02d%02d', ( $month + 2 ), 2;
1341             }
1342             elsif ( ( $day + 1 ) == $days_in_month[$month] ) {
1343 1         3 push @holidays, sprintf '%02d%02d', ( $month + 2 ), 1;
1344             }
1345             else {
1346 3         13 push @holidays,
1347             sprintf '%02d%02d', ( $month + 1 ), ( $day + 2 );
1348             }
1349             }
1350             else {
1351 37         111 push @holidays, sprintf '%02d%02d', ( $month + 1 ), ( $day + 1 );
1352             }
1353             }
1354 171         735 return @holidays;
1355             }
1356              
1357             sub _compute {
1358 513     513   1080 my ( $day, $month, $year, $params ) = @_;
1359 513         1215 my $date = Time::Local::timelocal( 0, 0, 0, $day, ( $month - 1 ), $year );
1360 513         24459 my ( $sec, $min, $hour, $wday, $yday, $isdst );
1361 513         0 my @holidays;
1362 513         1467 push @holidays, sprintf '%02d%02d', $month, $day;
1363 513 100       1158 if ( $params->{day_in_lieu} ) {
1364 380         3004 ( $sec, $min, $hour, $day, $month, $year, $wday, $yday, $isdst ) =
1365             localtime $date;
1366 380 100       874 if ( $wday == _SUNDAY() ) {
    100          
1367 39         95 $day += 1;
1368 39         140 push @holidays, sprintf '%02d%02d', ( $month + 1 ), $day;
1369             }
1370             elsif ( $wday == _SATURDAY() ) {
1371 69         118 $day += 2;
1372 69         215 push @holidays, sprintf '%02d%02d', ( $month + 1 ), $day;
1373             }
1374             }
1375 513         1515 return (@holidays);
1376             }
1377              
1378             1;
1379              
1380             __END__