悩んだ休日判定
Pythonではjpholiday
などのライブラリがあり、簡単に祝日判定を返してくれる。
土日はweekday
のナンバーで、祝日判定はライブラリに頼れるとして、じゃあ、ゴールデンウイーク前後で会社が休み、年末年始など祝日じゃないけど世間的に休みの時は??
いつ休みにするか、関係各所との調整でぎりぎりに決まるなんてことは珍しくないし。。。
毎年々々、その都度確認&コード修正なんて面倒くさい
- ディベロパーが手作業で対応するなんてナンセンス。
- 休日追加してコード動かないようにする、休日だけど任意のタイミングで上層部はほしい(レポーティングを吐き出すスクリプトなど)、なんて事務員さんや本人たちにやってもらいたい。
- そもそももう放っておくモードのコード触りたくない
と怠け者の俺は思った。
そしてなんとか考えた結果、この方法にたどり着いた。
結論
①スプレッドシートの=workday()
で営業日を算出
②スクリプトの稼働はカレンダー予定の開始日時にすることで追加/削除を簡易的にする
③特別な休日の追加はGoogleフォームで事務員さんにやってもらう
解説
スプシの何がいいかというと、
- 日付が変わると
=today()
を勝手に再計算してくれる(エクセルでは一回開いて上書き保存が必要)。これがファンダメンタル。これは深夜0:00amにこの目で確認した。 - GASがあるので、内閣府の祝日データを定期的に読み込むスクリプトをサクッと作れる。
- 祝日データと、人手で追加するデータの合算があれば、それで社内的な休日が割り出せる。
(本記事で触れる内容はここまで)
さらに、IFTTT(5 appletまで無料)のIF(トリガー)にはカレンダーイベントの作成や開始時、That(アクション)にはWebhookポストがあるので、これを混ぜてGoogleカレンダーをジョブスケジューラ化できる。
Googleカレンダーのジョブスケジューラ化とはつまり、Googleカレンダーイベントの追加や削除、時間移動で、プログラムの稼働タイミングをコントロールできるということ。
急な休みでプログラムをオフしたり、追加したりがこれで自在になる。稼働スケジュールの可視化にもなる。
(ここら辺は次回記事)
これらを使って、以下の施策を施した。
セットアップ
① GASで定期的に内閣府のHPの公開CSVから祝日データを取得
※天皇陛下の代替わりで一年に一回では祝日が必ずしも確定していないことを味わったので、月一回くらいの頻度でこのスクリプトをトリガーさせるようにした。
const url = 'https://www8.cao.go.jp/chosei/shukujitsu/syukujitsu.csv';
const sheetName ='HolidayDataFromGovernment'
const sheet = SpreadsheetApp.getActive().getSheetByName(sheetName);
function getHolidays() {
let text = UrlFetchApp.fetch(url).getBlob().getDataAsString("Shift_JIS");
let csv = Utilities.parseCsv(text);
// はりつけ前にクリア
sheet.clearContents()
// はりつける
sheet.getRange(1, 1, csv.length, csv[0].length).setValues(csv);
}
シート名はHolidayDataFromGovernment
。
② 手入力で休日を入れられるシートを用意。
③ そこに日付を追加するフォームを社内に共有。
Googleフォームでよし。ネイティブにフォームとスプシを連携させてもよし。フォームにコンテナバインドのスクリプトを追加して、onSubmit
で稼働させて日付を追加するのもよし。
みんなにシートを公開してしまうと、誤っての削除、日付フォーマットの乱れなどあるかもしれないので手入力は許さない。
まあそこまでしなくとも、保護などかけつつ限定共有するでもいいかもしれない、
④ HolidayDataFromGovernment
とmanual Input
を合算したシートを用意
大分前なのでどこを参考にしたのか忘れてしまったし関数の詳細は自分でも忘れてしまったが、=filter()
を使ってHolidayDataFromGovernment
の空欄じゃない、ついでに今より12か月前以後のものというフィルターをかけたものと、とmanual Input
の空欄じゃないものを配列を構成できる{;}
を使って合算してAggregated
というシートのA2
以下に持ってきている。
={FILTER(INDIRECT("'HolidayDataFromGovernment'!A2:A"&Match(1,ArrayFormula(1/(HolidayDataFromGovernment!A2:A<>"")),1)),INDIRECT("'HolidayDataFromGovernment'!A2:A"&Match(1,ArrayFormula(1/(HolidayDataFromGovernment!A2:A<>"")),1))>EDATE(TODAY(),-12));INDIRECT("'manual input'!A1:A"&Match(1,ArrayFormula(1/('manual Input'!A1:A<>"")),1))}
これで=WORKDAY(開始日, 日数, [休日])
の休日参照元ができあがった。
必要な判定はGoogleシートにやらせておく
「今日が営業日か?」
という判定は、
workdayで算出する 明日-1営業日
がtoday()
と一緒かのBooleanでできる。
※INDIRECT("Aggregated!A2:A"&COUNTA(Aggregated!A:A))
とすることで最終行までを動的に参照。単純にAggregated!A2:A
でもいいかも。
=WORKDAY(TODAY()+1,-1,INDIRECT("Aggregated!A2:A"&COUNTA(Aggregated!A:A)))=TODAY()
これでプログラム起動時に単一セルのBooleanを読むだけで今日が営業日か判明する。
FALSEの場合にexitというガードステートメントをコードに書いておけば、もうここまででもOK。
ただし、ここまでだと休日の追加は簡単にできても、稼働タイミングの追加はできない。
次回記事で、 このスプシを使って社内の特定の営業日を算出するやり方や、スプシで算出された日付を元に予定を作ることと、IFTTTを使うことで、Googleカレンダーをスクリプト実行するスケジューラーにする方法を紹介する内容を執筆予定。
スプシを頻繁に読み込むとエラーになるのが怖い、という場合もあるかもしれないし。
執筆したら次回記事のリンクをつけて記事更新&通知するので、気になる方はストックしてください。