Pages

自己紹介

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

LuaCalendarで日本の祝日を設定する方法(増補改訂版)

2016-07-24

Rainmeterのスキン「LuaCalendar」を使うとき、日本の祝日・振替休日・国民の休日の設定は、イベントファイルの書き換えだけで完結するよ、という話の増補改訂版。2016年施行の山の日の設定を追加し、数式の記述が面倒だった春分・秋分の日を組み込み変数とした。

Abstract

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

理由

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

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

今回使用しているLuaCalendarはバージョン5.0(あるいはLuaCalndarMod 5.0.1)で、動作にはRainmeter 3.0以降が必要だ。

準備

LuaCalendarの設定ファイル(スキンフォルダーのLuaCalendar\@Resources\Settings.inc)を見ると、イベントファイルを指定するEventFile=#@#Calendars\Holidays.xmlという行で、アメリカの休日が設定されたHolidays.xmlが指定されている(#@#は、スキンフォルダーのLuaCalendar\@Resources\のフルパスに置換される)。現在の日本の休日に対応したHolidaysJP.xml(ZIP形式)を別途用意したので、ZIPファイルを展開後、そこに含まれるHolidaysJP.xmlをHolidays.xmlと同じフォルダーにコピーし、Settings.incの該当行をEventFile=#@#Calendars\HolidaysJP.xmlに書き換えてしまおう。ファイル名の部分を「|」で区切って、同じフォルダーにある複数のイベントファイルを複数指定することも可能だ。なお、今回の増補改訂版では春分の日と秋分の日を組み込み変数化する都合上、このほかにもLuaCalendar本体(スキンフォルダーのLuaCalendar\@Resources\CScript.lua)に8行追加する必要がある(詳細は後述)。

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

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

対策

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

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

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

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

    現状では、「国民の祝日」のうち、元日(1月1日)、建国記念の日(2月11日)、昭和の日(4月29日)、憲法記念日(5月3日)、みどりの日(5月4日)、こどもの日(5月5日)、山の日(8月11日)、文化の日(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日は(振替休日や日曜日でなければ)ただの平日である。これらを厳密に...(以下略)。

  • 追加された「山の日」の場合

    2016年に施行された山の日(8月11日)は、先に説明した「特定の月日と結びついている祝日」に相当する。しかし、2015年以前のカレンダーには表示したくないので、静的関数{$Year}を使って表示年に関する条件を追加することにした。これで、2016年以降の8月11日だけが「山の日」として扱われるようになる。

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

    現在の「国民の祝日」で、設定が難しいのが「春分の日」(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))

    以前の版では、この数式をHolidaysJP.xmlに記述して、春分の日と秋分の日の計算、それぞれの振替休日の計算、敬老の日と秋分の日にはさまれた国民の休日の計算を行なっていた。それぞれの計算で同じ式が何度も登場するため、設定内容が複雑でわかりにくかった。

    今回の増補改訂版では、春分の日と秋分の日の計算をLuaCalendar本体(スキンフォルダーのLuaCalendar\@Resources\CScript.lua)にLuaコードで記述し、組み込み変数として結果を参照できる。すなわち、イベントファイルに{$Shunbun:Day}{$Shuubun:Day}と書けば、表示年における春分の日と秋分の日の日付を取り出せる。変数名が似ている? 祝日の名前を決めた人に言ってくれ。

    LuaCalendarの組み込み変数機能は、計算が面倒くさいことで有名なイースター(復活祭)の日付を求めるために用意されたものだ。組み込み変数{$Easter:Month}{$Easter:Day}で、表示年におけるイースターの月日の値を取り出せる。

    Luaコードによる春分の日・秋分の日の関数は、以下のように書ける。スキンフォルダーのLuaCalendar\@Resources\CScript.luaをお好みのテキストエディタで開き、イースター用の関数Easter()の記述がendで終了した直後(487行あたり)にこれを貼り付ければいい。小数点以下の切り捨てをmath.floor()で行ない、表示年をTime.show.yearで参照することを理解すれば、上の数式と同じ処理をしていることがわかるだろう。

    組み込み変数として春分の日・秋分の日を扱うには、上記の関数を貼り付けたすぐ下の位置にあるBuiltIn = { ... }の内部に、2つのエントリーshunbunshuubunを追加する必要がある(組み込み変数名の大文字・小文字は区別されない)。

    CScript.luaに追加するコードは以上だ。なお、HolidaysJP.xmlのZIPファイルにunified diff形式の差分ファイルを入れたので、patchの当て方がわかる人なら差分ファイルを使うと簡単にコードを変更できる。

    さて、組み込み変数を利用した春分の日・秋分の日とそれらの振替休日の計算は、以下のようにとても簡潔に書ける。

    なお、秋分の日はあと860年ほどの間はすべて22日か23日であるので、日曜日と重なるとしたら「第4日曜日」→{$FourthSun}である。以前配布していたHolidaysJP.xmlの記述「第3日曜日」→{$ThirdSun}では、2007年や2018年などのカレンダーで振替休日の計算に失敗する。以前の記事で何人かの方に指摘を受けたまま、ずっと放置していてごめんなさい。

  • 国民の休日の場合

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

    「みどりの日」が5月4日に移動した2007年以降、この規定による国民の休日は、「敬老の日」(9月第3月曜日)の2日後(9月第4水曜日)が「秋分の日」に当たる年の「秋分の日の前日」に限られる(最近では2009年と2015年が該当)。この条件を整理すると、「秋分の日が9月第4水曜日なら、その前日が国民の休日」と言えるので、組み込み変数${Shuubun:Day}を利用して、以下のように書けばいい。

解説

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

たとえば、ハッピーマンデー制度により、成人の日が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の5.0では「イベントファイル変数」(Event File Variables)が追加され、イベントファイルの内部で自分用の変数を追加できる(とLuaCalnedarのWebページに書かれている)。この記事を書き始めることになったキッカケは、「イベントファイル変数を使えば春分の日・秋分の日の設定がすっきりするな」と思ったからだ。ところが、実際に使ってみたら、

  • Webページの解説には、「Variable要素のName属性で変数名、Case属性で値を設定せよ」としか読み取れない例が載っているが、実際に値を設定するのはselect属性
  • 値に数値や数値同士の計算式は記述できるものの、{$Year}などの静的変数は解釈してくれない

という代物で、春分の日・秋分の日の計算には使い物にならなかった。該当部分の処理を確認するためにLuaコードを読んでいたら、思っていたよりも組み込み変数の実装が楽そうだったので、イベントファイル変数はあきらめて組み込み変数としてみた次第。

1 件のコメント

  1. Windows10にしてからカレンダーガジェットが使えなくなり、こちらを使って日本の祝日に対応したカレンダーを導入することができました。
    ありがとうございます。

    返信削除