最近Javascriptで土日祝日を飛ばして出荷日を自動表示する依頼があったのでまとめ
$(document).ready(function(){ var dt = noonDecision(); var w = dt.getDay(); var wd = ['日', '月', '火', '水', '木', '金', '土']; var holidayDates = ['2019/3/21','2019/4/29','2019/4/30','2019/5/1','2019/5/2','2019/5/3','2019/5/4','2019/5/5','2019/5/6','2019/7/15','2019/8/11','2019/8/12','2019/9/16','2019/9/23','2019/10/14','2019/10/22','2019/11/3','2019/11/4','2019/11/23']; var startWork = '2020/01/01'; var endWork = '2019/12/31'; var errorFlg = true; if (new Date(dt.getFullYear(), dt.getMonth(), dt.getDate()).getTime() >= new Date(endWork).getTime()) { dt = new Date(startWork); } else { while (errorFlg) { // 祝日判定 holidayDecision(); // 土日判定 satSunDecision(); } } $('body').html('<center>' + (dt.getMonth()+1) + '月' + dt.getDate() + '日 (' + wd[dt.getDay()] + ')</center>'); /** * 祝日判定 **/ function holidayDecision() { var checkDate = dt.getDate(); for (var i = 0; i < holidayDates.length; i++) { if (new Date(dt.getFullYear(), dt.getMonth(), dt.getDate()).getTime() == new Date(holidayDates[i]).getTime()) { dt.setDate(dt.getDate() + 1); } } if (checkDate == dt.getDate()) { errorFlg = false; } else { errorFlg = true; } } /** * 土日判定 **/ function satSunDecision() { if (dt.getDay() == 6) { dt.setDate(dt.getDate() + 2); errorFlg = true; } else if (dt.getDay() == 0) { dt.setDate(dt.getDate() + 1); errorFlg = true; } } /** * 正午判定 * return Date **/ function noonDecision() { var dt = new Date(); var insObj = new Date(dt.getFullYear(), dt.getMonth(), dt.getDate(), 12, 0, 0); if (dt >= insObj) { dt.setDate(dt.getDate() + 1); } return dt; } });
まとめ
whileで繰り返してるのはGWなど祝日明けが土日の場合と土日明けが祝日だったりするため。
祝日でも土日でもない場合に初めてwhile文を抜けます。
ややこしかったところ
月を取得するとき1月ならgetMonth()で0が取れてくるところ
(n – 1)なので+1をする。
オブジェクト生成するときは文字列を渡す場合と数値を渡す場合で結果が異なる。
new Date().getMonth(); // 3月だと2 (n-1) new Date('2019/3/1').getMonth(); // 2 new Date(2019,3,1).getMonth(); // 3
公式
注: 引数 monthIndex は 0 から始まります。 つまり 1 月 = 0、 12 月 = 11 です。
日付比較は.getTimeを使う
if (new Date(2019, 3, 1).getTime() == new Date('2019/3/1').getTime()) { // false } if (new Date(2019, (3-1), 1).getTime() == new Date('2019/3/1').getTime()) { // true } // getTimeを使わないとfalseになる var foo = new Date(2019, 3, 1); var bar = new Date(2019, 3, 1); if (foo == bar) { //false }
曜日はgetDay()で数値が取れてくるだけなので別に文字列で曜日配列を作成する必要がある。
日曜日なら0,月曜日なら1・・・土曜日なら6
祝日は自分で定義する必要がある。
日付オブジェクトを作成するとき文字列を渡す場合YYYY/MM/DDかYYYY/M/D形式にするとよい。
(スラッシュ区切り)
Date.parseは使用しない。
公式
注: ブラウザごとに動作が異なり一貫性がないため、Date コンストラクタ (または同等の Date.parse) で日付文字列を解釈しないように強くすすめます。RFC 2822 形式の文字列のサポートは、慣例にすぎません。 ISO 8601 フォーマットのサポートは、日付のみの文字列 (例: “1970-01-01”) が地方時ではなくUTCとして扱われる点で異なります。
末日を取得するときはdに0を指定すると指定した月の末日が取れてくる。
new Date(2019, 2, 0).getDate()と渡すと28が取得できる。
日付に31以上の数値を渡すと月を繰り上げてくれる。
var foo = new Date(2019, (3-1), 33); // 3月は31日まで (n-1)で3月と認識させている $('body').html((foo.getMonth() + 1) + '月'); // 33を渡すことにより繰り上がった結果4月 $('body').append(foo.getDate() + '日'); // 3月31日に33を渡すことにより繰り上がった結果2日
とてもややこしいですが月は0が1月扱いなのでDateオブジェクトを作成するときは-1
表示させるときは+1しています。
仮にDateオブジェクトを作成するときにMonthに-1をせず3を渡すと4月扱いとなりますので
2019年4月の末日は30日となり、33 – 30の計算でgetMonth()で繰り上がって4、getDate()では3が取得されます。