【VBA】Excelにカレンダー(日付入力)フォームを作る方法(コピペOK)

VBA
スポンサーリンク
スポンサーリンク
  1. この記事でわかること
    1. どんな場面で使う?
  2. 完成イメージ(Before / After)
  3. 実行前の準備
    1. バックアップを取る
    2. Excelをマクロ有効ブック(.xlsm)で保存する
  4. 手順(コピペ → 実行まで約10分)
    1. Step 1: VBE(コードを書く画面)を開く
    2. Step 2: UserFormを追加する
    3. Step 3: UserFormのコードウィンドウを開く
    4. Step 4: UserFormモジュールにコードを貼り付ける
    5. Step 5: 標準モジュールにフォーム表示コードを貼り付ける
    6. Step 6: 実行する
  5. コード(最小版)– 基本カレンダーフォーム
    1. UserFormモジュール(frmCalendar)に貼り付ける
    2. 標準モジュールに貼り付ける(フォーム表示用)
    3. 書き換えポイント
  6. コード(実務版)– 今日ハイライト+土日色分け+エラー処理付き
    1. UserFormモジュール(frmCalendar)に貼り付ける
    2. 標準モジュールに貼り付ける(フォーム表示用)
    3. (任意)セルのダブルクリックでカレンダーを開く
    4. 書き換えポイント
  7. よくある落とし穴5選
    1. 1. MonthViewコントロールが相手のPCで動かない
    2. 2. 日付が文字列としてセルに入り、VLOOKUPが効かない
    3. 3. DateSerialの月オーバーフローを知らず、翌月の日付が表示されない
    4. 4. Weekday関数の戻り値がずれてカレンダーの曜日が合わない
    5. 5. vbModelessを使わないとフォーム表示中にセルを選択できない
    6. VBAのカレンダーフォームで日付が文字列として入力されるときの対処法
    7. VBAのUserFormでカレンダー表示中にセルが選べないときの対処法
  8. FAQ
    1. Q1: 月曜始まりのカレンダーにできる?
    2. Q2: 土日だけでなく祝日にも色を付けたい
    3. Q3: セルをダブルクリックしたら自動でカレンダーが開くようにしたい
    4. Q4: カレンダーから入力した日付の形式を変えたい(例: yyyy年mm月dd日)
    5. Q5: 複数のセルに連続で日付を入力したい(フォームを閉じずに)
  9. まとめ
    1. 関連記事
  10. 次にやりたくなること

この記事でわかること

  • UserFormでカレンダー(日付選択)フォームを作る方法
  • 外部コントロール(MonthView等)を使わず、どのPCでも動く方式
  • 前月/翌月の切替・土日の色分け付きの実務版カレンダー

対象: Excel 2016以降 / Microsoft 365、Windows 10/11

どんな場面で使う?

  • 日付の手入力ミスをゼロにしたいとき
  • 外部コントロール不要でどのPCでも動くカレンダーUIを作りたいとき
  • 日報・勤怠管理シートにカレンダーから日付を入力させたいとき
  • MonthViewが使えない環境でも日付選択フォームが必要なとき

所要時間: コピペ → 実行まで約10分

完成イメージ(Before / After)

Before(手入力):

  • セルに「2026/3/18」「3月18日」「R8.3.18」「2026-03-18」など、人によって形式がバラバラ
  • 「2026/2/30」のような存在しない日付が入ることもある
  • VLOOKUPやSUMIFSがエラーを返す

After(カレンダーフォーム):

  • マクロを実行するとカレンダーフォームが表示される
  • 年月を切り替えながら日付ボタンをクリック
  • アクティブセルに 2026/03/18 のような正しい日付型の値が入る
  • 全員が同じ形式で入力できる

自分も以前、日報管理シートで日付を手入力させていたら、「2024/2/30」や「R6.3.15」のように形式がバラバラで、VLOOKUPが全滅した。カレンダーフォームを導入してからは日付の入力ミスがゼロになり、月末の修正作業がまるごとなくなった。日付入力のたびにヒヤヒヤしている人が、この記事で外部コントロール不要のカレンダーフォームをサクッと作れるようになればうれしい。

カレンダーフォームを使えば、日付の手入力ミスをゼロにできる。外部コントロール不要で、どのPCでも動く。

UserFormの基本操作がわからない場合は、先に 入力フォーム(UserForm)で手入力ミスを防ぐ方法 を読んでおくとスムーズに進められる。

実行前の準備

バックアップを取る

カレンダーから日付を入力すると、アクティブセルの値が上書きされる。マクロ経由の書き込みはCtrl+Zで元に戻せない。大事なデータがあるセルを選択した状態で実行しないよう注意。 念のためファイルのコピーを別フォルダに保存しておく。

Excelをマクロ有効ブック(.xlsm)で保存する

拡張子が .xlsx のままだとマクロが保存できない。

  1. 「ファイル」→「名前を付けて保存」
  2. ファイルの種類を「Excelマクロ有効ブック (*.xlsm)」に変更
  3. 保存

手順(コピペ → 実行まで約10分)

Step 1: VBE(コードを書く画面)を開く

Excelで Alt + F11 を押す。

Step 2: UserFormを追加する

  1. VBEのメニュー →「挿入」→「ユーザーフォーム」
  2. 空のフォーム(UserForm1)が追加される
  3. プロパティウィンドウで以下を変更する:
    • (Name): frmCalendar
    • Caption: 日付入力カレンダー
    • Width: 260(※コード実行時に自動調整されるため、おおよその値でOK)
    • Height: 240(※同上)

Step 3: UserFormのコードウィンドウを開く

  1. フォーム(frmCalendar)をダブルクリック
  2. コードウィンドウが開く
  3. 既存のコード(Private Sub UserForm_Click() 等)があれば全て消す

Step 4: UserFormモジュールにコードを貼り付ける

下の「コード(最小版)」または「コード(実務版)」をそのままコピペする。

Step 5: 標準モジュールにフォーム表示コードを貼り付ける

  1. VBEのメニュー →「挿入」→「標準モジュール」
  2. 下のフォーム表示コードを貼り付ける

Step 6: 実行する

  1. 日付を入力したいセルをクリックして選択
  2. Alt + F8ShowCalendar を選んで「実行」
  3. カレンダーフォームが表示される
  4. 日付をクリックすると、選択中のセルに日付が入る

ボタンに割り当てれば毎回Alt+F8を押さなくて済む。方法は マクロをボタン1つで実行する方法 を参照。

コード(最小版)– 基本カレンダーフォーム

まずこれで動きを確認する。年月の表示と日付ボタンのクリックで日付入力ができる最小構成。

UserFormモジュール(frmCalendar)に貼り付ける


'============================================================
' ■ カレンダー日付入力フォーム(最小版)
'   → UserFormにラベル+ボタンを動的生成してカレンダーを表示
'   → 日付クリックでアクティブセルに日付を入力
'   → 貼り付け場所: frmCalendar の UserFormモジュール
'============================================================
Option Explicit

'--- モジュールレベル変数
Private mYear  As Long   '現在表示中の年
Private mMonth As Long   '現在表示中の月

'--- 定数
Private Const BTN_W   As Single = 30   'ボタン幅
Private Const BTN_H   As Single = 22   'ボタン高さ
Private Const START_X As Single = 10   '左端の開始位置
Private Const START_Y As Single = 50   '日付ボタンの開始Y位置
Private Const GAP     As Single = 2    'ボタン間の隙間

'============================================================
' フォーム初期化 -- コントロールを動的に生成
'============================================================
Private Sub UserForm_Initialize()

    Me.Width = START_X * 2 + BTN_W * 7 + GAP * 6 + 10
    Me.Height = START_Y + BTN_H * 7 + GAP * 6 + 30

    '--- 年月ラベル
    Dim lblYM As MSForms.Label
    Set lblYM = Me.Controls.Add("Forms.Label.1", "lblYearMonth")
    With lblYM
        .Left = START_X: .Top = 8
        .Width = 120: .Height = 18
        .Font.Size = 12: .Font.Bold = True
        .Caption = ""
    End With

    '--- 前月ボタン
    Dim btnP As MSForms.CommandButton
    Set btnP = Me.Controls.Add("Forms.CommandButton.1", "btnPrev")
    With btnP
        .Left = Me.Width - 80: .Top = 6
        .Width = 30: .Height = 20
        .Caption = "<": .Font.Size = 10
    End With

    '--- 翌月ボタン
    Dim btnN As MSForms.CommandButton
    Set btnN = Me.Controls.Add("Forms.CommandButton.1", "btnNext")
    With btnN
        .Left = Me.Width - 45: .Top = 6
        .Width = 30: .Height = 20
        .Caption = ">": .Font.Size = 10
    End With

    '--- 曜日ヘッダー(日〜土)
    Dim dayNames As Variant
    dayNames = Array("日", "月", "火", "水", "木", "金", "土")
    Dim c As Long
    For c = 0 To 6
        Dim lblDay As MSForms.Label
        Set lblDay = Me.Controls.Add("Forms.Label.1", "lblDow" & c)
        With lblDay
            .Left = START_X + c * (BTN_W + GAP)
            .Top = START_Y - 18
            .Width = BTN_W: .Height = 16
            .TextAlign = fmTextAlignCenter
            .Caption = dayNames(c)
            .Font.Bold = True
            If c = 0 Then .ForeColor = RGB(220, 50, 50)     '日曜: 赤
            If c = 6 Then .ForeColor = RGB(50, 100, 220)     '土曜: 青
        End With
    Next c

    '--- 日付ボタン 42個(6行×7列)
    Dim r As Long
    For r = 0 To 5
        For c = 0 To 6
            Dim idx As Long
            idx = r * 7 + c
            Dim btn As MSForms.CommandButton
            Set btn = Me.Controls.Add("Forms.CommandButton.1", "btnDay" & idx)
            With btn
                .Left = START_X + c * (BTN_W + GAP)
                .Top = START_Y + r * (BTN_H + GAP)
                .Width = BTN_W: .Height = BTN_H
                .Caption = "": .Font.Size = 9
                .Tag = ""
            End With
        Next c
    Next r

    '--- 当月を表示
    mYear = Year(Date)
    mMonth = Month(Date)
    DrawCalendar

End Sub

'============================================================
' カレンダー描画
'============================================================
Private Sub DrawCalendar()

    '--- 年月ラベル更新
    Me.Controls("lblYearMonth").Caption = mYear & "年" & mMonth & "月"

    '--- 月初日と月末日
    Dim firstDate As Date
    firstDate = DateSerial(mYear, mMonth, 1)

    Dim lastDay As Long
    lastDay = Day(DateSerial(mYear, mMonth + 1, 0))

    '--- 月初の曜日(日曜=1)
    Dim startDow As Long
    startDow = Weekday(firstDate, vbSunday)

    '--- 42個のボタンを更新
    Dim i As Long
    For i = 0 To 41
        Dim btn As MSForms.CommandButton
        Set btn = Me.Controls("btnDay" & i)

        Dim dayNum As Long
        dayNum = i - (startDow - 1) + 1

        If dayNum >= 1 And dayNum <= lastDay Then
            btn.Caption = CStr(dayNum)
            btn.Tag = Format(DateSerial(mYear, mMonth, dayNum), "yyyy/mm/dd")
            btn.Enabled = True
            btn.ForeColor = RGB(0, 0, 0)

            '--- 土日の色分け
            Dim col As Long
            col = i Mod 7
            If col = 0 Then btn.ForeColor = RGB(220, 50, 50)     '日曜
            If col = 6 Then btn.ForeColor = RGB(50, 100, 220)     '土曜
        Else
            btn.Caption = ""
            btn.Tag = ""
            btn.Enabled = False
        End If
    Next i

End Sub

'============================================================
' 前月/翌月ボタン
'============================================================
Private Sub btnPrev_Click()
    mMonth = mMonth - 1
    If mMonth < 1 Then
        mMonth = 12
        mYear = mYear - 1
    End If
    DrawCalendar
End Sub

Private Sub btnNext_Click()
    mMonth = mMonth + 1
    If mMonth > 12 Then
        mMonth = 1
        mYear = mYear + 1
    End If
    DrawCalendar
End Sub

'============================================================
' 日付ボタンのクリック(全42個を1つのハンドラで処理)
'============================================================
Private Sub UserForm_MouseUp(ByVal Button As Integer, _
                              ByVal Shift As Integer, _
                              ByVal X As Single, ByVal Y As Single)
    '--- このイベントはフォーム自体のクリック。ボタンは下の専用処理で対応
End Sub

'--- 動的生成したボタンのクリックを受け取る汎用ハンドラ
'    Controls.Addで作ったボタンは直接イベントを持てないため、
'    ボタンごとにClickイベントを書く代わりに、Tag値を参照する方式を使う。
'    ※ 最小版では手動でイベントプロシージャを生成する簡易方式を採用
'============================================================
' ★ 以下の42個のイベントは、マクロで自動生成することも可能だが、
'   最小版ではコピペしやすいように個別に記載する。
'   実務版ではクラスモジュールを使って1箇所にまとめる。
'============================================================
Private Sub btnDay0_Click():  ClickDay 0:  End Sub
Private Sub btnDay1_Click():  ClickDay 1:  End Sub
Private Sub btnDay2_Click():  ClickDay 2:  End Sub
Private Sub btnDay3_Click():  ClickDay 3:  End Sub
Private Sub btnDay4_Click():  ClickDay 4:  End Sub
Private Sub btnDay5_Click():  ClickDay 5:  End Sub
Private Sub btnDay6_Click():  ClickDay 6:  End Sub
Private Sub btnDay7_Click():  ClickDay 7:  End Sub
Private Sub btnDay8_Click():  ClickDay 8:  End Sub
Private Sub btnDay9_Click():  ClickDay 9:  End Sub
Private Sub btnDay10_Click(): ClickDay 10: End Sub
Private Sub btnDay11_Click(): ClickDay 11: End Sub
Private Sub btnDay12_Click(): ClickDay 12: End Sub
Private Sub btnDay13_Click(): ClickDay 13: End Sub
Private Sub btnDay14_Click(): ClickDay 14: End Sub
Private Sub btnDay15_Click(): ClickDay 15: End Sub
Private Sub btnDay16_Click(): ClickDay 16: End Sub
Private Sub btnDay17_Click(): ClickDay 17: End Sub
Private Sub btnDay18_Click(): ClickDay 18: End Sub
Private Sub btnDay19_Click(): ClickDay 19: End Sub
Private Sub btnDay20_Click(): ClickDay 20: End Sub
Private Sub btnDay21_Click(): ClickDay 21: End Sub
Private Sub btnDay22_Click(): ClickDay 22: End Sub
Private Sub btnDay23_Click(): ClickDay 23: End Sub
Private Sub btnDay24_Click(): ClickDay 24: End Sub
Private Sub btnDay25_Click(): ClickDay 25: End Sub
Private Sub btnDay26_Click(): ClickDay 26: End Sub
Private Sub btnDay27_Click(): ClickDay 27: End Sub
Private Sub btnDay28_Click(): ClickDay 28: End Sub
Private Sub btnDay29_Click(): ClickDay 29: End Sub
Private Sub btnDay30_Click(): ClickDay 30: End Sub
Private Sub btnDay31_Click(): ClickDay 31: End Sub
Private Sub btnDay32_Click(): ClickDay 32: End Sub
Private Sub btnDay33_Click(): ClickDay 33: End Sub
Private Sub btnDay34_Click(): ClickDay 34: End Sub
Private Sub btnDay35_Click(): ClickDay 35: End Sub
Private Sub btnDay36_Click(): ClickDay 36: End Sub
Private Sub btnDay37_Click(): ClickDay 37: End Sub
Private Sub btnDay38_Click(): ClickDay 38: End Sub
Private Sub btnDay39_Click(): ClickDay 39: End Sub
Private Sub btnDay40_Click(): ClickDay 40: End Sub
Private Sub btnDay41_Click(): ClickDay 41: End Sub

'============================================================
' 日付クリック共通処理
'============================================================
Private Sub ClickDay(ByVal idx As Long)
    Dim btn As MSForms.CommandButton
    Set btn = Me.Controls("btnDay" & idx)

    If btn.Tag = "" Then Exit Sub

    '--- アクティブセルに日付型で書き込み
    ActiveCell.Value = CDate(btn.Tag)
    ActiveCell.NumberFormat = "yyyy/mm/dd"

    Me.Hide
End Sub

標準モジュールに貼り付ける(フォーム表示用)


'============================================================
' ■ カレンダーフォームを表示する
'   → 貼り付け場所: 標準モジュール
'============================================================
Sub ShowCalendar()
    frmCalendar.Show vbModeless
End Sub

書き換えポイント

項目 説明 初期値
BTN_W / BTN_H ボタンのサイズ 30 / 22
ActiveCell.NumberFormat 書き込む日付の表示形式 "yyyy/mm/dd"
曜日ヘッダー 日曜始まり Array("日","月","火","水","木","金","土")
vbModeless フォーム表示中にセル操作可能 モードレス表示

ポイント: DateSerial(mYear, mMonth + 1, 0) は「翌月の0日」、つまり当月の末日を返す。これで28日/29日/30日/31日の判定を自分で書く必要がない。日付計算の詳細は 2つの日付の差分・加算・比較を計算する方法 を参照。

コード(実務版)– 今日ハイライト+土日色分け+エラー処理付き

このカレンダーフォームを日報と勤怠シートに組み込んでからは、「日付の形式が違う」という問い合わせが一切なくなった。同僚にも配布しているが、外部コントロール不要なのでどのPCでもそのまま動いている。

実務版では以下を追加:

  • 今日の日付をハイライト(背景色で目立たせる)
  • 土日の色分け(日曜=赤、土曜=青)
  • エラー処理(予期しないエラーでフォームが閉じても安全)
  • セルをダブルクリックでカレンダーを開く機能(シートモジュール)

UserFormモジュール(frmCalendar)に貼り付ける

※ 最小版と同じフォーム名(frmCalendar)を使う。最小版のコードは全て消してから貼り付ける。


'============================================================
' ■ カレンダー日付入力フォーム(実務版)
'   → 今日ハイライト + 土日色分け + エラー処理付き
'   → 貼り付け場所: frmCalendar の UserFormモジュール
'============================================================
Option Explicit

'--- モジュールレベル変数
Private mYear  As Long
Private mMonth As Long

'--- 定数
Private Const BTN_W   As Single = 30
Private Const BTN_H   As Single = 22
Private Const START_X As Single = 10
Private Const START_Y As Single = 50
Private Const GAP     As Single = 2

'--- 色定数(★書き換えポイント:好みの色に変更可能)
Private Const CLR_BTN_BG   As Long = -2147483633 'Windowsのボタン既定色

'============================================================
' フォーム初期化
'============================================================
Private Sub UserForm_Initialize()
    On Error GoTo ErrHandler

    Me.Width = START_X * 2 + BTN_W * 7 + GAP * 6 + 10
    Me.Height = START_Y + BTN_H * 7 + GAP * 6 + 30

    '--- 年月ラベル
    Dim lblYM As MSForms.Label
    Set lblYM = Me.Controls.Add("Forms.Label.1", "lblYearMonth")
    With lblYM
        .Left = START_X: .Top = 8
        .Width = 120: .Height = 18
        .Font.Size = 12: .Font.Bold = True
    End With

    '--- 前月ボタン
    Dim btnP As MSForms.CommandButton
    Set btnP = Me.Controls.Add("Forms.CommandButton.1", "btnPrev")
    With btnP
        .Left = Me.Width - 80: .Top = 6
        .Width = 30: .Height = 20
        .Caption = "<": .Font.Size = 10
    End With

    '--- 翌月ボタン
    Dim btnN As MSForms.CommandButton
    Set btnN = Me.Controls.Add("Forms.CommandButton.1", "btnNext")
    With btnN
        .Left = Me.Width - 45: .Top = 6
        .Width = 30: .Height = 20
        .Caption = ">": .Font.Size = 10
    End With

    '--- 今日ボタン(★実務版で追加)
    Dim btnT As MSForms.CommandButton
    Set btnT = Me.Controls.Add("Forms.CommandButton.1", "btnToday")
    With btnT
        .Left = Me.Width - 115: .Top = 6
        .Width = 30: .Height = 20
        .Caption = "今日": .Font.Size = 8
    End With

    '--- 曜日ヘッダー
    Dim dayNames As Variant
    dayNames = Array("日", "月", "火", "水", "木", "金", "土")
    Dim c As Long
    For c = 0 To 6
        Dim lblDay As MSForms.Label
        Set lblDay = Me.Controls.Add("Forms.Label.1", "lblDow" & c)
        With lblDay
            .Left = START_X + c * (BTN_W + GAP)
            .Top = START_Y - 18
            .Width = BTN_W: .Height = 16
            .TextAlign = fmTextAlignCenter
            .Caption = dayNames(c)
            .Font.Bold = True
            If c = 0 Then .ForeColor = RGB(220, 50, 50)
            If c = 6 Then .ForeColor = RGB(50, 100, 220)
        End With
    Next c

    '--- 日付ボタン 42個
    Dim r As Long
    For r = 0 To 5
        For c = 0 To 6
            Dim idx As Long
            idx = r * 7 + c
            Dim btn As MSForms.CommandButton
            Set btn = Me.Controls.Add("Forms.CommandButton.1", "btnDay" & idx)
            With btn
                .Left = START_X + c * (BTN_W + GAP)
                .Top = START_Y + r * (BTN_H + GAP)
                .Width = BTN_W: .Height = BTN_H
                .Caption = "": .Font.Size = 9
                .Tag = ""
            End With
        Next c
    Next r

    '--- 当月を表示
    mYear = Year(Date)
    mMonth = Month(Date)
    DrawCalendar

    Exit Sub

ErrHandler:
    MsgBox "カレンダーの初期化でエラーが発生しました。" & vbCrLf & _
           "エラー: " & Err.Description, vbExclamation
End Sub

'============================================================
' カレンダー描画
'============================================================
Private Sub DrawCalendar()
    On Error GoTo ErrHandler

    Me.Controls("lblYearMonth").Caption = mYear & "年" & mMonth & "月"

    Dim firstDate As Date
    firstDate = DateSerial(mYear, mMonth, 1)

    Dim lastDay As Long
    lastDay = Day(DateSerial(mYear, mMonth + 1, 0))

    Dim startDow As Long
    startDow = Weekday(firstDate, vbSunday)

    Dim todayStr As String
    todayStr = Format(Date, "yyyy/mm/dd")

    Dim i As Long
    For i = 0 To 41
        Dim btn As MSForms.CommandButton
        Set btn = Me.Controls("btnDay" & i)

        Dim dayNum As Long
        dayNum = i - (startDow - 1) + 1

        If dayNum >= 1 And dayNum <= lastDay Then
            btn.Caption = CStr(dayNum)
            Dim dateStr As String
            dateStr = Format(DateSerial(mYear, mMonth, dayNum), "yyyy/mm/dd")
            btn.Tag = dateStr
            btn.Enabled = True

            '--- 色リセット
            btn.ForeColor = RGB(0, 0, 0)
            btn.BackColor = CLR_BTN_BG

            '--- 土日の色分け(★実務版で強化)
            Dim col As Long
            col = i Mod 7
            If col = 0 Then btn.ForeColor = RGB(220, 50, 50)     '日曜
            If col = 6 Then btn.ForeColor = RGB(50, 100, 220)     '土曜

            '--- 今日のハイライト(★実務版で追加)
            If dateStr = todayStr Then
                btn.BackColor = RGB(100, 255, 255)   '薄い水色
                btn.Font.Bold = True
            Else
                btn.Font.Bold = False
            End If

        Else
            btn.Caption = ""
            btn.Tag = ""
            btn.Enabled = False
            btn.BackColor = CLR_BTN_BG
        End If
    Next i

    Exit Sub

ErrHandler:
    MsgBox "カレンダーの描画でエラーが発生しました。" & vbCrLf & _
           "エラー: " & Err.Description, vbExclamation
End Sub

'============================================================
' 前月 / 翌月 / 今日ボタン
'============================================================
Private Sub btnPrev_Click()
    mMonth = mMonth - 1
    If mMonth < 1 Then
        mMonth = 12
        mYear = mYear - 1
    End If
    DrawCalendar
End Sub

Private Sub btnNext_Click()
    mMonth = mMonth + 1
    If mMonth > 12 Then
        mMonth = 1
        mYear = mYear + 1
    End If
    DrawCalendar
End Sub

'--- 今日ボタン(★実務版で追加)
Private Sub btnToday_Click()
    mYear = Year(Date)
    mMonth = Month(Date)
    DrawCalendar
End Sub

'============================================================
' 日付ボタンのクリック(42個)
'============================================================
Private Sub btnDay0_Click():  ClickDay 0:  End Sub
Private Sub btnDay1_Click():  ClickDay 1:  End Sub
Private Sub btnDay2_Click():  ClickDay 2:  End Sub
Private Sub btnDay3_Click():  ClickDay 3:  End Sub
Private Sub btnDay4_Click():  ClickDay 4:  End Sub
Private Sub btnDay5_Click():  ClickDay 5:  End Sub
Private Sub btnDay6_Click():  ClickDay 6:  End Sub
Private Sub btnDay7_Click():  ClickDay 7:  End Sub
Private Sub btnDay8_Click():  ClickDay 8:  End Sub
Private Sub btnDay9_Click():  ClickDay 9:  End Sub
Private Sub btnDay10_Click(): ClickDay 10: End Sub
Private Sub btnDay11_Click(): ClickDay 11: End Sub
Private Sub btnDay12_Click(): ClickDay 12: End Sub
Private Sub btnDay13_Click(): ClickDay 13: End Sub
Private Sub btnDay14_Click(): ClickDay 14: End Sub
Private Sub btnDay15_Click(): ClickDay 15: End Sub
Private Sub btnDay16_Click(): ClickDay 16: End Sub
Private Sub btnDay17_Click(): ClickDay 17: End Sub
Private Sub btnDay18_Click(): ClickDay 18: End Sub
Private Sub btnDay19_Click(): ClickDay 19: End Sub
Private Sub btnDay20_Click(): ClickDay 20: End Sub
Private Sub btnDay21_Click(): ClickDay 21: End Sub
Private Sub btnDay22_Click(): ClickDay 22: End Sub
Private Sub btnDay23_Click(): ClickDay 23: End Sub
Private Sub btnDay24_Click(): ClickDay 24: End Sub
Private Sub btnDay25_Click(): ClickDay 25: End Sub
Private Sub btnDay26_Click(): ClickDay 26: End Sub
Private Sub btnDay27_Click(): ClickDay 27: End Sub
Private Sub btnDay28_Click(): ClickDay 28: End Sub
Private Sub btnDay29_Click(): ClickDay 29: End Sub
Private Sub btnDay30_Click(): ClickDay 30: End Sub
Private Sub btnDay31_Click(): ClickDay 31: End Sub
Private Sub btnDay32_Click(): ClickDay 32: End Sub
Private Sub btnDay33_Click(): ClickDay 33: End Sub
Private Sub btnDay34_Click(): ClickDay 34: End Sub
Private Sub btnDay35_Click(): ClickDay 35: End Sub
Private Sub btnDay36_Click(): ClickDay 36: End Sub
Private Sub btnDay37_Click(): ClickDay 37: End Sub
Private Sub btnDay38_Click(): ClickDay 38: End Sub
Private Sub btnDay39_Click(): ClickDay 39: End Sub
Private Sub btnDay40_Click(): ClickDay 40: End Sub
Private Sub btnDay41_Click(): ClickDay 41: End Sub

'============================================================
' 日付クリック共通処理(★実務版: エラー処理追加)
'============================================================
Private Sub ClickDay(ByVal idx As Long)
    On Error GoTo ErrHandler

    Dim btn As MSForms.CommandButton
    Set btn = Me.Controls("btnDay" & idx)

    If btn.Tag = "" Then Exit Sub

    '--- アクティブセルに日付型で書き込み
    ActiveCell.Value = CDate(btn.Tag)
    ActiveCell.NumberFormat = "yyyy/mm/dd"

    Me.Hide
    Exit Sub

ErrHandler:
    MsgBox "日付の入力でエラーが発生しました。" & vbCrLf & _
           "セルが選択されているか確認してください。" & vbCrLf & _
           "エラー: " & Err.Description, vbExclamation
End Sub

標準モジュールに貼り付ける(フォーム表示用)


'============================================================
' ■ カレンダーフォームを表示する(実務版)
'   → 貼り付け場所: 標準モジュール
'============================================================
Sub ShowCalendar()
    On Error GoTo ErrHandler
    frmCalendar.Show vbModeless
    Exit Sub
ErrHandler:
    MsgBox "カレンダーの表示でエラーが発生しました。" & vbCrLf & _
           "エラー: " & Err.Description, vbExclamation
End Sub

(任意)セルのダブルクリックでカレンダーを開く

以下をシートモジュール(対象シートのコードウィンドウ)に貼り付ける。セルをダブルクリックすると、通常の編集モードの代わりにカレンダーフォームが開く。

シートモジュールの開き方: VBEの左側のプロジェクトエクスプローラーで、対象シート(例: Sheet1 (Sheet1))をダブルクリックする。コードウィンドウが開いたら、以下を貼り付ける。


'============================================================
' ■ セルのダブルクリックでカレンダーを開く
'   → 貼り付け場所: シートモジュール(対象シートのコード)
'============================================================
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
    '--- ★書き換えポイント: カレンダーを表示する列を指定
    '    例: A列(1列目)のセルをダブルクリックした場合のみ
    If Target.Column = 1 Then
        Cancel = True   '通常の編集モードをキャンセル
        ShowCalendar
    End If
End Sub

エラー処理の詳細は エラー処理(On Error)で止まらないマクロを作る方法 を参照。

書き換えポイント

項目 説明 初期値
RGB(100, 255, 255) 今日の日付の背景色 薄い水色
Target.Column = 1 ダブルクリックでカレンダーを開く列 A列(1)
ActiveCell.NumberFormat 日付の表示形式 "yyyy/mm/dd"

よくある落とし穴5選

1. MonthViewコントロールが相手のPCで動かない

自分も最初、MonthViewコントロールで立派なカレンダーを作って配布したら、相手のPCで「コントロールを読み込めません」エラーが出た。半日かけて作ったのが無駄になって、正直しんどかった。

原因: MonthView(MSCOMCT2.OCX)はOffice 2010以降で標準搭載されなくなった。64bit版Excelでは32bit用OCXが動かない場合もある。

対策: 外部コントロールを使わない。本記事のようにUserFormの標準コントロール(Label, CommandButton)だけで作れば、どのPCでも動く。

2. 日付が文字列としてセルに入り、VLOOKUPが効かない

原因: ActiveCell.Value = "2026/03/18" のように文字列で書き込むと、セルの値は日付型ではなく文字列型になる。見た目は同じでもVLOOKUPやSUMIFSで一致しない。

対策: ActiveCell.Value = CDate("2026/03/18") または ActiveCell.Value = DateSerial(2026, 3, 18) のように日付型で書き込む。表示形式は NumberFormat で制御する。

3. DateSerialの月オーバーフローを知らず、翌月の日付が表示されない

原因: DateSerial(2026, 13, 1) は「13月1日」ではなくエラーになると思いがちだが、実際はVBAが自動で 2027/1/1 に繰り上げてくれる。逆に DateSerial(2026, 0, 1)2025/12/1 になる。この仕様を知らないと不要なIf文を書いてしまう。

対策: DateSerialは月のオーバーフロー/アンダーフローを自動処理する。DateSerial(y, m + 1, 0) で月末日が取れるのもこの仕様のおかげ。

4. Weekday関数の戻り値がずれてカレンダーの曜日が合わない

原因: Weekday(日付) は既定で日曜=1、月曜=2 … 土曜=7を返す。月曜始まりカレンダーを作る場合にこの値をそのまま使うと、曜日が1日ずれる。

対策: 日曜始まりなら Weekday(日付, vbSunday)、月曜始まりなら Weekday(日付, vbMonday) を使う。第2引数を明示して「何曜日を1とするか」を固定する。

5. vbModelessを使わないとフォーム表示中にセルを選択できない

原因: frmCalendar.Show だけで表示すると、既定でモーダル表示(フォームを閉じるまでシート操作不可)になる。日付を入力したいセルを先に選んでからフォームを開く必要がある。

対策: frmCalendar.Show vbModeless でモードレス表示にすれば、フォームを開いたままセルを選択できる。UserFormの表示方法の詳細は ユーザーフォームで本格的な入力画面を作る方法 を参照。

VBAのカレンダーフォームで日付が文字列として入力されるときの対処法

「カレンダーで選んだ日付がVLOOKUPで一致しない」という場合、原因はセルに日付型ではなく文字列として入力されていること。書き込み時に CDate() で日付型に変換してからセルに代入する。

VBAのUserFormでカレンダー表示中にセルが選べないときの対処法

「フォーム表示中にシートのセルをクリックできない」という場合、原因はフォームをモーダル表示しているから。UserForm1.Show vbModeless でモードレス表示にすればフォームを開いたままセルを選択できる。

FAQ

Q1: 月曜始まりのカレンダーにできる?

できる。以下の2箇所を変更する:

  1. 曜日ヘッダーを Array("月", "火", "水", "木", "金", "土", "日") に変更
  2. Weekday(firstDate, vbSunday)Weekday(firstDate, vbMonday) に変更

Q2: 土日だけでなく祝日にも色を付けたい

祝日リストをシートまたは配列で管理し、DrawCalendar内で日付を照合して色を変えればよい。祝日・営業日の判定方法は 祝日・土日を除いた営業日を自動計算する方法 に詳しい。

Q3: セルをダブルクリックしたら自動でカレンダーが開くようにしたい

実務版の「セルのダブルクリックでカレンダーを開く」コードをシートモジュールに貼り付ける。Target.Column の値を変えれば、任意の列でのみカレンダーを表示できる。

Q4: カレンダーから入力した日付の形式を変えたい(例: yyyy年mm月dd日)

ActiveCell.NumberFormat の値を変更する。例: ActiveCell.NumberFormat = "yyyy""年""mm""月""dd""日""" 。日付型の値はそのままで、表示形式だけが変わる。

Q5: 複数のセルに連続で日付を入力したい(フォームを閉じずに)

ClickDay の最後の Me.Hide を削除すれば、日付を入力してもフォームが閉じない。次に入力したいセルをクリックしてから、再度カレンダーの日付をクリックすればよい。

まとめ

  • カレンダーフォーム: UserFormにラベルとボタンを配置して日付選択UIを作れる
  • 外部コントロール不要: Label + CommandButton だけで作るため、どのPCでも動く
  • DateSerial: DateSerial(y, m+1, 0) で月末日を取得。月のオーバーフローも自動処理
  • 日付型で書き込み: CDate() で日付型にしてから書き込む。文字列で書くとVLOOKUPが壊れる
  • vbModeless: フォーム表示中にセルを選択するにはモードレス表示が必要

関連記事

次にやりたくなること

コメント

タイトルとURLをコピーしました