今回は特定日付が、第何週目の何曜日なのかを求める関数を紹介する。
といっても曜日はWeekday関数やFormat関数で簡単に求まるので、今回紹介するのは月のうちの何週目に相当するかを求める関数だ。
まず、特定月のうち何週目に当たるのかは、次の関数で求められる。
Function WeekOfTheMonth(d As Date) As Long WeekOfTheMonth = DatePart("ww", d) - DatePart("ww", DateSerial(Year(d), Month(d), 1)) + 1 End Function
ただ作ってみてこれは私が求めている結果と違うことに気付いた。
実務では第二火曜日とか、第三木曜日に特定の処理を行うことがある。
たとえば2019年3月21日は、3月の第四週目にあたる。
でも、2019年3月21日は第三木曜日である。
その月の何回目の木曜日かを数える必要があるのだ。
そこで、愚直に数え上げる関数を作った。
これが本記事のメインである。
Function WeekNumberByDayOfTheWeek(d As Date) As Long Dim ret As Long Dim target As Long: target = Weekday(d) Dim i As Date For i = DateSerial(Year(d), Month(d), 1) To d If Weekday(i) = target Then ret = ret + 1 Next WeekNumberByDayOfTheWeek = ret End Function
関数を試すコードが以下。最初に紹介したWeekOfTheMonthも使用している。
Sub hoge() Dim d As Date For d = #1/1/2019# To #4/1/2019# Debug.Print Format(d, "yyyy年m月d日"); "は、"; Debug.Print Month(d); "月の第"; WeekOfTheMonth(d); "週目、"; Debug.Print "第"; WeekNumberByDayOfTheWeek(d); Format(d, "aaa"); "曜日です。" Next End Sub
結果はこんな感じ
2019年1月1日は、 1 月の第 1 週目、第 1 火曜日です。 2019年1月2日は、 1 月の第 1 週目、第 1 水曜日です。 2019年1月3日は、 1 月の第 1 週目、第 1 木曜日です。 2019年1月4日は、 1 月の第 1 週目、第 1 金曜日です。 2019年1月5日は、 1 月の第 1 週目、第 1 土曜日です。 2019年1月6日は、 1 月の第 2 週目、第 1 日曜日です。 2019年1月7日は、 1 月の第 2 週目、第 1 月曜日です。 2019年1月8日は、 1 月の第 2 週目、第 2 火曜日です。 2019年1月9日は、 1 月の第 2 週目、第 2 水曜日です。 2019年1月10日は、 1 月の第 2 週目、第 2 木曜日です。 2019年1月11日は、 1 月の第 2 週目、第 2 金曜日です。 2019年1月12日は、 1 月の第 2 週目、第 2 土曜日です。 2019年1月13日は、 1 月の第 3 週目、第 2 日曜日です。 2019年1月14日は、 1 月の第 3 週目、第 2 月曜日です。 …つづく
3/26 追記 もっとスマートなやり方
記事を引用していただいたのでお邪魔すると、更にスマートなやり方が紹介されていた。
z1000s.hatenablog.com
WeekNumberByDayOfTheWeek(d)は(Day(d) + 6) \ 7に置き換えできるようだ。
どういう理屈なのかは上記サイトを参照のこと。
以下で試してみたところ、中断されずに問題なく完了した。
Sub hoge() Dim d As Date For d = Date To Date + 100000 Debug.Assert (Day(d) + 6) \ 7 = WeekNumberByDayOfTheWeek(d) Next Debug.Print "End" End Sub
※Debug.AssertにFalseを与えると中断する。
おわりに
今回は英語の関数名を考えるのに苦労した。
もう日本語で「第X曜日」という関数名にしようかと思ったけど最近は英語の識別子に拘ってしまう。
日本語だと「曜日」の2文字で済むものが、英語だと「Day of the week」になる。
既存関数のようにWeekdayという単語を使っても良かったんだけど、平日限定の意味を含んでしまう気がしてやめた。