この記事でわかること
- 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 のままだとマクロが保存できない。
- 「ファイル」→「名前を付けて保存」
- ファイルの種類を「Excelマクロ有効ブック (*.xlsm)」に変更
- 保存
—
手順(コピペ → 実行まで約10分)
Step 1: VBE(コードを書く画面)を開く
Excelで Alt + F11 を押す。
Step 2: UserFormを追加する
- VBEのメニュー →「挿入」→「ユーザーフォーム」
- 空のフォーム(UserForm1)が追加される
- プロパティウィンドウで以下を変更する:
(Name):frmCalendarCaption:日付入力カレンダーWidth:260(※コード実行時に自動調整されるため、おおよその値でOK)Height:240(※同上)
Step 3: UserFormのコードウィンドウを開く
- フォーム(frmCalendar)をダブルクリック
- コードウィンドウが開く
- 既存のコード(
Private Sub UserForm_Click()等)があれば全て消す
Step 4: UserFormモジュールにコードを貼り付ける
下の「コード(最小版)」または「コード(実務版)」をそのままコピペする。
Step 5: 標準モジュールにフォーム表示コードを貼り付ける
- VBEのメニュー →「挿入」→「標準モジュール」
- 下のフォーム表示コードを貼り付ける
Step 6: 実行する
- 日付を入力したいセルをクリックして選択
Alt + F8→ShowCalendarを選んで「実行」- カレンダーフォームが表示される
- 日付をクリックすると、選択中のセルに日付が入る
ボタンに割り当てれば毎回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箇所を変更する:
- 曜日ヘッダーを
Array("月", "火", "水", "木", "金", "土", "日")に変更 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: フォーム表示中にセルを選択するにはモードレス表示が必要
関連記事
- 入力フォーム(UserForm)で手入力ミスを防ぐ方法 — UserFormの基本操作
- ユーザーフォームで本格的な入力画面を作る方法 — UserFormの発展形
- 祝日・土日を除いた営業日を自動計算する方法 — カレンダーに祝日判定を追加したい場合
- 2つの日付の差分・加算・比較を計算する方法 — DateSerial等の日付関数の詳細
- 日付・曜日の判定で月末処理を自動化 — 日付判定の基本
—
次にやりたくなること
- 祝日・土日を除いた営業日を自動計算する方法: カレンダーに祝日判定を追加して、営業日だけ色分けしたい場合
- ユーザーフォームで本格的な入力画面を作る方法: カレンダーだけでなく、テキストボックスやコンボボックスを組み合わせた本格的な入力画面を作りたい場合
- 入力規則(ドロップダウンリスト)をVBAで一括設定する方法: 日付以外の入力項目もドロップダウンで制限して、入力ミスを防ぎたい場合


コメント