BXjaholiday: LaTeXで祝日・曜日判定

2019-10-14 (updated: 2025-12-08) #LaTeX #expl3

日本には祝日がたくさんあり、祝日数世界第3位のホリデー大国にあたるのだそうです。さらに、2000年以降はいわゆる「ハッピーマンデー制度」のために日付が固定されないものが多く、日本の祝日判定の難しさは世界でも類を見ないレベルと考えられます(推測です。他国がどうかは調べてません)。

そうした背景もあってか、某アレ Users SlackでTeX/LaTeXのための祝日判定機実装が要望されていたため、約1年前にexpl3で祝日判定を実装しました。

台風19号の影響で、一昨日の土曜日に予定されていたTeXConf 2019が中止になり、TeX不足でのたうち回っている人もいるかもしれないので、これを機にこのパッケージの紹介をしてみたいと思います。

祝日・曜日の判定にBXjaholiday

基本的な使い方

BXjaholidayはすでにTeX LiveとMiKTeXに取り込まれており、これらのディストリビューションの最新版利用者であれば特別にインストール等を行う必要はありません。

BXjaholidayを使用するには、まずは通常通りプリアンブルでパッケージの読み込みを行います。

\usepackage{bxjaholiday}

パッケージオプションはありません。BXjaholidayパッケージはpdfTeX, XeTeX, LuaTeX, (u)pTeXをサポートしています1

祝日名

最も基本的な命令は\jaholidaynameです。この命令は

\jaholidayname{<year>}{<month>}{<day>}

の形で使用します。<year>, <month>, <day> は西暦で日付を表す数値です。例えば2019年1月1日(元日)の祝日名を得たい場合には次のように記述します。

\jaholidayname{2019}{1}{1}%=>元日

これにより、紙面に「元日」と印字されます2。与えた日付が祝日でない場合は、何も印字されません(つまり、展開結果は空文字列になります)。

少しTeX言語要素の入った使い方になりますが、この命令の引数には具体的な算用数字だけではなくカウンタレジスタ等を与えることも可能です。例えば、TeX実行時の年・月・日をそれぞれ格納しているカウンタレジスタ\year, \month, \dayを引数に与えると、実行日(つまり「今日」)の祝日判定を行うことが可能です。

\jaholidayname{\year}{\month}{\day}

本日(2019年10月14日)は体育の日なので、上記により「体育の日」という文字列が得られます3

来週は改元に伴い特殊な祝日がありますが、BXjaholidayは対応済みです。

\jaholidayname{2019}{10}{22}%=>即位礼正殿の儀

なお、存在しない日付を表す数値を指定した場合の動作は未定義です(ほかの命令についても同様)。またBXjaholidayが扱う「祝日」は、1948年7月20日公布の国民の祝日に関する法律(通称・祝日法)により規定されるものを言います。したがって、1948年7月20日より前の日付はすべて非祝日扱い(すなわち\jaholidaynameの展開結果は空文字列)となります。

曜日名

ハッピーマンデー制度の存在のため、日本の祝日を判定するためには曜日判定の実装が必要です。そのため、BXjaholidayは副産物として曜日判定を行う\jadayofweek命令も提供します。

\jadayofweek{<year>}{<month>}{<day>}

使い方は\jaholidaynameとまったく同様です。この命令は、指定した日付の曜日を表す漢字1字に展開されます4

\jadayofweek{2019}{1}{1}%=>火

ちなみに奥村先生の開発されたokumacroパッケージの\曜コマンドを用いても、実行日(つまり「今日」)の曜日を得ることができます。両者の内部的なロジックにはまったく違いがありません。\曜コマンドとの違いは、書式(容易に好きな日付を指定できる)と\caption中などLaTeXの「動く引数」内でも使用できるという点ぐらいです。

祝日判定

\IfJaHolidayTFコマンドを用いると、指定した日付が祝日であるか否かによって条件分岐を行うことができます。

\IfJaHolidayTF{<year>}{<month>}{<day>}{<true code>}{<false code>}

具体的な使用例を示すと、次のようになります:

\IfJaHolidayTF{2019}{1}{1}{祝日}{非祝日}%=>祝日
\IfJaHolidayTF{2019}{1}{2}{祝日}{非祝日}%=>非祝日

用途としては「2019年1月1日(火・祝)」のように日付表示したい際などを想定しています。

\newcommand{\mydate}[3]{%
  #1年#2月#3日%
  \IfHolidayPriceTF{#1}{#2}{#3}
    {(\jadayofweek{#1}{#2}{#3}・祝)}
    {(\jadayofweek{#1}{#2}{#3})}}

\mydate{2019}{1}{1}%=>2019年1月1日(火・祝)
\mydate{2019}{1}{2}%=>2019年1月2日(水)

\IfJaHolidayTFには祝日判定が真の場合、あるいは偽の場合の分岐のみを記述するバージョンも用意されています5

\IfJaHolidayT{<year>}{<month>}{<day>}{<true code>}
\IfJaHolidayF{<year>}{<month>}{<day>}{<false code>}

expl3インターフェースを利用した応用

祝日や曜日の判定を伴うより複雑な処理を行う場合のために、BXjaholidayはさらに多機能なexpl3インターフェース(bxjhモジュール)を提供しています6。利用可能なexpl3インターフェースの網羅的な説明についてはパッケージ文書(bxjaholiday.pdf)を参照してください7。ここでは、expl3インターフェースを利用した応用の一例を紹介します。

応用例:休日料金の判定

カラオケ店や宿泊施設などでは、需要の関係から休日(週末・祝日)およびその前日(金曜・祝前日)に休日料金が適用される場合があります。ここでは、指定した日付がこの「休日料金の適用日」に該当するか否かを判定するexpl3関数\my_if_holiday_price:nnnTFを定義してみましょう。

\my_if_holiday_price:nnnTF {<year>} {<month>} {<day>}
  {<true code>} {<false code>}

expl3で条件分岐命令を定義する場合、\prg_new_conditional:Npnn関数を用いると便利です。雛形は次のようになります。

\prg_new_conditional:Npnn \my_if_holiday_price:nnn #1#2#3 { TF }
  {
    <何らかの条件分岐関数>:TF
      { \prg_return_true: }  % 休日料金
      { \prg_return_false: } % 平日料金
  }

\prg_new_conditional:Npnnの第1引数には定義したい\my_if_holiday_price:nnnTFのうちTF部分を含まない名前を指定することに注意してください。続いてやはりTF部分を除く引数についてのパラメタテキストを記述します。第3引数は、定義したい条件分岐命令のバリエーションをカンマ区切りで指定します。今回は\my_if_holiday_price:nnnTFのみを用意しますが、同時に\my_if_holiday_price:nnnT\my_if_holiday_price:nnnFも定義したい場合は{ TF, T, F }のように指定します。

4つ目の引数は定義本体で、ここに条件分岐のコードを記述していき、真の分岐(すなわち、定義した関数のT引数が実行されるべき条件のところ)には\prg_return_true:を、偽の分岐には\prg_return_false:を記述します。

さて休日料金判定に話を戻しますが、まず祝日とは無関係に金・土・日は祝日料金となります。「曜日を表す漢字1字」に展開される\jadayofweekのexpl3関数版\bxjh_day_of_week_name:nnnもありますが、条件分岐に使う場合は「曜日を表す内部数値」に展開される\bxjh_day_of_week:nnnを利用した方が便利です。BXjaholidayで曜日を表す内部数値は次のように定義されています。

曜日 内部数値 expl3の定数
0 \c_bxjh_monday_int
1 \c_bxjh_tuesday_int
2 \c_bxjh_wednesday_int
3 \c_bxjh_thursday_int
4 \c_bxjh_friday_int
5 \c_bxjh_saturday_int
6 \c_bxjh_sunday_int

したがって、金・土・日を判定するためには\bxjh_day_of_week:nnnで得られた数値がc_bxjh_thursday_intよりも大きいかどうかで判定するのが簡単です。

\prg_new_conditional:Npnn \my_if_holiday_price:nnn #1#2#3 { TF }
  {
    \int_compare:nNnTF
      { \bxjh_day_of_week:nnn {#1} {#2} {#3} } > { \c_bxjh_thursday_int }
      { \prg_return_true: }  % 金・土・日
      {
        % TODO: 月〜木は祝日の存在を考慮
      }
  }

続いて月〜木を考えます。月〜木はほとんどの場合平日料金が適用されますが、祝日および祝前日は休日料金となります。祝日の判定は\IfJaHolidayTFのexpl3関数版\bxjh_if_holiday:nnnTFを用いて簡単です。

\bxjh_if_holiday:nnnTF {#1} {#2} {#3}
  { \prg_return_true: }  % 祝日
  {
    % TODO: 祝前日を判定
  }

鬼門は祝前日の判定ですが、これには\bxjh_apply_next_day:Nnnn関数が便利です。この関数の書式はちょっとクセがあるのですが、次のようになっています:

\bxjh_apply_next_day:Nnnn <function> {<year>} {<month>} {<day>}

ここで<function>は日付を{<year>}{<month>}{<day>}の形で取る任意の関数です。例えば\bxjh_day_of_week:nnn\bxjh_if_holiday:nnnTFは該当します。\bxjh_apply_next_day:Nnnnを用いると、第1引数に指定した関数を、第2〜第3引数で指定した日付の「翌日」に適用することができます。つまり、次のように記述することで指定した日付の「翌日」が祝日かどうかを判定することができます。

\bxjh_apply_next_day:Nnnn \bxjh_if_holiday:nnnTF {#1} {#2} {#3}
  { \prg_return_true: }  % 祝前日
  { \prg_return_false: }  % 平日

ここまでのコードを1つにまとめれば、求めていた関数の定義になります。

\prg_new_conditional:Npnn \my_if_holiday_price:nnn #1#2#3 { TF }
  {
    \int_compare:nNnTF
      { \bxjh_day_of_week:nnn {#1} {#2} {#3} } > { \c_bxjh_thursday_int }
      { \prg_return_true: }  % 金・土・日
      {
        \bxjh_if_holiday:nnnTF {#1} {#2} {#3}
          { \prg_return_true: }  % 祝日
          {
            \bxjh_apply_next_day:Nnnn \bxjh_if_holiday:nnnTF {#1} {#2} {#3}
              { \prg_return_true: }  % 祝前日
              { \prg_return_false: }  % 平日
          }
      }
  }

まとめ

TeXでカレンダーを作る際や請求書・納品書等々の自動生成を行う際は、ぜひBXjaholidayを活用してみてください!


主な更新履歴

  • 2025-12-07: スタイルの更新

  1. 要するにexpl3がサポート対象とするエンジンすべてです。expl3がe-TeX拡張を要求するため、e-TeX拡張は必須です。 ↩︎

  2. TeX言語者向けの情報:\jaholidaynameは先頭完全展開可能です。 ↩︎

  3. ちなみにですが「体育の日」という名前の祝日は今年を最後に姿を消す予定です。以降は「スポーツの日」という名称になるそうです。さらに来年限定でスポーツの日は東京オリンピック開会式の行われる7月24日に移動されるらしいです。ちょっと意味がわかりませんがBXjaholidayはこのイレギュラーにも対応しています。 ↩︎

  4. TeX言語者向けの情報:\jadayofweek も先頭完全展開可能です。 ↩︎

  5. TeX言語者向けの情報:\IfJaHolidayTFは先頭完全展開可能です。\IfJaHolidayTも先頭完全展開可能です。\IfJaHolidayFも先頭完全展開可(ry ↩︎

  6. TeX言語者向けの情報:BXjaholidayの提供するすべてのexpl3関数は先頭完全展開可能です。 ↩︎

  7. 残念ながら、BXjaholidayのパッケージ文書は現状英語版しかありません。なぜならl3docクラスを日本語対応するのが面倒だからです(えっ) ↩︎