t-hom’s diary

主にVBAネタを扱っているブログ…とも言えなくなってきたこの頃。

VBA 特定日付が、第何週目の何曜日なのかを求める関数

今回は特定日付が、第何週目の何曜日なのかを求める関数を紹介する。
といっても曜日は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という単語を使っても良かったんだけど、平日限定の意味を含んでしまう気がしてやめた。

当ブログは、amazon.co.jpを宣伝しリンクすることによってサイトが紹介料を獲得できる手段を提供することを目的に設定されたアフィリエイト宣伝プログラムである、 Amazonアソシエイト・プログラムの参加者です。