ソフトウェア/javascript/japanese-holidays のバックアップの現在との差分(No.3)

更新


  • 追加された行はこの色です。
  • 削除された行はこの色です。
[[公開メモ]]

* 日本の休日を求めるための javascript ライブラリを npm と github へ公開しました [#y6d9a7a7]

祝日名が取れて、なおかつメンテナンスしやすい形の
ライブラリが見付からなかったので書いてみました。

一応、複数のライブラリと突き合わせて齟齬がないことを確認しましたが、
運用は個々の責任でお願いします。ミスがあれば教えてください。

法律改正などで休日が変更になっても、よほどのことがない限り definition 
のところをいじるだけで対応できるはずです。

もともとこのライブラリは 2013 年に書かれた物です。
2016年から 「山の日」 が新設されましたが、これに対するコードの追加は、

 LANG: javascript
    [ "山の日",                   simpleHoliday( 8, 11), 2016       ],

の一行だけで済みました。

ライセンスは MIT です。
煮るなり焼くなり好きにしてください。

- npm~
https://www.npmjs.com/package/japanese-holidays
- github~
https://github.com/osamutake/japanese-holidays-js

* 使い方 [#jfc77040]

npm を使うなら、

 LANG:console
 $ npm i japanese-holidays
 $ node
 > Holidays = require('japanese-holidays');
 > Holidays.getHolidaysOf(2016);
 [ { month: 1, date: 1, name: '元日' },
   { month: 1, date: 11, name: '成人の日' },
   { month: 2, date: 11, name: '建国記念の日' },
   { month: 3, date: 20, name: '春分の日' },
   { month: 3, date: 21, name: '振替休日' },
   { month: 4, date: 29, name: '昭和の日' },
   { month: 5, date: 3, name: '憲法記念日' },
   { month: 5, date: 4, name: 'みどりの日' },
   { month: 5, date: 5, name: 'こどもの日' },
   { month: 7, date: 18, name: '海の日' },
   { month: 8, date: 11, name: '山の日' },
   { month: 9, date: 19, name: '敬老の日' },
   { month: 9, date: 22, name: '秋分の日' },
   { month: 10, date: 10, name: '体育の日' },
   { month: 11, date: 3, name: '文化の日' },
   { month: 11, date: 23, name: '勤労感謝の日' },
   { month: 12, date: 23, name: '天皇誕生日' } ]
 > Holidays.isHoliday(new Date(2016,3-1,20));
 '春分の日'
 > Holidays.isHoliday(new Date(2016,3-1,21));
 '振替休日'

npm を使わないなら、~
 https://rawgit.com/osamutake/japanese-holidays-js/master/lib/japanese-holidays.js ~
 https://cdn.rawgit.com/osamutake/japanese-holidays-js/v1.0.6/lib/japanese-holidays.js ~
を読み込めば JapaneseHolidays に必要な関数が入ってきます。

 LANG:javascript
 <script src="https://rawgit.com/osamutake/japanese-holidays-js/master/lib/japanese-holidays.js"></script>
 <script src="https://cdn.rawgit.com/osamutake/japanese-holidays-js/v1.0.6/lib/japanese-holidays.js"></script>
 <script>
   alert( JapaneseHolidays.isHoliday(new Date(2016,3-1,20)) );
 </script>

さらにちゃんとした例をこちらに置きました。

  http://jsbin.com/qicazaroxu/edit?js,output
 http://jsbin.com/qicazaroxu/edit?js,output

リンク先では上記ライブラリを使って休日入りのカレンダーを表示しています。

休日の上にマウスカーソルを置くと、休日名がツールチップとして表示されるはずです。~
(下はスクリーンキャプチャーですので表示されている休日名は変化しません)

&ref(calendar.png,nolink);

* タイムゾーンに注意が必要 [#e7bb3da8]
* タイムゾーンについて [#e7bb3da8]

JapaneseHolidays.isHoliday に与える Date 型の値を作成する際には、
タイムゾーンについてよく考える必要があります。
JapaneseHolidays.isHoliday は与えられた「時刻」ではなく「日付」を元に祝日を判定します。 例えばニュージーランドで

 LANG:javascript
 JapaneseHolidays.isHoliday(new Date()); 
 JapaneseHolidays.isHoliday(new Date(2016,3-1,8)); 

例えばこのコードは一見、「今日」が祝日かどうかを判断しているように読めますが、
実際に判断しているのは「今」が祝日かどうか、です。
とすると、ニュージーランド時間の 2016-03-08 00:00:00 が関数に渡されます。 これは日本時間では 2016-03-07 21:00:00 を表しますが、 isHoliday は与えられた日付 3/8 が休日かどうかを判定するということです。

というのも、このコードが例えばアメリカで実行されたとすると、その時点で
アメリカが例えば8日だったとしても、日本はすでに9日かもしれなくて、
isHoliday は実際には今日でなく明日が祝日かどうかを判断してしまうかも
しれないのです。
多くの場合これは利用者の意図するところだと思います。

同様に、ニュージーランドで
万一、与えた「時刻」において日本で休日かどうかを判定する必要があれば、

 LANG:javascript
 JapaneseHolidays.isHoliday(new Date(2016,3,8)); 
 JapaneseHolidays.isHolidayAt(new Date(2016,3-1,8)); 

を実行してしまうと、これはニュージーランド時間で 2016-03-08 00:00:00 
を表しますから、このとき日本では 2016-03-07 21:00:00 でして、
意図せず前日を判定してしまいます。
を呼んでください。例えばニュージーランドでこれを呼べば、3/7 が休日かどうかが判定されます。

ですので、もしあなたが 2016/03/08 が祝日かどうかを判別したければ、
日時を日本のタイムゾーン居合わせて指定しなければなりません。例えば
* 2019年の改元に対応するためアップデート (v1.0.7) [#re56aa85]

 LANG:javascript
 JapaneseHolidays.isHoliday(new Date(Date.UTC(2016,3,8,-9))); 
普段やり慣れないことで手順を思い出す(調べる)のにとても苦労したためメモしておく。

のように書けばいいわけです。ちょっと分かりづらかったら試してみれば、
+ GitHub でプルリクエストをマージした
+ ローカルに git clone した
+ npm install した
+ 必要部分を修正して make test が通るようにした
+ package.json のバージョン番号を 1.0.7 にした
+ README.md のバージョン番号相当部分を 1.0.7 にした
+ git push した
+ GitHub でリリースを作成した
+ npm adduser でログイン情報を登録した
+ npm publish した

 $ node
 > new Date(Date.UTC(2016,3,8,-9))
 Fri Apr 08 2016 00:00:00 GMT+0900 (JST)
* 2021年のオリンピック対応に対応するためアップデート (v1.0.10) [#d52f7e1a]

のように、正しく動作はすることを確かめられます。とはいえ、
これでは非常に読みづらいので、
JapaneseHolidays は jDate という関数を提供しています。
普段やり慣れないことで手順を思い出す(調べる)のにとても苦労したためメモしておく。
っていうか、上記のメモを見つけられずまたもや車輪を再発明してしまった orz

 LANG:javascript
 JapaneseHolidays.isHoliday(JapaneseHolidays.jDate(2016,3,8))); 
+ GitHub でプルリクエストをマージした
+ ローカルに git clone した
+ npm install した
+ 必要部分を修正して make test が通ることを確認した
+ package.json のバージョン番号を 1.0.10 にした
+ README.md のバージョン番号相当部分を 1.0.10 にした
+ README.md の Change Log を更新しそこなった(どうやって直したらいいか分かってない...)
+ git commit -a -m "prepare for v1.0.10" した
+ git push した
+ GitHub でリリースを作成し、その際にタグをつけた
+ npm adduser でログイン情報を登録した
+ npm publish ./ した

これは、上と同じ動作をします。
更新が遅くなってしまい多方面にご迷惑をおかけいたしました。

逆に、ある Date オブジェクトが日本時間で何日の何時何分を
表しているか読み取るため、getJ??? という形式の一連の
関数も提供しています。
大変申し訳ありません。

 LANG:javascript
 var date = new Date();
 var jyear    = JapaneseHolidays.getJFullYear(date);
 var jmonth   = JapaneseHolidays.getJMonth(date);
 var jdate    = JapaneseHolidays.getJDate(date);
 var jday     = JapaneseHolidays.getJDay(date);
 var jhours   = JapaneseHolidays.getJHours(date);
 var jminutes = JapaneseHolidays.getJMinutes(date);
*** 分かっていないこと: [#o9ba777e]

あともう一つ便利なユーティリティ関数として、
JapaneseHolidays.shiftDate があります。
この関数は与えられた Date を与えられた期間分だけ変化させた
値を計算して返します。期間には負の値も入れられます。
- npm install で coffee-script に deprecated が出るのだけれど、どう直すのが影響が少ないかわからない
- package-lock.json を .gitignore に入れてしまっていいものか判断できない
- 一旦リリースしてミスがあったら再リリースしなければならないんだろうなあ、やっぱり orz

 LANG:javascript
 // 1年前
 console.log(JapaneseHolidays.shiftDate(new Date(), -1));
 // 1ヶ月後
 console.log(JapaneseHolidays.shiftDate(new Date(), 0, 1));
 // 15ヶ月後
 console.log(JapaneseHolidays.shiftDate(new Date(), 0, 15));
 // 明日
 console.log(JapaneseHolidays.shiftDate(new Date(), 0, 0, 1));
 // 100 時間後
 console.log(JapaneseHolidays.shiftDate(new Date(), 0, 0, 0, 100));
* 春分・秋分の計算について(メモ) [#g553f029]

これらのユーティリティ関数の有効な使い方については、
例えば上でも紹介した jsbin のカレンダーの例をご参照ください。
現在のコードでは、

 http://jsbin.com/qicazaroxu/edit?js,output
> 春分・秋分の日は年によって日付が異なります。
> 
> この理由は、暦の上での1年の長さが閏年分だけ等間隔にならないため、 本来ほぼ正確に等間隔でやってくる春分・秋分の日付がカレンダー上でずれてしまうためです。 とはいえ、春分・秋分の間隔も完全に等間隔ではなく、毎年少しずつ揺れ動くようです。
> 
> Wikipedia の 春分 ・ 秋分 のページに 1600年~2399年 のデータがあって、そこから周期を求めることで、 春分についてはすべての範囲で計算と実測とが一致しました。秋分については ふらつきが大きいようで、計算だけではどうしても一致しなかったため、 いくつかの値についてのみ個別に指定しています。
> 
> 結果として、1600年~2399年 の範囲で上記 Wikipedia のページにあった日付を 再現できています。

** やっぱりおかしい [#u3ebe405]
としているのだけれど、

結果がタイムゾーンによらないように、今、ではなく、今日、
の判定をするように変更すべきだと思えてきました。
Wikipedia にある太陽年のページの数式と、TAIとUTCの変換ライブラリとを使うとすべて単純計算できるのか、それ以外に揺らぎがあるのか、後で試してみたくなりました。

https://ja.wikipedia.org/wiki/%E5%A4%AA%E9%99%BD%E5%B9%B4

https://fukuno.jig.jp/3430

** その後 [#n968d0aa]

https://eco.mtk.nao.ac.jp/koyomi/wiki/B5A8C0E12FB5A8C0E1A4CEA4E1A4B0A4EAA4CEBCFEB4FC2FC6F3BBEAC6F3CAAC.html



https://eco.mtk.nao.ac.jp/koyomi/wiki/B5A8C0E12FC6F3BDBDBBCDC0E1B5A4A4CECAD1C6B0A4CFA4ABA4CAA4EACAA3BBA8.html#o06ebe78

によれば春分・秋分は数分単位で見ると等間隔ではなく、いろんなものの影響を受けるので
単純な数式で計算するのは難しいっぽいですね・・・



* コメント・質問・バグ報告 [#af0a004f]

できれば github の方へお願いします。日本語で結構です。~
https://github.com/osamutake/japanese-holidays-js/issues

よく分からなければここでも構いません。

#article_kcaptcha


Counter: 7741 (from 2010/06/03), today: 1, yesterday: 0