JavaScriptで日本の祝日を扱うライブラリ5選

# はじめに
JavaScriptで祝日判定をしたかったんです。
きっといい感じのライブラリがあるはずだと思ってググっても、
上位には自力でゴリゴリ実装する方法ばかり出てきちゃうんですよねー。。

色々と試行錯誤して検索したら見つかったんですが、
もっと見つかりやすくなるように、Qiitaにオススメをまとめておきますね。

# TL;DR

* 日本の祝日だけ扱うなら [holiday_jp-js](https://github.com/holiday-jp/holiday_jp-js)
* 日本の祝日だけ扱って軽量化に拘るなら [japanese-holidays-js](https://github.com/osamutake/japanese-holidays-js)
* 世界中の祝日を扱うなら [date-holidays](https://github.com/commenthol/date-holidays)

がお勧め！

# 見つけたライブラリ5選
## 1. holiday_jp-js
https://github.com/holiday-jp/holiday_jp-js

[Rubyの定番Gem](https://github.com/holiday-jp/holiday_jp-ruby)のJavaScript移植版です。


```html
<script src="./your/own/path/holiday_jp.js"></script>
<script>
var holidays = holiday_jp.between(new Date('2010-09-14'), new Date('2010-09-21'));
console.log(holidays[0]['name']); // 敬老の日
</script>
```

```js
var holiday_jp = require('@holiday-jp/holiday_jp');
var holidays = holiday_jp.between(new Date('2010-09-14'), new Date('2010-09-21'));
console.log(holidays[0]['name']); // 敬老の日
```

ブラウザでもそのまんま使えるし、Node.jsでも使えます。
ここのファイルをダウンロードすればすぐ使えます。
https://github.com/holiday-jp/holiday_jp-js/tree/master/release

もちろんwebpackでビルドしてやることも可能！
日本限定のシステムのときは、これがイチオシかな。

作者さんのブログ
[holiday_jp(Ruby gem) のPHP版、JavaScript版を作りました](https://k1low.hatenablog.com/entry/2014/11/23/230327)

## 2. node-holiday-jp
https://github.com/hitsujiwool/node-holiday-jp

Node.jsのライブラリとしてシンプルにまとまってる。

```js
var holiday = require('holiday-jp')

// find holidays between 3/6/2014 ~ 30/9/2014
// returns Array of Object (see below for their properties)
holiday.between(new Date(2014, 5, 3), new Date(2014, 8, 30))

// whether given date is holiday or not
// return true (or false)
holiday.isHoliday(new Date(2014, 10, 3))
```

`(Node.jsで使う || webpackでビルドしてWebで使う) && 日本限定`なら良さそう。
ブラウザでそのまんま使うことはできません。

しかしこのライブラリ、あまりメンテされていないようで、最終コミットが2016年。
2019年のゴールデンウィークは10連休になってませんでした。
https://github.com/hitsujiwool/node-holiday-jp/blob/b214a63dea01ec0dc94c1e4f6b55ad3cef345443/holidays.json#L762-L766

今後も祝日増えたりすることはありそうなので、
あんまりお勧めできないかも・・・

## 3. date-holidays
https://github.com/commenthol/date-holidays

これ凄いっすね・・・世界各国の祝日に対応。

```js
var Holidays = require('date-holidays')
var hd = new Holidays()

// get supported countries
hd.getCountries()
/*>
{ AD: 'Andorra',
  ...
  US: 'United States' }
*/

// get supported states e.g. for US
hd.getStates('US')
/*>
{ al: 'Alabama',
  ...
  wy: 'Wyoming' }
*/

// get supported regions e.g. for US, Lousiana
hd.getRegions('US', 'la')
/*>
{ no: 'New Orleans' }
*/

// initialize holidays for US, Lousiana, New Orleans
hd.init('US', 'la', 'no')
// or using a new instance
hd = new Holidays('US', 'la', 'no')

// get all holidays for the year 2016
hd.getHolidays(2016)
/*>
[ { date: '2016-01-01 00:00:00',
    start: Fri Jan 01 2016 00:00:00 GMT-0600 (CST),
    end: Sat Jan 02 2016 00:00:00 GMT-0600 (CST),
    name: 'New Year\'s Day',
    type: 'public' },
  ...
  { date: '2016-11-24 00:00:00',
    start: Thu Nov 24 2016 00:00:00 GMT-0600 (CST),
    end: Fri Nov 25 2016 00:00:00 GMT-0600 (CST),
    name: 'Thanksgiving Day',
    type: 'public' },
  ...
  { date: '2016-12-26 00:00:00',
    start: Mon Dec 26 2016 00:00:00 GMT-0600 (CST),
    end: Tue Dec 27 2016 00:00:00 GMT-0600 (CST),
    substitute: true,
    name: 'Christmas Day (substitute day)',
    type: 'public' } ]
*/

// check if date is a holiday while respecting timezones
hd.isHoliday(new Date('2016-02-09 00:00:00 GMT+0000'))
//> false
hd.isHoliday(new Date('2016-02-09 10:00:00 GMT-0600'))
/*>
{ date: '2016-02-09 00:00:00',
  start: Tue Feb 09 2016 00:00:00 GMT-0600 (CST),
  end: Wed Feb 10 2016 00:00:00 GMT-0600 (CST),
  name: 'Mardi Gras',
  type: 'public' }
*/
```

各国の祝日を1つのシステムで扱いたいときはとても良さそうです。
でも日本での利用しか想定しない場合は、オーバースペックかな。

参考記事
[date-holidays という祝日ライブラリが良い意味で狂っていた](https://hnw.hatenablog.com/entry/2019/04/13/212054)

## 4. japanese-holidays-js
https://github.com/osamutake/japanese-holidays-js

「日本の祝日専用ライブラリ」って意味で、
ユーザーから見たコンセプトは[holiday_jp-js](https://github.com/holiday-jp/holiday_jp-js)に近いです。
ブラウザとNode.js両対応って点も同じ。メンテナンスもしっかりされてます。

```js
var JapaneseHolidays = require('japanese-holidays');

var today = new Date();
var holiday = JapaneseHolidays.isHoliday(today);
if(holiday) {
    console.log("今日は " + holiday + " です");
} else {
    console.log("今日は祝日ではありません");
}
```

```html
<script src="https://cdn.rawgit.com/osamutake/japanese-holidays-js/v1.0.6/lib/japanese-holidays.min.js"></script>
<script>
var today = new Date();
var holiday = JapaneseHolidays.isHoliday(today);
if(holiday) {
    alert("今日は " + holiday + " です");
} else {
    alert("今日は祝日ではありません");
}
</script>
```


しかし、ライブラリの内部仕様はかなりコンセプトが違うので、そこをどう考えるかが選定ポイント。

### 祝日を判定する内部仕様比較

このjapanese-holidays-jsは、かなりロジカルに「祝日を計算」しています。
https://github.com/osamutake/japanese-holidays-js/blob/master/src/japanese-holidays.coffee

一方最初に挙げたholiday_jp-jsは、依存ライブラリで定義されたYAMLファイルに
全祝日がベタ書きされています。
https://github.com/holiday-jp/holiday_jp/blob/master/holidays.yml

これをどう考えるかですが、僕は後者の「ベタ書き」の方が安全に使えると思っていて、
holiday_jp-jsの方をお勧めします。

根拠はこの記事に詳しく書いてあるので、読んでみてください。僕もこの考えに賛同します。
[1分でできるJavaScriptで国民の祝日を判定する方法](https://iwb.jp/javascript-new-date-is-holiday-check/)
> 「JavaScript 祝日 判定」などで検索すると8月11日を山の日などと判定させるやり方を紹介しているサイトがあるが、祝日は毎年同じ月日とは限らないため、問題を起こす可能性が高いやり方を使用してはならない。

### ライブラリの容量の問題

ロジカルに計算する大きなメリットもあります。
それは「ライブラリが軽量化されること」ですね。
特にクライアントサイドに仕込むJSは極力容量を減らしたいですよね。


試しに、`holiday_jp-js`, `japanese-holidays-js`, `date-holidays`の3種類で
webpackのproductionビルドをして比較してみました。
（実案件のコードで実験したのでコードの詳細は割愛・・・）

|条件|容量|
|---|---|
|日付計算を仕込む前|506KB|
|japanese-holidays-jsで日付計算|510KB|
|holiday_jp-jsで日付計算|731KB|
|date-holidaysで日付計算|2.2MB (笑)|

もともとそれなりに重い処理があって506KBだったので、
holiday_jp-jsを適用して+200KBは重めだなーと思いました。
japanese-holidays-jsは+4KBなので、超優秀ですね！
なので軽量化に拘るなら、japanese-holidays-jsを選べば良いと思います。

まぁdate-holidaysの増量が凄まじいので、
このオーダーと比較すると誤差レベルかもしれませんがw


## 5. UltraDate.js
https://hrdaya.github.io/UltraDate.js/

これは元々、JSの`Date`オブジェクトをより使いやすくしたライブラリです。
作者が日本人で、その拡張機能として和暦や日本の祝日を扱う機能も提供されてます。

ブラウザ専用で、Node.jsでの利用は想定されていないっぽい。
webpackで使えないこともないですが、
その場合は[exports-loader](https://webpack.js.org/loaders/exports-loader/)使ったり一工夫が必要です。

```js
var checkDate = function(date){
    var str = date.format("yyyy年MM月dd日");
    if (date.isHoliday()) {
        str += "は祝祭日です";
    } else {
        str += "は祝祭日ではありません";
    }
    return str;
};
 
// 今日が祝祭日かどうかを確認する
var date = new UltraDate();
console.log(checkDate(date));
 
// 2015年11月23日が祝祭日かどうかを確認する
date.setFullYear(2015, 10, 23);
console.log(checkDate(date));
```

[サイボウズのCDN](https://developer.cybozu.io/hc/ja/articles/202960194-Cybozu-CDN)に載ってる関係で、kintone界隈では人気みたいです。
僕もkintone始めたばかりの頃は使ってました。
B'zばりに「ウルトラデイト！ハイッ！！！」と叫びたくなるライブラリ名は好きです。

でもwebpackからスムーズに使えないし、
2019-05-16時点で[このIssue](https://github.com/hrdaya/UltraDate.js/issues/75)がOpenのままで、あんまり活発にメンテされてる感じがありません。
実用的には、あんまりお勧めできないですねー。。

# 結論

* 日本の祝日だけ扱うなら [holiday_jp-js](https://github.com/holiday-jp/holiday_jp-js)
* 日本の祝日だけ扱って軽量化に拘るなら [japanese-holidays-js](https://github.com/osamutake/japanese-holidays-js)
* 世界中の祝日を扱うなら [date-holidays](https://github.com/commenthol/date-holidays)

がお勧めな理由、分かっていただけたでしょうか！

ではまた！