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

[![CPAN version](https://badge.fury.io/pl/Date-Holidays.svg)](https://metacpan.org/pod/Date::Holidays)
![stability-stable](https://img.shields.io/badge/stability-stable-green.svg)
[![Build Status](https://github.com/jonasbn/perl-date-holidays/actions/workflows/ci.yml/badge.svg)](https://github.com/jonasbn/perl-date-holidays/actions/workflows/ci.yml)
[![Coverage Status](https://coveralls.io/repos/github/jonasbn/perl-date-holidays/badge.svg?branch=master)](https://coveralls.io/github/jonasbn/perl-date-holidays?branch=master)
[![License: Artistic-2.0](https://img.shields.io/badge/License-Artistic%202.0-0298c3.svg)](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 )