Date-Holidays
view release on metacpan or search on metacpan
lib/Date/Holidays.pm view on Meta::CPAN
sub is_holiday {
my ( $self, %params ) = @_;
# Our result
my $r;
if ( not $params{'countries'} ) {
if ( blessed $self) {
$r = $self->{'_inner_object'}->is_holiday(%params);
}
else {
my @countries = all_country_codes(); # From Locale::Country
@countries = sort @countries;
$params{'countries'} = \@countries;
$r = __PACKAGE__->_check_countries(%params);
}
}
else {
if ( blessed $self) {
$r = $self->_check_countries(%params);
}
else {
$r = __PACKAGE__->_check_countries(%params);
}
}
return $r;
}
sub holidays_dt {
my ( $self, %params ) = @_;
my $hashref = $self->holidays( year => $params{'year'} );
my %dts;
foreach my $h ( keys %{$hashref} ) {
my ( $month, $day ) = $h =~ m{
\A # Beginning of string
(\d{2}) # 2 digits indicating the month
(\d{2}) # 2 digits indicating the day
\Z # End of string
}xsm;
my $dt = DateTime->new(
year => $params{'year'},
month => $month,
day => $day,
);
$dts{ $hashref->{$h} } = $dt;
}
return \%dts;
}
sub _check_countries {
my ( $self, %params ) = @_;
my $result = {};
my $precedent_calendar = q{};
foreach my $country ( @{ $params{'countries'} } ) {
#The list of countries is ordered
if ( $country =~ m/\A[+](\w+)/xism ) {
$country = $1;
$precedent_calendar = $country;
}
try {
my $dh = $self->new(
countrycode => $country,
nocheck => $params{nocheck}
);
if ( !$dh ) {
my $countryname = code2country($country);
my $countrycode = $country;
die
"Unable to initialize Date::Holidays for country: $countrycode - $countryname\n";
}
my %prepared_parameters = (
year => $params{'year'},
month => $params{'month'},
day => $params{'day'},
);
if ( $params{gov} ) {
$prepared_parameters{gov} = $params{gov};
}
if ( $params{lang} ) {
$prepared_parameters{lang} = $params{lang};
}
# did we receive special regions parameter?
if ( $params{regions} ) {
$prepared_parameters{regions} = $params{regions};
}
# did we receive special state parameter?
if ( $params{state} ) {
$prepared_parameters{state} = $params{state};
}
my $r = $dh->is_holiday(%prepared_parameters);
if ( $precedent_calendar eq $country ) {
$self->{precedent_calendar} = $dh;
}
# handling precedent calendar
if ( $precedent_calendar
and $precedent_calendar ne $country )
{
my $holiday = $self->{precedent_calendar}
->is_holiday(%prepared_parameters);
# our precedent calendar dictates overwrite or nullification
if ( defined $holiday ) {
$r = $holiday;
}
}
if ( defined $r ) {
$result->{$country} = $r;
}
}
catch {
warn "$_\n";
}
}
return $result;
}
sub is_holiday_dt {
my $self = shift;
my $dt = shift;
return $self->is_holiday(
year => $dt->year,
month => $dt->month,
day => $dt->day,
@_,
);
}
sub _fetch {
my ( $self, $params ) = @_;
# Do we have a country code?
if ( not $self->{'_countrycode'} and not $params->{countrycode} ) {
die "No country code specified\n";
}
my $countrycode = $params->{countrycode} || $self->{'_countrycode'};
# Do we do country code assertion?
if ( !$params->{'nocheck'} ) {
# Is our country code valid or local?
if ( $countrycode !~ m/\Alocal\Z/xism
and not code2country($countrycode) )
{ #from Locale::Country
die "$countrycode is not a valid country code\n";
}
}
# Trying to load adapter module for country code
my $module;
try {
# We load an adapter implementation
if ( $countrycode =~ m/\Alocal\Z/xism ) {
$module = 'Date::Holidays::Adapter::Local';
}
elsif ( code2country($countrycode) ) {
$module = 'Date::Holidays::Adapter::' . uc $countrycode;
lib/Date/Holidays.pm view on Meta::CPAN
if ( $module = $self->_load($module) ) {
warn "we got a module and we return\n";
}
}
catch {
warn "Unable to load module: $module - $_\n";
$module = 'Date::Holidays::Adapter';
$module = $self->_load($module);
};
};
# Returning name of loaded module upon success
return $module;
}
1;
__END__
=pod
=encoding UTF-8
=begin markdown
# Date::Holidays
[](https://metacpan.org/pod/Date::Holidays)

[](https://github.com/jonasbn/perl-date-holidays/actions/workflows/ci.yml)
[](https://coveralls.io/github/jonasbn/perl-date-holidays?branch=master)
[](https://opensource.org/license/artistic-2-0/)
<!-- MarkdownTOC autoanchor=false -->
<!-- /MarkdownTOC -->
=end markdown
=head1 NAME
Date::Holidays - Date::Holidays::* adapter and aggregator for all your holiday needs
=head1 VERSION
The documentation describes version 1.35 of Date::Holidays
=head1 FEATURES
=over
=item * Exposes a uniform interface towards modules in the Date::Holidays::* namespace
=item * Inquire whether a certain date is a holiday in a specific country or a set of countries
=item * Inquire for a holidays for a given year for a specific country or a set of countries
=item * Overwrite/rename/suppress national holidays with your own calendar
=back
=head1 SYNOPSIS
use Date::Holidays;
# Initialize a national holidays using the ISO 3361 country code
my $dh = Date::Holidays->new(
countrycode => 'dk'
);
# Inquire and get a local name for a holiday if it is a national holiday
my $holidayname = $dh->is_holiday(
year => 2004,
month => 12,
day => 25
);
# Inquire and get a set of local names for national holiday in a given country
my $hashref = $dh->holidays(
year => 2004
);
# Inquire and get local names for a set of countries, where the specific date is a
# national holiday
$holidays_hashref = Date::Holidays->is_holiday(
year => 2004,
month => 12,
day => 25,
countries => ['se', 'dk', 'no'],
);
foreach my $country (keys %{$holidays_hashref}) {
print $holidays_hashref->{$country}."\n";
}
# Example of a module with additional parameters
# Australia is divided into states with local holidays
# using ISO-3166-2 codes
my $dh = Date::Holidays->new(
countrycode => 'au'
);
$holidayname = $dh->is_holiday(
year => 2004,
month => 12,
day => 25,
state => 'TAS',
);
$hashref = $dh->holidays(
year => 2004
state => 'TAS',
);
# Another example of a module with additional parameters
# Great Britain is divided into regions with local holidays
# using ISO-3166-2 codes
my $dh = Date::Holidays->new(
countrycode => 'gb'
);
$holidayname = $dh->is_holiday(
year => 2014,
month => 12,
day => 25,
regions => ['EAW'],
);
$hashref = $dh->holidays(
year => 2014
regions => ['EAW'],
);
=head1 DESCRIPTION
Date::Holidays is an adapters exposing a uniform API to a set of distributions
in the Date::Holidays::* namespace. All of these modules deliver methods and
information on national calendars, but no standardized API exist.
The distributions more or less follow a I<de> I<facto> standard (see: also the generic
adapter L<Date::Holidays::Adapter|https://metacpan.org/pod/Date::Holidays::Adapter>), but the adapters are implemented to uniform
this and Date::Holidays exposes a more readable API and at the same time it
provides an OO interface, to these diverse implementations, which primarily
holds a are procedural.
As described below it is recommended that a certain API is implemented (SEE:
B<holidays> and B<is_holiday> below), but taking the adapter strategy into
consideration this does not matter, or we attempt to do what we can with what is
available on CPAN.
If you are an module author/CPAN contributor who wants to comply to the suggested,
either look at some of the other modules in the Date::Holidays::* namespace to get an
idea of the I<de> I<facto> standard or have a look at L<Date::Holidays::Abstract|https://metacpan.org/pod/Date::Holidays::Abstract> and
L<Date::Holidays::Super|https://metacpan.org/pod/Date::Holidays::Super> - or write me.
In addition to the adapter feature, Date::Holidays also do aggregation, so you
can combine calendars and you can overwrite and redefined existing calendars.
=head2 DEFINING YOUR OWN CALENDAR
As mentioned in the FEATURES section it is possible to create your own local calendar.
This can be done using a L<JSON|https://metacpan.org/pod/JSON> file with your local definitions:
{
"1501" : "jonasbn's birthday"
}
This also mean you can overwrite your national calendar:
{
"1225" : ""
}
You can specify either month plus day for a recurring holiday. If you you want to define
a holiday for a specific year, simply extend the date with year:
{
"201.1625" : ""
}
In order for the calendar to be picked up by Date::Holidays, set the environment variable:
$HOLIDAYS_FILE
This should point to the JSON file.
=head1 SUBROUTINES/METHODS
=head2 new
This is the constructor. It takes the following parameters:
=over
=item countrycode (MANDATORY, see below), unique two letter code representing a country name. Please refer to ISO3166 (or L<Locale::Country|https://metacpan.org/pod/Locale::Country>)
=item nocheck (optional), if set to true the countrycode specified will not be validated against a list of known country codes for existence, so you can build fake holidays for fake countries, I currently use this for test. This parameter might disap...
=back
The constructor loads the module from Date::Holidays::*, which matches the
country code and returns a Date::Holidays module with the specified module
loaded and ready to answer to any of the following methods described below, if
these are implemented - of course.
If no countrycode is provided or the class is not able to load a module, nothing
is returned.
my $dh = Date::Holidays->new(countrycode => 'dk')
or die "No holidays this year, get back to work!\n";
=head2 holidays
This is a wrapper around the loaded module's B<holidays> method if this is
implemented. If this method is not implemented it tries <countrycode>_holidays.
Takes 3 optional named arguments:
=over
=item * year, four digit parameter representing year
=item * state, ISO-3166-2 code for a state
Not all countries support this parameter
=item * regions, pointing to a reference to an array of ISO-3166-2 code for regions
Not all countries support this parameter
=back
$hashref = $dh->holidays(year => 2007);
=head2 holidays_dt
This method is similar to holidays. It takes one named argument b<year>.
The result is a hashref just as for B<holidays>, but instead the names
of the holidays are used as keys and the values are DateTime objects.
lib/Date/Holidays.pm view on Meta::CPAN
These parameters are left to the module authors discretion and the actual
Date::Holidays::* module should be consulted.
Example Date::Holidays::AU
use Date::Holidays::AU qw( is_holiday );
my ($year, $month, $day) = (localtime)[ 5, 4, 3 ];
$year += 1900;
$month += 1;
my ($state) = 'VIC';
print "Excellent\n" if is_holiday( $year, $month, $day, $state );
=head1 DEVELOPING A DATE::HOLIDAYS::ADAPTER CLASS
If you want to contribute with an adapter, please refer to the documentation in
L<Date::Holidays::Adapter|https://metacpan.org/pod/Date::Holidays::Adapter>.
=head1 DEVELOPING ON DATE::HOLIDAYS
Date::Holidays is distributed and maintained using L<Dist::Zilla|https://metacpan.org/pod/Dist::Zilla>
=head2 RUNNING THE TEST SUITE
The test suite can be executed using
$ dzil test
The test suite, which attempts lots scenarios does emit a lot of warnings, so it is recommended to suppress C<STDERR> by redirecting it to C</dev/null>
$ dzil test 2> /dev/null
To enable author tests aimed at asserting distribution and code quality in addition to functionality, use the C<--author> flag
$ dzil test --author 2> /dev/null
If you are working on a release, use the C<--release> flag
$ dzil test --release 2> /dev/null
The release flag is implicit for the L<Dist::Zilla|https://metacpan.org/pod/Dist::Zilla> release command.
=head1 DIAGNOSTICS
=over
=item * No country code specified
No country code has been specified.
=item * Unable to initialize Date::Holidays for country: <countrycode>
This message is emitted if a given country code cannot be loaded.
=back
=head1 CONFIGURATION AND ENVIRONMENT
As mentioned in the section on defining your own calendar. You have to
set the environment variable:
$HOLIDAYS_FILE
This environment variable should point to a JSON file containing holiday definitions
to be used by L<Date::Holidays::Adapter::Local|https://metacpan.org/pod/Date::Holidays::Local>.
=head1 DEPENDENCIES
=over
=item * L<Carp|https://metacpan.org/pod/Carp>
=item * L<DateTime|https://metacpan.org/pod/DateTime>
=item * L<Locale::Country|https://metacpan.org/pod/Locale::Country>
=item * L<Module::Load|https://metacpan.org/pod/Module::Load>
=item * L<Try::Tiny|https://metacpan.org/pod/Try::Tiny>
=item * L<Scalar::Util|https://metacpan.org/pod/Scalar::Util>
=item * L<JSON|https://metacpan.org/pod/JSON>
=item * L<File::Slurp|https://metacpan.org/pod/File::Slurp>
=back
=head2 FOR TESTING
=over
=item * L<Test::Class|https://metacpan.org/pod/Test::Class>
=item * L<Test::More|https://metacpan.org/pod/Test::More>
=item * L<FindBin|https://metacpan.org/pod/FindBin>
=back
Please see the F<cpanfile> included in the distribution for a complete listing.
=head1 INCOMPATIBILITIES
Currently the following CPAN Date::Holidays distributions are unsupported:
=over
=item * L<Date::Holidays::UK|https://metacpan.org/pod/Date::Holidays::UK> only supports bank holidays until 2007
=item * L<Date::Holidays::UK::EnglandAndWales|https://metacpan.org/pod/Date::Holidays::UK::EnglandAndWales> only supports bank holidays until 2014
=back
Additional issues might be described the specific adapter classes or their respective adaptees.
=head1 BUGS AND LIMITATIONS
Currently we have an exception for the L<Date::Holidays::AU|https://metacpan.org/pod/Date::Holidays::AU> module, so the
( run in 0.797 second using v1.01-cache-2.11-cpan-5c0b1e786e0 )