1. Perl
  2. Date/Time

Get holidays with Google Calendar Data API

Holidays are very difficult to handle because they are decided by humans. There are also holidays such as spring equinox and autumn equinox, which are decided in February of the previous year, and transfer holidays.

In this example, we will get the data of Japanese holidays provided by Google with Google Calendar Data API.

It is not absolutely reliable because it is the data of Japanese holidays examined by Google. If Google is wrong, it will get the wrong holiday data, so please do not use it as it is for applications where the wrong date causes damage. Make sure you are correct by other means.

use strict;
use warnings;

# Use an HTTP client to get information from the web.
use LWP::UserAgent;

# Since the feed is given in XML, parse it with XML::Simple.
use XML::Simple;

# Google Calendar Data API URL (URL to get Japanese holidays)
my $feed_base
  = 'http://www.google.com/calendar/feeds/japanese@holiday.calendar.google.com/public/full';

# Start date including this date
my $start_date = '2007-01-01';

# End date not including this date
my $end_date = '2008-01-01';

# Maximum number of feeds
my $max_results = 100;

my $query = "start-min = ${start_date} & start-max = ${end_date} & max-results = ${max_results}";

my $feed_url = $feed_base.'?'. $Query;

# Get XML from the web
my $http_client = LWP::UserAgent->new;
my $response = $http_client->get($feed_url);

my $holidays_xml;
if ($response->is_success) {
  $holidays_xml = $response->content;
}
else {
  die "Failed to get the feed.";
}

# Parse XML
my $xml_parser = XML::Simple->new;
# XML::Change parser for those who don't have SAX
$XML::Simple::PREFERRED_PARSER = 'XML::Parser';
my $holidays_data = $xml_parser->XMLin($holidays_xml);

my $holidays = [];
for my $key (keys %{$holidays_data->{'entry'}}) {
  my $holiday_day = $holidays_data->{entry}{$key}{'gd: when'}{startTime};
  my $holiday_name = $holidays_data->{entry}{$key}{title}{content};
  push @$holidays, {day => $holiday_day, name => $holiday_name};
}

# Character code is Perl's internal representation (UTF8), so encode as you like
use Encode;
my $encode_to;
if ($^O eq 'MSWin32') {
  $encode_to = 'shift-jis';
}
else {
  $encode_to = 'utf8';
}

# Encode all data
for my $holiday (@$holidays) {
  for my $key (keys %$holiday) {
    $holiday->{$key} = encode($encode_to, $holiday->{$key});
  }
}

use Data::Dumper;
print Data::Dumper->Dump([$holidays], ['* holidays']);

Holiday issues

Holidays vary from country to country. Even if a holiday is decided, the holiday may change due to a transfer holiday. In some cases, such as the equinox and autumn equinox, the government decides on a formal holiday in February of the previous year.

Google Calender Data API

You can use the Google Calender Data API to get national holidays. Transfer holidays are also taken into consideration. Reliability depends on Google's reliability.

Code explanation

Google Calender Data API

The following URL is the URL for getting holidays for the Google Calender Data API.

my $feed_base
  = 'http://www.google.com/calendar/feeds/japanese@holiday.calendar.google.com/public/full';

Create query string

Concatenate the query string with the specified conditions to the above source URL. The date you specify will include the start date and not the end date.

# Start date including this date
my $start_date = '2007-01-01';

# End date not including this date
my $end_date = '2008-01-01';

# Maximum number of feeds
my $max_results = 100;

my $query = "start-min = ${start_date} & start-max = ${end_date} & max-results = ${max_results}";
my $feed_url = $feed_base.'?'. $Query;

In this example, the following URL is created.

[http://www.google.com/calendar/feeds/japanese@holiday.calendar.google.com/public/full?start-min=2007-01-01&start-max=2008-01-01&max-results=100 ]

After that, get the information of the above URL from the Web, analyze it because it is XML data, make it easy to use, and encode the character code according to the OS.

Get XML data from the Web.

LWP::UserAgent is a module for creating HTTP clients. You can programmatically do what your web browser is doing.

use LWP::UserAgent;
my $http_client = LWP::UserAgent->new;
my $response = $http_client->get($feed_url);

my $holidays_xml;
if ($response->is_success) {
  $holidays_xml = $response->content;
}
else {
  die "Failed to get the feed.";
}

Parse XML to make it easy to use.

Use XML::Simple to parse the XML. XML::Simple is a module for converting XML data into Perl data (hash, array).

use XML::Simple;

# Parse XML
my $xml_parser = XML::Simple->new();
$XML::Simple::PREFERRED_PARSER = 'XML::Parser';
my $holidays_data = $xml_parser->XMLin($holidays_xml);

my $holidays = [];
for my $key (keys %{$holidays_data->{'entry'}}) {
  my $holiday_day = $holidays_data->{entry}{$key}{'gd: when'}{startTime};
  my $holiday_name = $holidays_data->{entry}{$key}{title}{content};
  push @$holidays, {day => $holiday_day, name => $holiday_name};
}

After the XML transformation, you can access the data as follows.

# Holiday dates
$holidays_data->{'entry'}{URL as an identifier}{'gd: when'}{startTime};

# Holiday name
$holidays_data->{entry}{URL as an identifier}{title}{content};

Convert character code

The character code of XML received from the Web is UTF-8. When XML::Simple converts XML to Perl data, the characters are converted to Perl's internal representation (UTF-8).

In order to output this correctly, it is necessary to encode it from Perl's internal representation to an appropriate character code.

(Even if the output string is UTF-8, encoding is necessary. It is easy to understand if you think of converting from the internal representation UTF-8 to the external representation UTF-8. Officially, "Turn off the UTF-8 flag. It's hard to understand)

use Encode;
my $encode_to;
if ($^O eq 'MSWin32') {
  $encode_to = 'shift-jis';
}
else {
   $encode_to = 'utf8';
}

# Encode all data
for my $holiday (@$holidays) {
   for my $key (keys %$holiday) {
     $holiday->{$key} = encode($encode_to, $holiday->{$key});
   }
}

Related Informatrion