プリザンターのカレンダーで祝日表示をする方法

:::note info
本記事はプリザンターの標準カレンダーで使用可能です。FullCalendarには現状では対応していません。
:::

## はじめに
プリザンターのカレンダー、祝日や土日のスタイル表示がなくて不便と思ったことはないですか？
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3555395/10542e4c-86c1-6a28-bb9a-4810bab54a5e.png)
これ、実はCSSだけで簡単に祝日や土日の表示を加えることができます！

## 土日表示
手始めに土日へスタイルをあててみましょう！こんなCSSを用意します。
```css:CalendarStyle-Weekend.css
#CalendarBody #Grid tbody tr td:nth-child(6):not(.other-month){background-color:#add8e6;}
#CalendarBody #Grid tbody tr td:nth-child(7):not(.other-month){background-color:#ffc0cb;}
```
表の6列目・7列目の背景色を変更しているだけです。前月・来月の背景がグレーアウトされている部分に適用されると見栄えが良くないので、そこは否定して適用されないようにしています。プリザンターの本体の設定、General.jsonでFirstDayOfWeekを触っている場合[^1]は曜日の位置が変わっているので、数字の部分を適宜変更してください。

これを管理画面のスタイルにいれてみると、こんな表示になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3555395/c57fb32d-c531-d9ae-9c49-64666ee30446.png)
いい感じですね。

## 祝日表示
ここからが本番です。祝日を表示してみましょう。こんなCSSを用意します。
```css:CalendarStyle-Sample.css
#CalendarBody #Grid tbody tr td[data-id="2024/12/24"]:not(.other-month){background-color:#ffc0cb !important;}
#CalendarBody #Grid tbody tr td[data-id="2024/12/24"] div .day:after{content:"クリスマス";margin-left:5px;}
```
背景色の変更と、疑似要素で祝日を表示するためのラベルを設定しているだけです。data-idに日付要素が格納されているので、それを使って日付指定をしています。これを管理画面のスタイルでカレンダーに当ててみるとこんな感じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3555395/4dbe707c-68e5-db0f-0ff7-cbf60558040e.png)
いい感じですね。

では、これを祝日でやってみます。定番の内閣府の祝日一覧を参考に2024年と2025年の祝日分を作成するとこんな感じになります。
```css:CalendarStyle-Holiday2024.css
#CalendarBody #Grid tbody tr td[data-id="2024/1/1"]:not(.other-month){background-color:#ffc0cb !important;}
#CalendarBody #Grid tbody tr td[data-id="2024/1/1"] div .day:after{content:"元日";margin-left:5px;}
#CalendarBody #Grid tbody tr td[data-id="2024/1/8"]:not(.other-month){background-color:#ffc0cb !important;}
#CalendarBody #Grid tbody tr td[data-id="2024/1/8"] div .day:after{content:"成人の日";margin-left:5px;}
#CalendarBody #Grid tbody tr td[data-id="2024/2/11"]:not(.other-month){background-color:#ffc0cb !important;}
#CalendarBody #Grid tbody tr td[data-id="2024/2/11"] div .day:after{content:"建国記念の日";margin-left:5px;}
#CalendarBody #Grid tbody tr td[data-id="2024/2/12"]:not(.other-month){background-color:#ffc0cb !important;}
#CalendarBody #Grid tbody tr td[data-id="2024/2/12"] div .day:after{content:"休日";margin-left:5px;}
#CalendarBody #Grid tbody tr td[data-id="2024/2/23"]:not(.other-month){background-color:#ffc0cb !important;}
#CalendarBody #Grid tbody tr td[data-id="2024/2/23"] div .day:after{content:"天皇誕生日";margin-left:5px;}
#CalendarBody #Grid tbody tr td[data-id="2024/3/20"]:not(.other-month){background-color:#ffc0cb !important;}
#CalendarBody #Grid tbody tr td[data-id="2024/3/20"] div .day:after{content:"春分の日";margin-left:5px;}
#CalendarBody #Grid tbody tr td[data-id="2024/4/29"]:not(.other-month){background-color:#ffc0cb !important;}
#CalendarBody #Grid tbody tr td[data-id="2024/4/29"] div .day:after{content:"昭和の日";margin-left:5px;}
#CalendarBody #Grid tbody tr td[data-id="2024/5/3"]:not(.other-month){background-color:#ffc0cb !important;}
#CalendarBody #Grid tbody tr td[data-id="2024/5/3"] div .day:after{content:"憲法記念日";margin-left:5px;}
#CalendarBody #Grid tbody tr td[data-id="2024/5/4"]:not(.other-month){background-color:#ffc0cb !important;}
#CalendarBody #Grid tbody tr td[data-id="2024/5/4"] div .day:after{content:"みどりの日";margin-left:5px;}
#CalendarBody #Grid tbody tr td[data-id="2024/5/5"]:not(.other-month){background-color:#ffc0cb !important;}
#CalendarBody #Grid tbody tr td[data-id="2024/5/5"] div .day:after{content:"こどもの日";margin-left:5px;}
#CalendarBody #Grid tbody tr td[data-id="2024/5/6"]:not(.other-month){background-color:#ffc0cb !important;}
#CalendarBody #Grid tbody tr td[data-id="2024/5/6"] div .day:after{content:"休日";margin-left:5px;}
#CalendarBody #Grid tbody tr td[data-id="2024/7/15"]:not(.other-month){background-color:#ffc0cb !important;}
#CalendarBody #Grid tbody tr td[data-id="2024/7/15"] div .day:after{content:"海の日";margin-left:5px;}
#CalendarBody #Grid tbody tr td[data-id="2024/8/11"]:not(.other-month){background-color:#ffc0cb !important;}
#CalendarBody #Grid tbody tr td[data-id="2024/8/11"] div .day:after{content:"山の日";margin-left:5px;}
#CalendarBody #Grid tbody tr td[data-id="2024/8/12"]:not(.other-month){background-color:#ffc0cb !important;}
#CalendarBody #Grid tbody tr td[data-id="2024/8/12"] div .day:after{content:"休日";margin-left:5px;}
#CalendarBody #Grid tbody tr td[data-id="2024/9/16"]:not(.other-month){background-color:#ffc0cb !important;}
#CalendarBody #Grid tbody tr td[data-id="2024/9/16"] div .day:after{content:"敬老の日";margin-left:5px;}
#CalendarBody #Grid tbody tr td[data-id="2024/9/22"]:not(.other-month){background-color:#ffc0cb !important;}
#CalendarBody #Grid tbody tr td[data-id="2024/9/22"] div .day:after{content:"秋分の日";margin-left:5px;}
#CalendarBody #Grid tbody tr td[data-id="2024/9/23"]:not(.other-month){background-color:#ffc0cb !important;}
#CalendarBody #Grid tbody tr td[data-id="2024/9/23"] div .day:after{content:"休日";margin-left:5px;}
#CalendarBody #Grid tbody tr td[data-id="2024/10/14"]:not(.other-month){background-color:#ffc0cb !important;}
#CalendarBody #Grid tbody tr td[data-id="2024/10/14"] div .day:after{content:"スポーツの日";margin-left:5px;}
#CalendarBody #Grid tbody tr td[data-id="2024/11/3"]:not(.other-month){background-color:#ffc0cb !important;}
#CalendarBody #Grid tbody tr td[data-id="2024/11/3"] div .day:after{content:"文化の日";margin-left:5px;}
#CalendarBody #Grid tbody tr td[data-id="2024/11/4"]:not(.other-month){background-color:#ffc0cb !important;}
#CalendarBody #Grid tbody tr td[data-id="2024/11/4"] div .day:after{content:"休日";margin-left:5px;}
#CalendarBody #Grid tbody tr td[data-id="2024/11/23"]:not(.other-month){background-color:#ffc0cb !important;}
#CalendarBody #Grid tbody tr td[data-id="2024/11/23"] div .day:after{content:"勤労感謝の日";margin-left:5px;}
```
```css:CalendarStyle-Holiday2025.css
#CalendarBody #Grid tbody tr td[data-id="2025/1/1"]:not(.other-month){background-color:#ffc0cb !important;}
#CalendarBody #Grid tbody tr td[data-id="2025/1/1"] div .day:after{content:"元日";margin-left:5px;}
#CalendarBody #Grid tbody tr td[data-id="2025/1/13"]:not(.other-month){background-color:#ffc0cb !important;}
#CalendarBody #Grid tbody tr td[data-id="2025/1/13"] div .day:after{content:"成人の日";margin-left:5px;}
#CalendarBody #Grid tbody tr td[data-id="2025/2/11"]:not(.other-month){background-color:#ffc0cb !important;}
#CalendarBody #Grid tbody tr td[data-id="2025/2/11"] div .day:after{content:"建国記念の日";margin-left:5px;}
#CalendarBody #Grid tbody tr td[data-id="2025/2/23"]:not(.other-month){background-color:#ffc0cb !important;}
#CalendarBody #Grid tbody tr td[data-id="2025/2/23"] div .day:after{content:"天皇誕生日";margin-left:5px;}
#CalendarBody #Grid tbody tr td[data-id="2025/2/24"]:not(.other-month){background-color:#ffc0cb !important;}
#CalendarBody #Grid tbody tr td[data-id="2025/2/24"] div .day:after{content:"休日";margin-left:5px;}
#CalendarBody #Grid tbody tr td[data-id="2025/3/20"]:not(.other-month){background-color:#ffc0cb !important;}
#CalendarBody #Grid tbody tr td[data-id="2025/3/20"] div .day:after{content:"春分の日";margin-left:5px;}
#CalendarBody #Grid tbody tr td[data-id="2025/4/29"]:not(.other-month){background-color:#ffc0cb !important;}
#CalendarBody #Grid tbody tr td[data-id="2025/4/29"] div .day:after{content:"昭和の日";margin-left:5px;}
#CalendarBody #Grid tbody tr td[data-id="2025/5/3"]:not(.other-month){background-color:#ffc0cb !important;}
#CalendarBody #Grid tbody tr td[data-id="2025/5/3"] div .day:after{content:"憲法記念日";margin-left:5px;}
#CalendarBody #Grid tbody tr td[data-id="2025/5/4"]:not(.other-month){background-color:#ffc0cb !important;}
#CalendarBody #Grid tbody tr td[data-id="2025/5/4"] div .day:after{content:"みどりの日";margin-left:5px;}
#CalendarBody #Grid tbody tr td[data-id="2025/5/5"]:not(.other-month){background-color:#ffc0cb !important;}
#CalendarBody #Grid tbody tr td[data-id="2025/5/5"] div .day:after{content:"こどもの日";margin-left:5px;}
#CalendarBody #Grid tbody tr td[data-id="2025/5/6"]:not(.other-month){background-color:#ffc0cb !important;}
#CalendarBody #Grid tbody tr td[data-id="2025/5/6"] div .day:after{content:"休日";margin-left:5px;}
#CalendarBody #Grid tbody tr td[data-id="2025/7/21"]:not(.other-month){background-color:#ffc0cb !important;}
#CalendarBody #Grid tbody tr td[data-id="2025/7/21"] div .day:after{content:"海の日";margin-left:5px;}
#CalendarBody #Grid tbody tr td[data-id="2025/8/11"]:not(.other-month){background-color:#ffc0cb !important;}
#CalendarBody #Grid tbody tr td[data-id="2025/8/11"] div .day:after{content:"山の日";margin-left:5px;}
#CalendarBody #Grid tbody tr td[data-id="2025/9/15"]:not(.other-month){background-color:#ffc0cb !important;}
#CalendarBody #Grid tbody tr td[data-id="2025/9/15"] div .day:after{content:"敬老の日";margin-left:5px;}
#CalendarBody #Grid tbody tr td[data-id="2025/9/23"]:not(.other-month){background-color:#ffc0cb !important;}
#CalendarBody #Grid tbody tr td[data-id="2025/9/23"] div .day:after{content:"秋分の日";margin-left:5px;}
#CalendarBody #Grid tbody tr td[data-id="2025/10/13"]:not(.other-month){background-color:#ffc0cb !important;}
#CalendarBody #Grid tbody tr td[data-id="2025/10/13"] div .day:after{content:"スポーツの日";margin-left:5px;}
#CalendarBody #Grid tbody tr td[data-id="2025/11/3"]:not(.other-month){background-color:#ffc0cb !important;}
#CalendarBody #Grid tbody tr td[data-id="2025/11/3"] div .day:after{content:"文化の日";margin-left:5px;}
#CalendarBody #Grid tbody tr td[data-id="2025/11/23"]:not(.other-month){background-color:#ffc0cb !important;}
#CalendarBody #Grid tbody tr td[data-id="2025/11/23"] div .day:after{content:"勤労感謝の日";margin-left:5px;}
#CalendarBody #Grid tbody tr td[data-id="2025/11/24"]:not(.other-month){background-color:#ffc0cb !important;}
#CalendarBody #Grid tbody tr td[data-id="2025/11/24"] div .day:after{content:"休日";margin-left:5px;}
```
これをスタイルに入れてみると、こんな表示に。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3555395/66d0bf08-9dbb-cfab-8061-461a67c5334c.png)
いい感じですね。

## プログラム化してみた
このCSS、分量としては手動でもできるけど、出来れば自動化したい・・・という微妙なラインの量です。
Excel芸でもどうにか出来るのですが、せっかくなので1本プログラムを作ってみました。祝日のソースには定番の内閣府のCSVファイルを使用しています。
サイトごとに設定するもの面倒なので、拡張スタイルに格納して、全サイトに一括で適用します。

### レポジトリ
:::note warn
レポジトリが変更になっています。
https://github.com/pleasanter-developer-community/pleasanter-calendar-holiday-style-generator
:::

レポジトリはこちらになります。
https://github.com/vehiclevisionjp/VehicleVision.PleasanterTools.HolidayStyleGenerator

### 使い方
Windowsにインストールしている場合、[こちら](https://pleasanter.org/ja/manual/getting-started-pleasanter-windows)のマニュアルに従ってインストールされているとしたときの使用方法です。基本的に1.4系以降のバージョンがインストールされていることが前提ではありますが、.NET 8 Runtimeを追加でインストールすれば以前のバージョンでも使用することが可能です。**実行時に内閣府のサイトからファイルを取得してくるので、オフライン環境では実行出来ません**のでご注意ください。

上記のレポジトリから最新版のリリースからzipファイルを取得・解凍して`C:\web\pleasanter\HolidayStyleGenerator`に配置します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3555395/433fe354-540f-7e0c-3784-05dfa74140ce.png)
次にコマンドプロンプトを開いてコマンドを実行します。
```
cd C:\pleasanter\HolidayStyleGenerator
dotnet VehicleVision.PleasanterTools.HolidayStyleGenerator.dll
```
`C:\pleasanter\Implem.Pleasanter\App_Data\Parameters\ExtendedStyles\CalendarStyle`の中にCSSファイル群が生成されていることを確認します。生成されていれば完了です。必要に応じてプリザンターのプロセスの再起動などを実施してください。

### Azureで使用する方法
Azureで使用する場合は、[こちら](https://pleasanter.org/ja/manual/getting-started-pleasanter-azure)の手順5と同様に、siteフォルダにリリースからダウンロードしたzipファイルを解凍せずにアップロードしてください。
自動的に解凍され、`HolidayStyleGenerator`フォルダの中に実体が展開されます。
次に`HolidayStyleGenerator`に移動してコマンドを実行します。
```
dotnet VehicleVision.PleasanterTools.HolidayStyleGenerator.dll /p C:\home\site\wwwroot
```

### ディレクトリ構成が異なる場合
ジェネレータは相対バスで`Implem.Pleasanter`の場所を探して出力を行っています。`Implem.Pleasanter`と`HolidayStyleGenerator`が同階層に格納されいない場合は`/p`オプションを使用してプリザンター本体が格納されているパスを指定します。`Implem.CodeDefiner`と同じです。

[^1]:公式マニュアルだと「本パラメータは変更不可」となっているので変更してるケースはごく少数だとは思いますが・・・。

## まとめ
プリザンターのカレンダ－に祝日表示を追加することで、仕事の予定などを祝日に入れてしまう事故も軽減できるかと思います。今後はFullCalendarへの対応や、会社固有の休日を設定出来るようにするなどのプログラムの改修も予定します。気になる方はレポジトリの購読をお願いします。