Google Calendar Data API で祝日を取得する




  1. Perl




  2. 日付・時刻


 祝日というのは人間が決めたものなので非常に扱いにくいものです。春分秋分という前年の2月に決まる祝日や、振替休日などもあります。

 今回のサンプルではGoogleGoogle Calendar Data APIで提供してくれている日本の祝日のデータを取得することにします。

 あくまでGoogleが調べた日本の休日のデータなので絶対的な信頼性はありません。Googleが間違っていれば間違った祝日のデータを取得しますので、日付の間違いが損害を及ぼすようなアプリケーションにそのまま使用してはいけません。かならず他の手段で正しいことを確かめるようにします。

use strict;
use warnings;

# Web上から情報を取得するのでHTTPクライアントを使用する。
use LWP::UserAgent;

#フィードがXMLで与えられるのでXML::Simpleで解析。
use XML::Simple;

# Google Calendar Data API のURL( 日本の祝日を取得するためのURL )
my $feed_base
  = 'http://www.google.com/calendar/feeds/japanese@holiday.calendar.google.com/public/full';

# この日を含む開始日
my $start_date = '2007-01-01';

# この日を含まない終了日
my $end_date = '2008-01-01';

# フィードの最大取得件数
my $max_results = 100;

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

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

# WebからXMLを取得
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 "フィードの取得に失敗しました。";
}

# XMLを解析
my $xml_parser = XML::Simple->new;
# XML::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};
}

# 文字コードがPerlの内部表現( UTF8 )になっているのでお好みに応じてエンコード
use Encode;
my $encode_to;
if ($^O eq 'MSWin32') {
  $encode_to = 'shift-jis';
}
else {
  $encode_to = 'utf8';
}

# データすべてをエンコード
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']);

祝日の問題

 祝日は国によってことなります。また祝日が決まっても振り替え休日で休日が変化することもあります。春分秋分などのように政府が前年の2月に正式な祝日の日を決定するものもあります。

Google Calender Data API

 Google Calender Data API を使用すると、国民の休日を取得することができます。振替休日も考慮されています。信頼性はGoogleの信頼性によります。

コード解説

Google Calender Data API

 以下のURLがGoogle Calender Data API の祝日取得のためのURLです。

my $feed_base
  = 'http://www.google.com/calendar/feeds/japanese@holiday.calendar.google.com/public/full';
クエリ文字列の作成

 上記の元になるURLに条件を指定したクエリ文字列を連結します。指定する日付は開始日を含み、終了日を含まないものになります。

# この日を含む開始日
my $start_date = '2007-01-01';

# この日を含まない終了日
my $end_date = '2008-01-01';

# フィードの最大取得件数
my $max_results = 100;

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

 このサンプルでは以下のURLを作成しています。
  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

 あとは上記URLの情報をWebから取得して、XMLデータなのでこれを解析して使いやすい形にして、OSに応じて文字コードエンコードします。

WebからXMLデータを取得する。

 LWP::UserAgentは、HTTPクライアントを作成するためのモジュールです。Webブラウザがやっていることをプログラム上で行えます。

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 "フィードの取得に失敗しました。";
}
XMLを解析して使いやすいデータにする。

 XMLを解析するにはXML::Simpleを使用します。XML::SimpleはXMLデータをPerlのデータ(ハッシュ、配列)に変換するためのモジュールです。

use XML::Simple;

# 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};
}

 XML変換後はデータに以下のようにしてアクセスできます。

# 祝日の日付
$holidays_data->{'entry'}{識別子となるURL}{'gd:when'}{startTime};

# 祝日の名前
$holidays_data->{entry}{識別子となるURL}{title}{content};
文字コードを変換する

 Webから受け取ったXML文字コードUTF-8です。XML::SimpleがXMLPerlのデータに変換した時点で、文字はPerlの内部表現( UTF-8 )に変換されます。

 これを正しく出力するためには、Perlの内部表現から適切な文字コードエンコードする必要があります。

 (出力する文字列がたとえUTF-8であろうともエンコードは必要です。内部表現UTF-8から外部表現UTF-8に変換すると考えると理解しやすいです。公式には「UTF-8フラグを落とす」といいますがわかりにくい)

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

# データすべてをエンコード
for my $holiday (@$holidays) {
  for my $key (keys %$holiday){
    $holiday->{$key} = encode($encode_to, $holiday->{$key});
  }
}