🚀The world's best VBA AI has evolved. ExcelMaster is now an autonomous Agent.Read more →
Back to Blog

Excel VBA の Weekday・DatePart — 日付の部品を取り出す、そして月曜日が 1 でない理由

|

Excel VBA の Weekday・DatePart — 日付の部品を取り出す、そして月曜日が 1 でない理由

TL;DRYear(d)Month(d)Day(d)Hour(t)Minute(t)Second(t) は、日付から整数を 1 つずつ返します — 単純で曖昧さもありません。罠は Weekday(d) です。1〜7 を返しますが、その番号 付けは既定で vbSunday(1)になる第 2 引数に左右されるので、既定では月曜日は 1 ではなく 2 です。vbMonday を渡す(または vb* 定数と比較する)と、週末ロジックは静かに間違うのをやめます。

Sub PartsDemo()
    Dim d As Date: d = #2026-08-26#        ' 水曜日
    Debug.Print Year(d), Month(d), Day(d)  ' 2026  8  26
    Debug.Print Weekday(d)                 ' 4  — 既定は日曜=1 なので水曜=4
    Debug.Print Weekday(d, vbMonday)       ' 3  — 月曜=1 なので水曜=3
    Debug.Print DatePart("ww", d)          ' 35 — 週番号(専用関数はない)
End Sub

部品を取り出すのは、部品から日付を組み立てることの逆向きです。Double は 手元にあり、そこから年、月、曜日がほしい。関数のほとんどは、あるべきとおりに退屈です — YearMonthDay はただ数値を読むだけ。Weekday は、必要以上に多くのマクロを終わらせてきた一つで、 その原因はまるごと、誰も覚えていない既定値にあります。

この記事で学べること

  • 単純な取り出し役 — YearMonthDayHourMinuteSecond — それぞれ整数を 1 つ
  • Weekday が既定で月曜日に 2 を返す理由と、それを直すただ一つの引数
  • ひそかに間違っていない週末・平日の判定の書き方
  • DatePart — 週番号や四半期に届く汎用の取り出し役
  • DatePart("ww", …) の週番号が年境界で 1 つずれることがある理由(ISO 8601)
  • WeekdayNameMonthNameローカライズされた名前を返す — 表示に使い、解析には使わない

単純な取り出し役:それぞれ整数を 1 つ

YearMonthDay は日付をカレンダーの構成要素に分け、HourMinuteSecond は時刻の小数を 分けます。それぞれがただの Integer を返し、つまずくところはありません。

Dim d As Date: d = Now                 ' 2026-08-26 14:30:07
Debug.Print Year(d)      ' 2026
Debug.Print Month(d)     ' 8   (1〜12 の数値であって、名前ではない)
Debug.Print Day(d)       ' 26
Debug.Print Hour(d)      ' 14  (24 時間制)
Debug.Print Minute(d)    ' 30
Debug.Print Second(d)    ' 7

Month"August" ではなく 8 を返します — 数値です。これらは、関連する日付(月初、翌年の 同じ日など)を組み立てるために DateSerial へ渡し戻す積み木です。ここに 驚きはありません — だからこそ Weekday が人の不意を突くのです。

Weekday が月曜日に 2 を返す理由

Weekday(date, [firstDayOfWeek]) は 1 から 7 の数値を返します — が、どの曜日が 1 かは第 2 引数で 決まり、省略すると VBA は vbSunday を使うので、日曜日 = 1、月曜日 = 2 になります。

Weekday(#2026-08-24#)             ' 2  — その月曜日、既定で日曜=1 だから
Weekday(#2026-08-24#, vbMonday)   ' 1  — これで月曜=1 … 日曜=7

これが一族全体の目玉のバグです。If Weekday(d) = 1 Then ' 月曜日 のようなコードは誤りで — 既定の 呼び出しでは 1日曜日です — If Weekday(d) = 6 Or Weekday(d) = 7 Then ' 週末 のようなコードは、 呼び出し箇所からは見えない「最初の曜日」の思い込みに丸ごと依存しています。堅牢な直し方は 2 つあり、 どちらも当て推量を取り除きます。

' 直し方 1 — 最初の曜日を明示すれば、月曜が本当に 1 になる:
If Weekday(d, vbMonday) >= 6 Then MsgBox "weekend"   ' 6 = 土, 7 = 日

' 直し方 2 — マジックナンバーではなく、名前付き定数と比較する:
If Weekday(d) = vbSaturday Or Weekday(d) = vbSunday Then MsgBox "weekend"

vb* 定数(vbSundayvbMonday、… vbSaturday)は、最初の曜日の引数に関わらず正しいので、 それらと比較するのが最も安全な習慣です。ルールはこうです。曜日番号を裸の数値で書かないこと — vbMonday を渡して番号付けを期待どおりにするか、vb* 定数と比較しましょう。

DatePart:汎用の取り出し役

DatePart(interval, date, [firstDayOfWeek], [firstWeekOfYear]) は万能ナイフ版です。 DateAddDateDiff同じインターバルコードを取り、その単位を 取り出します。年・月・日・時刻については専用関数と同じですが、自分専用の関数を持たないいくつかの 部品に届く唯一の組み込み手段でもあります。

DatePart("q", d)     ' 年の四半期 (1〜4) — Quarter() 関数は存在しない
DatePart("ww", d)    ' 年の週番号 (1〜53)
DatePart("y", d)     ' 年内通算日 (1〜366) — 「年内通算日」を意味する "y"
DatePart("m", d)     ' 8 — Month(d) と同じ

四半期週番号が必要なときは DatePart に手を伸ばし、日常的な部品には素の Year / Month / Day を使いましょう。そのほうが読みやすいからです。DateAdd と同じコードの罠に注意 — "y" は 年内通算日、"ww" は週です。一度声に出しておきましょう。

年境界での週番号の罠

DatePart("ww", …) には、人を驚かせる独自の既定値があります。年の最初の週週の最初の曜日が、 どちらも US 式のルール(vbSundayvbFirstJan1)を既定とし、これはISO 8601 ではありません — ヨーロッパの大半と多くの業務カレンダーが使う標準です。そのため 12 月末や 1 月初めの日が、思って いない週番号に着地することがあります。

DatePart("ww", #2026-12-31#)                          ' 53  (US 式の既定ルール)
DatePart("ww", #2026-12-31#, vbMonday, vbFirstFourDays) ' ISO 式の答え

週番号が重要なら — 給与計算の週、スプリント番号、壁のカレンダーと一致しなければならない何か — 最初の曜日に vbMonday を、最初の週のルールに vbFirstFourDays を渡して ISO 8601 に合わせましょう。 「年末年始のあたりで週番号が 1 つずれる」という定番のバグは、いつもこの 2 つの既定値です。

WeekdayName と MonthName はローカライズされる

曜日や月の番号名前に変えるには、WeekdayNameMonthName を使います。どちらもマシンの 言語で名前を返すので、表示には理想的で、読み戻す用途には誤りです。

WeekdayName(2)              ' 英語環境で "Monday"、ドイツ語環境で "Montag"
MonthName(8)               ' ロケール次第で "August" / "August" / "août"
WeekdayName(2, True)       ' 省略形: "Mon"

出力がユーザーのロケールに従うので、固定の英語文字列と比較したり、別のシステムが読むファイルに 書き込んだりしてはいけません — それはロケールバグの種です。自分で制御できる安定したラベルには、 代わりに日付を書式化しましょう。Format(d, "dddd") は完全な曜日名を、Format(d, "mmmm") は月名を 返します。これも Format 経由でロケールを意識しますが、明示的です。 WeekdayName / MonthName は画面表示に、ロジックには数値(WeekdayMonth)を使いましょう。

率直な結論:部品は簡単、既定値がやっかい

日付から部品を取り出すのは、VBA の日付まわりで最も不思議のないことです — ただし、不釣り合いに多くの バグを生む注釈が 1 つあります。

  • 単純な部品、単純な関数YearMonthDayHourMinuteSecond。それぞれ整数を 返し、Month は名前ではなく数値です。
  • Weekday には隠れた既定値 → それは vbSunday なので、月曜日は 2 です。vbMonday を 渡すか、vbSaturday / vbSunday と比較すること — 裸の数値は禁物。
  • 関数のない部品には DatePart四半期"q")と週番号"ww")。ISO 週は vbMonday
    • vbFirstFourDays で合わせます。
  • 名前はローカライズされるWeekdayName / MonthName はマシンの言語に従う。表示に使い、 決して解析には使わないこと。

最も多くのバグを防ぐたった一つの習慣。曜日番号を決してリテラルにしないこと。どの曜日が最初かを 言うか、意味する曜日を名前で指すか、です。

ExcelMaster の活用

部品取り出しのバグが厄介なのは、コードが見るからに正しそうに見えるからです。Weekday = 1 を チェックする週末フィルター、毎年 1 月に給与カレンダーと食い違う週番号の列、別の言語のシステムが 読めない WeekdayName をファイルに書くレポート。どれも、誰も覚えていなかった既定値です。

ExcelMaster は、最初から正しい 取り出しを書きます。ルールを説明すれば — 「週末を飛ばす」、「四半期で行をまとめる」、「各行に ISO 週のラベルを付ける」 — 曜日ロジックには Weekday(d, vbMonday)vb* 定数を、週番号には ISO 引数 付きの DatePart を使い、表示用の名前と分岐に使う数値を分けて保ちます。あなたはカレンダーのルールを 説明するだけ。隠れた既定値に頼らない部品取り出しを書くのは、それがやります。

よくある質問

VBA で Weekday が間違った曜日番号を返すのはなぜ?

Weekday が週の番号付けを第 2 引数で決め、それが既定で vbSunday になるからです — つまり 日曜日が 1、月曜日が 2 です。月曜日が 1 だと思い込んでいると、すべての結果が 1 つずれます。最初の 曜日を明示して Weekday(d, vbMonday) とすれば月曜日が 1、日曜日が 7 になり、あるいは結果を名前付き 定数 vbSaturdayvbSunday と比較しましょう。ハードコードした数値ではなく。

VBA で日付が週末かどうかを判定するには?

最初の曜日の既定値に噛まれないよう、定数を使います — If Weekday(d) = vbSaturday Or Weekday(d) = vbSunday Then …vb* 定数は、どんな「最初の曜日」引数が働いていても正しいままです。あるいは Weekday(d, vbMonday) >= 6 は 6(土曜)と 7(日曜)を週末として扱います — ただし vbMonday を 渡したことを確かめてください。

VBA で日付の四半期や週番号を取得するには?

専用の QuarterWeek 関数がないので、DatePart を使います。DatePart("q", d) は四半期 1〜4 を、 DatePart("ww", d) は週番号を返します。ISO 8601 の週番号には追加の引数を渡します — DatePart("ww", d, vbMonday, vbFirstFourDays)。さもないと年末年始の週が 1 つずれることがあります。

VBA の Month と MonthName の違いは?

Month(d) は月を数値(1〜12)で返し、ロジックに使います。MonthName(n) は月番号を名前の テキストに変えます(MonthName(8) は "August")。MonthName はマシンの言語に従うので、表示専用に しましょう。分岐や比較には Month の数値を使います。

VBA の WeekdayName は英語名を返しますか?

英語環境でのみです。WeekdayNameMonthNameシステムのロケールで名前を返すので、同じ コードでもマシンによって "Monday" や "Montag" や "lundi" になります。その出力を固定の英語文字列と 比較してはいけません。制御されたラベルには Format(d, "dddd") を、ロジックには数値の Weekday を 使いましょう。

検証環境

検証環境: Excel 365 (Windows 11), VBA 7.1 — 最終確認 2026-08-26。

関連ガイド: VBA DateAdd・DateDiff — 日付計算 · VBA Now・Date・Time — 時計を読む · VBA Format — 日付・数値の書式設定 · VBA CStr・CDate・Val — 文字列を数値・日付へ変換 · VBA For ループ — 実務例