Pages

自己紹介

某IT技術情報誌に連載記事を持っていたテクニカルライター。またもや休刊してしまったよ。
Copyright © 2011-2016 Daregada. All rights reserved. Powered by Blogger.

LuaCalendarで日本の祝日を設定する方法

2012-12-10

Rainmeterのスキン「LuaCalendar」を使うとき、日本の祝日・振替休日・国民の休日の設定は、イベントファイルの書き換えだけで完結するよ、という話。以下の内容は古いため、増補改訂版を参照されたい。

Abstract

理由
LuaCalendarのイベントファイルでは、変数や条件判断を含む数式を利用できるので、現在の日本の祝日・振替休日・国民の休日を問題なく記述可能なため
準備
イベントファイルに毎年繰り返される休日を設定する場合の一般的な構造を解説する。
対策
2012年現在の日本の休日は、以下のいずれかの方法で設定することが可能である。
解説
さらに厳密な休日の設定をする方法についてちょっとだけ解説する。

理由

Rainmeterのガジェット(Rainmeter用語ではスキン)のひとつに、1ヶ月分のカレンダーを表示する「LuaCalendar」がある。前後の月への切り替えや、スタイルシートによる外見の変更にも対応した優れものだ。人気のあるテーマ「Enigma」とのデザイン的な親和性も高いので、Enigmaのカレンダースキンの代わりに使っている人も多いだろう。

LuaCalendarでは、休日や記念日などのイベントの月・日の値・説明文をXML形式で記述したイベントファイルを読み込んで、カレンダーの表示に反映してくれる。日の値には、「成人の日」(1月第2月曜日)などを容易に設定するための{$SecondMon}などの変数日(Variable Days)を利用できる。また、表示年(西暦)に置換される{$Year}などの静的変数(Static Variables)と、Rainmeterに組み込まれた四則演算や条件判断を含む数式評価機能(Formula)を組み合わせることで、簡易的な天文計算が必要な「春分の日」や「秋分の日」、祝日法の規定に基づく「振替休日」や「国民の休日」に対し、毎年書き換えなくても通用する設定を行なうことが可能だ。

今回使用しているLuaCalendarはバージョン4.1で、動作にはRainmeter 2.5(r1706)以降が必要だ。なお、バージョン4.0までは変数の記述方法が異なり、{SecondMon}{Year}のように$記号を付けないので、古いバージョンを利用している場合は適宜読み替えて欲しい。

準備

LuaCalendarの設定ファイル(スキンフォルダーのLuaCalendar\@Resources\Settings.inc)を見ると、イベントファイルを指定するEventFile=#@#Calendars\Holidays.xmlという行で、アメリカの休日が設定されたHolidays.xmlが指定されている(#@#は、スキンフォルダーのLuaCalendar\@Resources\のフルパスに置換される)。現在の日本の休日に対応したHolidaysJP.xmlを別途用意したので、これをHolidays.xmlと同じフォルダーにコピーし、Setteings.incの該当行をEventFile=#@#Calendars\HolidaysJP.xmlに書き換えてしまおう。なお、「|」で区切って複数のイベントファイル(のフルパス)を並べて指定することも可能だ。

イベントファイルで休日設定を行なう場合の一般的な構造を以下に示す。なお、一度きりのイベントも記述できるように作られているので、すべての休日を毎年繰り返すイベントとして扱うには、EventFile要素の開始タグにRepeat="Year"を指定する(さもないと、個々の休日にRepeat属性の記述が必要になる)。

個々の休日は、月・日の値をそれぞれMonth/Day属性で指定したEvent要素として記述することもできるし(1)、1ヶ月分をまとめた(月の値をMonth属性で指定した)Set要素を用意し、その内容に日の値のみをDay属性で指定したEvent要素として書くこともできる(2)。たいていの祝日に振替休日の処理が伴うため、(2)の形式で書くことが多いだろう。なお、Description属性に日本語の説明を書く場合はMS漢字コード(シフトJIS)で保存するのだが、このとき(本来ならutf-8以外では必須の)XML宣言を付けるとパースに失敗するので、XML宣言を書かないこと。

対策

現在の日本の祝日・振替休日・国民の休日は、国民の祝日に関する法律(祝日法)によって定められている。 祝日法は、1948年に公布されてからこれまでに8回の改正が行なわれており、後から追加された祝日や日付が移動した祝日、ハッピーマンデー制度の適用によって月曜日に移動した祝日、振替休日や国民の休日に関する規定の追加や修正など、正確に再現するには結構複雑な処理が必要になる。

条件判断を含む数式(後述)を駆使すれば、すべての休日の施行・変更年月日を考慮した厳密な設定も可能だ。しかし、LuaCalendarのユーザーインターフェースでは数年遡るのにも結構な手間がかかるので、HolidaysJP.xmlでは現在の日本の休日を正確に表示するための設定に絞っている。実際、2006年以前の「みどりの日」と「昭和の日」、2002年以前は「海の日」と「敬老の日」、1999年以前は「成人の日」と「体育の日」の日付が誤って表示されるので注意されたい。

さて、2012年現在の日本の祝日・振替休日・国民の休日は、以下のいずれかの方法で設定することが可能である。

  • 特定の月日と結びついている祝日の場合

    現状では、「国民の祝日」のうち、元日(1月1日)、建国記念の日(2月11日)、昭和の日(4月29日)、憲法記念日(5月3日)、みどりの日(5月4日)、こどもの日(5月5日)、文化の日(11月3日)、勤労感謝の日(11月23日)、天皇誕生日(12月23日)がこれに相当する。イベントファイルでは、これらの月日をそれぞれ数値で直接指定すればいい。

  • 月曜日と結びついている祝日の場合

    現状では、「国民の祝日」のうち、成人の日(1月第2月曜日)、海の日(7月第3月曜日)、敬老の日(9月第3月曜日)、体育の日(10月第2月曜日)がこれに相当する。LuaCalendarでは、こうした「第n番目のw曜日」の日の値に置換される変数日(Variable Days)を用意している。たとえば、第2月曜日なら{$SecondMon}、第3月曜日なら{$ThirdMon}だ。イベントファイルでは、月の値に直接数値を指定し、日の値にこれらの変数を指定すればいい。

  • 振替休日の場合

    現状の振替休日の規定は、『「国民の祝日」が日曜日に当たるときは、その日後においてその日に最も近い「国民の祝日」でない日を休日とする』というものだ(国民の祝日に関する法律 第3条2項)。前項の「月曜日と結びついている祝日」以外のすべての祝日は、日曜日に当たる可能性がある。

    厳密には、上記の規定が施行されたのは2007年1月1日から。1973年4月12日~2006年12月31日は、『「国民の祝日」が日曜日に当たるときは、その翌日を休日とする』だった(月曜日に限定)。さらに、1973年4月11日以前は振替休日に関する規定がないため、祝日が日曜日に当たっていても振替休日は発生しない。静的変数{$Year}{$Month}を使って、表示年月を含む条件を数式に組み込めば、これらを厳密に処理することも可能だ(面倒なので今回は省略)。

    イベントファイルで振替休日の設定を行なうには、Rainmeterの数式(Formula)機能を利用する。四則演算や条件判断を含む数式を評価可能だ。用意されている演算子や関数は、RainmeterのCalc measure / Formula Syntax(計算量/数式構文)を参照。なお、イベントファイル(XML形式)中に記述する都合上、比較演算子の「<」や「>」や論理演算子の「&&」を、実体参照(「&lt;」など)で書く必要があることに注意されたい。

    振替休日の処理では、祝日が日曜日かどうかを判断して、日曜日なら「振替休日(たいていは翌日)の日の値」、そうでなければ「0」となる数式を日の値として指定する。日付が0になった設定は、カレンダーには表示されないからだ。

    なお、LuaCalendarの変数日は「第n番目のw曜日」形式しか用意されていないので、曜日だけを調べることはできない。祝日が1~7日なら{$FirstSun}、8~14日なら{$SecondSun}、15~21日なら{$ThirdSun}、22~28日なら{$FourthSun}、29~31日なら{$LastSun}と比較しよう。たとえば、元日(1月1日)の場合、1日が日曜日かどうかを調べる条件式は、1={$FirstSun}と書ける(「等しい」は「=」ひとつ)。

    こうした条件式の真偽によって数式の値を変えるには、C言語と同じ三項演算子「(条件式) ? 真の場合の値 : 偽の場合の値」を使うとわかりやすい(30回までネスト可能)。真の場合の値は振替休日の日の値、偽の場合の値は0にする。たとえば、元日とその振替休日(1月2日)の設定は以下のようになる。

    ゴールデンウィーク後半の連休の場合、3~5日のいずれかが日曜日かどうかを、(3={$FirstSun}) || (4={$FirstSun}) || (5={$FirstSun})という条件式で判断する(「または」は「||」、「=」より優先順位が高いため丸カッコが必要)。いずれかが日曜日なら5月6日が振替休日になるので、5月の休日設定をまとめると以下のように書ける。

    厳密には、「みどりの日」が5月4日になったのは2007年以降で、1986年~2006年は「国民の休日」だった。当時の「国民の休日」は、『祝日に挟まれた日(ただし、日曜日と振替休日を除く)を休日とする』という規定なので、この期間の5月4日が日曜日でも振替休日は発生しない点や、5月3日が日曜日なら5月4日は(国民の休日ではなく)単なる振替休日になる点など、祝日とは扱いがかなり異なる。さらに、1985年以前は、祝日法にこの規定がなかったため、5月4日は(振替休日や日曜日でなければ)ただの平日である。これらを厳密に...(以下略)。

  • 例外: 春分の日と秋分の日

    現在の「国民の祝日」で、設定が難しいのが「春分の日」(3月20日ごろ)と「秋分の日」(9月23日ごろ)だ。前年2月に官報で発表されるまで正式な日付が確定しないし、それらの予測値となる天の赤道と黄道との交点(春分日・秋分日)を求めるには天文計算が必要になる。

    イベントファイルで厳密な天文計算をするのは明らかにやりすぎなので、春分日・秋分日の簡易計算式で代用する。これには、書籍「新こよみ便利帳―天文現象・暦計算のすべて」(海上保安庁水路部「暦計算研究会」編、現在絶版状態か)に掲載されている簡易計算式のうち、1980年~2099年用のものを利用する。

    春分の日・秋分の日の簡易計算式だけなら、Addin Box / 祝日についてなどに(上記の本の引用として)載っている。なお、この式の結果に誤差があるという掲示板の書き込みは、式そのものが間違っている(末尾のint(yyyy-1980)/4。正しくは、int((yyyy-1980)/4))ので、気にしないように。

    簡易計算式に指定するパラメータは西暦年のみだが、四則計算のほかに「小数部分を切り捨てる関数」が必要になる。LuaCalendarの場合、表示年(西暦)は静的関数{$Year}で取得し、小数部分を切り捨てる関数もtrunc()として用意されているので、以下のように書ける。

    春分日
    trunc(20.8431+0.242194*({$Year}-1980)-trunc(({$Year}-1980)/4))
    秋分日
    trunc(23.2488+0.242194*({$Year}-1980)-trunc(({$Year}-1980)/4))

    なお、LuaCalendarには、休日の計算をLuaコードで記述し、組み込み変数として結果を参照する機能も用意されている。実際、LuaCalendarのCScript.luaには、イースター(復活祭)の日付を求める関数が含まれており、組み込み変数{$EasterMonth}{$EasterDay}で、表示年におけるイースターの月日の値を取り出せる。春分の日・秋分の日についても同様の処理は可能だが、面倒なのでやらない。

    この数式を利用すると、1980年~2099年の春分の日・秋分の日(とそれらの振替休日)は以下のように書ける。振替休日については、祝日の日の値が数式(trunc(...))である点に注意すれば、前項の振替休日の処理と同じ形をしていることがわかるだろう。

  • 国民の休日の場合

    現状の国民の休日の規定は、『その前日及び翌日が「国民の祝日」である日を(「国民の祝日」でない日に限り)休日とする』というものだ(国民の祝日に関する法律 第3条3項)。

    「みどりの日」が5月4日に移動した2007年以降、この規定による国民の休日は、「敬老の日」(9月第3月曜日)の2日後(9月第4水曜日)が「秋分の日」に当たる年の「9月第4火曜日」に限られる。この条件を整理すると、「秋分の日が9月第4水曜日なら、9月第4火曜日が国民の休日」と言えるので、さきほどの簡易計算式を利用して、以下のように書けばいい。

解説

さらに厳密な設定をするには、祝日法の改正が施行された年月日とその内容を把握する必要がある。

たとえば、ハッピーマンデー制度により、成人の日が1月15日から1月第2月曜日に移動したのは、1998年の改正が施行された2000年1月1日以降だ。つまり、成人の日をより正確に再現するには、1999年までは1月15日、2000年以降は1月第2月曜日になるような数式を設定すればいい。

「表示年(西暦)が2000より小さい」という条件式は、{$Year}&lt;2000と書ける(「小さい」を意味する「<」は実体参照「&lt;」で書く必要がある)。よって、成人の日の設定は以下のようになる。

待てよ、成人の日は、祝日法が公布・施行された1948年7月20日より前には存在していない。さらに厳密さを求めるなら、「表示年(西暦)が1949より小さければ0、そうでなくて2000より小さければ15、そうでなければ第2月曜日」という数式にしなくては。以下のように、三項演算子を二重にネストすれば書ける。

おっと、1999年以前は、成人の日が第3日曜日に当たる可能性があるので、振替休日の設定も行なう必要があるな。厳密には、振替休日の規定を含む改正がはじめて施行されたのは1973年4月12日だから...面倒になってきたので、もう止めよう。実際のところ、最大1年単位でしか遡れないLuaCalendarのユーザーインターフェースでは、2,3年前までならともかく、数十年前まで遡ってカレンダーを見ようとする人はまずいないと思われる。

この記事を書くきっかけは、LuaCalendarで日本の祝日などを表示する方法を探していて、見つけたブログの記事が「Google Calendar APIを叩いて祝日リストを取得」していたこと。

念のため補足しておくと、上記のブログの筆者が「ひな形」として利用したLuaCalendarのバージョン3.1では、日付の設定に数式を使えなかった。数式がサポートされたのはバージョン3.2から。

「え、祝日を取り込むのにそれは大げさすぎるんじゃないの」と思って付属のHolidays.xmlを見たら、アメリカの「選挙の日」(Election Day、2年ごと)が数式で記述されていた。そこからRainmeterの数式構文にたどり着き、比較演算子を実体参照で書かないで嵌まったりしながら仕上げたという次第。出来上がったイベントファイルの内容が大げさすぎるような気がするのは...気のせいだろう。

7 件のコメント

  1. すばらしい。
    これで毎年休日を指定する手間がなくなりました。

    返信削除
  2. どうもです。
    ReadMeを参考に私も、おじゃまします

    誕生日




    新聞休刊日
























    ミソは、Styles.incの[HolidayStyle]で色指定すると
    ソレが優先される様なので、EventFileで個別指定しました。
    なお、EventFile内で複数の色を指定する場合、
    各々に指定するか、別にパッケージングし、
    EventFileで区切る方がそさそうです

    返信削除
    返信
    1. すみませんが、コード部分(?)がこちらに送られる段階で取り除かれているようです。

      削除
  3. 秋分の日の22日・23日は第4日曜になるので、FourthSunとの比較も必要かと思います。

    返信削除
  4. 秋分の日の振替休日の判定は{$FourthSun}ではないでしょうか

    返信削除
  5. 最近、Google Calendar APIを叩いて
    祝日リストの取得ができなくなってみたいなので、助かりました

    「山の日」2016年8月11日から
    http://www8.cao.go.jp/chosei/shukujitsu/gaiyou.html
    2019年8月11日は日曜日なので、
    2019年8月12日は「振替休日」になりますね


    追加しないといけませんね。
    *****************************************************************




    *****************************************************************

    返信削除
  6. 日本の祝日用のxmlのリンクがおかしくなっているようです。
    ぜひ利用させていただきたいと思ったのですが・・・。

    返信削除