本記事はJavascript Advent Calendar 2019の19日目の記事です。
結論
ordinalNumber
: x番目、1以上の整数
weekDay
: y曜日、日曜日を0として0~6の整数
date
: 指定の年月、javascriptの日付型、デフォルトで本日
function getDate(ordinalNumber, weekDay, date = new Date) {
return ((7 * (ordinalNumber - 1) + 1) + (weekDay - new Date(date.getFullYear(), date.getMonth(), 1).getDay()) + (-(Math.sign(Math.sign(weekDay - new Date(date.getFullYear(), date.getMonth(), 1).getDay()) + 1) - 1) * 7)) * Math.sign(Math.sign(new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate() - ((7 * (ordinalNumber - 1) + 1) + (weekDay - new Date(date.getFullYear(), date.getMonth(), 1).getDay()) + (-(Math.sign(Math.sign(weekDay - new Date(date.getFullYear(), date.getMonth(), 1).getDay()) + 1) - 1) * 7))) + 1)
}
例
2019年12月19日付に実行した場合です
// 今月の第3木曜日
console.log(getDate(3,4)) // => 19
// 第5水曜日(1月1日)
console.log(getDate(5,3)) // => 0
// 2020年の体育の日(10月の第2月曜日)
console.log(getDate(2,1,new Date('2020/10'))) // => 12
なぜこの関数が生まれたのか
Googleカレンダーのこれを真似したいと思いました。
この第x,y曜日という指定がどうしてもしたかったのです。あとはここから日付を求めればOK。
しかしその方法をいくらネットを探しても見当たらない。日付→第x,y曜日を求めるのはいくつか見つけましたが、私がほしいのはその逆関数。モジュールにdayjsを使ってたのですが、こちらにもない。なので仕方なく自作で作ることになりました。
で、どうせならワンライナーでまとめてみました。~~ワンライナーでまとめる意味全くないのですが。しかも見づらいし。~~ワンライナーなのに関数含めて3行という点はご了承ください。これを作ったのが2ヶ月近く前で、今見直しても解読できません。
作りとしては条件分岐が激しくあるので、かなりズルい手法ですが、Math.signを使ってゴリ押ししました。Math.signは正なら1、負なら-1、0なら0を返します。
絶対ワンライナーで使うために作られた関数ではないですが。
格好良くワンライナーでまとめるよりは、素直に読めるコード書きましょう。