内閣府から祝日の一覧を取得+DBへ格納し、祝日マスタをプログラムでメンテナンスする方法をします。
概要
・祝日情報は内閣府(www8.cao.go.jp)から取得する
・取得したデータをDBに格納する
・一定期日前より前の日付は取り込まない
・12/31、1/2、1/3は追加で登録する
・取得したデータをDBに格納する
・一定期日前より前の日付は取り込まない
・12/31、1/2、1/3は追加で登録する
祝日マスタの登録について
内閣府から祝日データを自動取得し、SPIRALのデータベースに一括登録するPHPスクリプトを紹介します。
実装の概要
1. 内閣府の祝日CSVデータをcURLで取得する。
2. 取得したCSVデータをパースし、指定日付以降のデータをフィルタリングする。
3. 大晦日や三が日などの追加休日を設定する。
4. 日付順にソートしてデータを整理する。
5. SPIRAL APIを使用してデータベースに一括登録・更新する。
6. 処理結果を表示する。
2. 取得したCSVデータをパースし、指定日付以降のデータをフィルタリングする。
3. 大晦日や三が日などの追加休日を設定する。
4. 日付順にソートしてデータを整理する。
5. SPIRAL APIを使用してデータベースに一括登録・更新する。
6. 処理結果を表示する。
データベース設計
祝日マスタのデータベース構造は以下の通りです。
項目名 | 識別名 | フィールドタイプ | DB上で必須な属性 |
---|---|---|---|
日付 | holidayAt | 日付(○年○月○日) | 必須制約 ユニーク制約 主キー |
休日名 | body | テキストフィールド(128 bytes) | なし |
サンプルデータ
日付 | 休日名 |
2025/1/1 | 元日 |
2025/1/13 | 成人の日 |
2025/2/11 | 建国記念の日 |
PHPコード(メイン機能)
祝日データを自動取得・登録するPHPスクリプトです。
コピー<?php /** * 休日登録サービス * 内閣府から休日データを取得し、Spiral APIを使用してデータベースに登録する */ // ==================== 設定定数 ==================== // 環境ごとに設定してください const SPIRAL_API_TOKEN = ''; const SPIRAL_API_SECRET = ''; // マスタ登録する日付の下限 const WITHOUT_LOWER_DATE = '2025-01-01'; class HolidayRegisterService { // 内閣府の休日データを取得するURL private const SHUKUJITU_CSV_URL = 'https://www8.cao.go.jp/chosei/shukujitsu/syukujitsu.csv'; // データベース設定 // データベース名は環境ごとに設定してください private const DB_TITLE = 'holiday'; private const KEY_COLUMN = 'holidayAt'; private const COLUMNS = ['holidayAt', 'body']; /** * 値が空でないかチェックする関数 * * @param mixed $value チェックする値 * @return bool 値が存在し、空でない場合はtrue */ private function filled($value): bool { if (is_null($value)) { return false; } if (is_string($value)) { return trim($value) !== ''; } if (is_array($value)) { return !empty($value); } return true; } /** * cURLを使用してHTTPリクエストを実行する * * @param string $url リクエストURL * @param array $options cURLオプション * @return string レスポンス * @throws Exception cURLエラーが発生した場合 */ private function executeCurlRequest(string $url, array $options = []): string { $curl = curl_init(); // デフォルトオプションを設定 $defaultOptions = [ CURLOPT_URL => $url, CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 30, CURLOPT_FOLLOWLOCATION => true, ]; // オプションをマージ(追加オプションが優先) $mergedOptions = $options + $defaultOptions; curl_setopt_array($curl, $mergedOptions); $response = curl_exec($curl); if (curl_errno($curl)) { $error = curl_error($curl); curl_close($curl); throw new Exception("cURL error occurred: {$error}"); } curl_close($curl); return $response; } /** * 内閣府から休日データを取得する * * @param DateTime|null $lower 取得する日付の下限(nullの場合は全期間) * @return array 休日データの配列 [['日付', '休日名'], ...] * @throws Exception データ取得に失敗した場合 */ private function fromCabinetOffice(?DateTime $lower = null): array { // 下限日付を設定 if ($this->filled($lower)) { $lower->setTime(0, 0, 0); } // 内閣府からCSVデータを取得 $response = $this->executeCurlRequest(self::SHUKUJITU_CSV_URL); // 文字エンコーディングを変換(SHIFT-JIS → UTF-8) $response = mb_convert_encoding($response, 'utf-8', 'SHIFT-JIS'); // CSVデータをパース $holidays_data = explode(PHP_EOL, rtrim($response)); array_shift($holidays_data); // ヘッダー行を削除 // 日付フィルタリングとデータ整形 $filtered_holidays = array_map(function ($item) use ($lower) { return $this->parseHolidayData($item, $lower); }, $holidays_data); // null値を除去して配列を再構築 $filtered_holidays = array_filter($filtered_holidays, function ($item) { return $this->filled($item); }); return array_values($filtered_holidays); } /** * 休日データの1行をパースする * * @param string $item CSVの1行 * @param DateTime|null $lower 下限日付 * @return array|null パースされたデータまたはnull */ private function parseHolidayData(string $item, ?DateTime $lower): ?array { $parts = explode(",", $item); if (count($parts) < 2) { return null; } $date = $parts[0]; // 例:1955/1/1 $holidayName = rtrim($parts[1]); // 日付をDateTimeオブジェクトに変換 $dateTime = DateTime::createFromFormat('Y/n/j', $date); if (!$dateTime) { return null; } $dateTime->setTime(0, 0, 0); // 下限日付でフィルタリング if ($this->filled($lower) && $dateTime < $lower) { return null; } return [$date, $holidayName]; } /** * 休日データを取得し、追加の休日を設定する * * @return array 完全な休日データの配列 */ private function holidays(): array { // 内閣府から基本データを取得 $lowerDate = new DateTime(WITHOUT_LOWER_DATE); $holidays = $this->fromCabinetOffice($lowerDate); // 追加の休日を設定 $holidays = array_merge($holidays, $this->getAdditionalHolidays()); // 日付昇順にソート usort($holidays, function ($a, $b) { return strtotime($a[0]) - strtotime($b[0]); }); return $holidays; } /** * 追加の休日(大晦日、三が日など)を取得する * * @return array 追加休日の配列 */ private function getAdditionalHolidays(): array { $currentYear = (int)date('Y'); $nextYear = $currentYear + 1; return [ // 実行年の大晦日 [ date('Y/12/31'), '大晦日', ], // 来年の1/2(三が日) [ "{$nextYear}/1/2", '三が日', ], // 来年の1/3(三が日) [ "{$nextYear}/1/3", '三が日', ], ]; } /** * 休日データをデータベースに一括登録・更新する * * @param array $holidays 休日データの配列 * @return array APIレスポンス * @throws Exception API呼び出しに失敗した場合 */ private function upsertHolidays(array $holidays): array { return SimpleSpiralApiRequest::databaseBulkUpsert([ 'db_title' => self::DB_TITLE, 'key' => self::KEY_COLUMN, 'columns' => self::COLUMNS, 'data' => $holidays, ]); } /** * メイン処理を実行する * * 1. 内閣府から休日データを取得 * 2. 追加の休日を設定 * 3. データベースに登録・更新 */ public static function main(): void { try { $service = new self(); echo "休日データの取得を開始します...\n"; $holidays = $service->holidays(); echo "取得した休日数: " . count($holidays) . "\n"; echo "データベースへの登録を開始します...\n"; $res = $service->upsertHolidays($holidays); echo "登録完了!\n"; var_dump($res); } catch (Exception $e) { echo "エラーが発生しました: " . $e->getMessage() . "\n"; exit(1); } } }
PHPコード(SPIRAL API呼び出し機能)
SPIRAL APIのBulk Upsertを呼び出すPHPスクリプトです。
コピー<?php class SimpleSpiralApiRequest { private const LOCATOR_URL = "https://www.pi-pe.co.jp/api/locator"; private static ?string $apiUrl = null; /** * APIでlocatorを取得する * * @return string APIのURL * @throws Exception API呼び出しに失敗した場合 */ private static function fetchApiUrl(): string { $api_headers = [ "X-SPIRAL-API: locator/apiserver/request", "Content-Type: application/json; charset=UTF-8", ]; $parameters = [ "spiral_api_token" => SPIRAL_API_TOKEN ]; $ch = curl_init(self::LOCATOR_URL); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($parameters)); curl_setopt($ch, CURLOPT_HTTPHEADER, $api_headers); $response = curl_exec($ch); if (curl_errno($ch)) { throw new Exception(curl_error($ch)); } curl_close($ch); $response_array = json_decode($response, true); if (!isset($response_array['location'])) { throw new Exception('Invalid API response: location not found'); } return $response_array['location']; } /** * APIのURLを取得する(既に取得済みの場合はそれを返す) * * @return string APIのURL */ private static function getApiUrl(): string { if (is_null(self::$apiUrl)) { self::$apiUrl = self::fetchApiUrl(); } return self::$apiUrl; } /** * データベースの一括登録・更新を実行する * * @param array $param パラメータ * @return array APIレスポンス * @throws Exception API呼び出しに失敗した場合 */ public static function databaseBulkUpsert(array $param): array { $api_headers = [ "X-SPIRAL-API: database/bulk_upsert/request", "Content-Type: application/json; charset=UTF-8" ]; $time = time(); // 認証パラメータを構築 $basicParam = [ "spiral_api_token" => SPIRAL_API_TOKEN, "passkey" => $time, "signature" => hash_hmac('sha1', SPIRAL_API_TOKEN . "&" . $time, SPIRAL_API_SECRET, false), ]; $ch = curl_init(self::getApiUrl()); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(array_merge($basicParam, $param))); curl_setopt($ch, CURLOPT_HTTPHEADER, $api_headers); $response = curl_exec($ch); if (curl_errno($ch)) { throw new Exception(curl_error($ch)); } curl_close($ch); $response_array = json_decode($response, true); // エラーチェック if (!array_key_exists('code', $response_array) || $response_array['code'] !== "0") { throw new Exception('SPIRAL API Error Occurred.[response:' . $response . ']'); } return $response_array; } }
実行&実行結果
以下プログラムにて処理が実行されます。
HolidayRegisterService::main();
スクリプトを実行すると、以下のような出力が表示されます。
コピー休日データの取得を開始します... 取得した休日数: 25 データベースへの登録を開始します... 登録完了! array(3) { ["code"]=> string(1) "0" ["message"]=> string(2) "OK" ["results"]=> array(40) { [0]=> array(2) { ["id"]=> int(1258) ["status"]=> string(7) "updated" } ... } }
実装時の注意点
・ このスクリプトは、SPIRAL APIの認証情報が必要です。
・ 内閣府のCSVデータはSHIFT-JISエンコーディングで提供されます。
・ 実行前にSPIRAL_API_TOKENとSPIRAL_API_SECRETを設定してください。
・ データベース名(DB_TITLE)は環境に合わせて変更してください。
・ 日付の下限設定(WITHOUT_LOWER_DATE)を適切に設定してください。
・ 内閣府のCSVデータはSHIFT-JISエンコーディングで提供されます。
・ 実行前にSPIRAL_API_TOKENとSPIRAL_API_SECRETを設定してください。
・ データベース名(DB_TITLE)は環境に合わせて変更してください。
・ 日付の下限設定(WITHOUT_LOWER_DATE)を適切に設定してください。
まとめ
本記事では、内閣府から祝日データを自動取得し、SPIRALのデータベースに一括登録するPHPスクリプトを紹介しました。
このスクリプトにより、毎年更新される祝日データを手動で管理する手間を大幅に削減できます。
実行前に適切な認証情報(TOKEN,SECRET)とデータベース設定を行い、定期的な実行(カスタムプログラムによる定期実行)で祝日マスタを最新に保つことをお勧めします。
このスクリプトにより、毎年更新される祝日データを手動で管理する手間を大幅に削減できます。
実行前に適切な認証情報(TOKEN,SECRET)とデータベース設定を行い、定期的な実行(カスタムプログラムによる定期実行)で祝日マスタを最新に保つことをお勧めします。