はじめに
今年のゴールデンウィークは大型連休となりましたが、天皇の即位の日の5月1日が休みとなったためです。
東京オリンピックの年(2020年)は、「海の日」は7月23日に、「体育の日(スポーツの日)」は7月24日に、「山の日」は8月10日になります。
そこで今回はEXCEL VBAを利用してオリジナルカレンダーを作成してみました。
子供やペット、自動車やアニメキャラなどで自分だけのカレンダーを作ってみてはいかがでしょうか?
EXCEL2013(64ビット)で動作確認
オリジナルカレンダーVer2はこちら
ダウンロード
今回のカレンダーは、A4縦サイズです。上段に好みの写真やイラストを表示できます。
1か月単位で出力できるので必要な分だけ印刷して利用できます。
ちょこっと解説
カレンダーシート
メインのシートです。このシートでカレンダーを生成し印刷できます。
画像シート
月ごとに画像ファイルを設定しておけます。
画像は、カレンダーEXCELと同じフォルダか下位のフォルダに格納して利用します。
画像形式は、イメージコントロールで読み込み可能なもので、BMP・JPG・GIFなどが指定可能です。残念ながらPNGは取り扱えません。
祝日シート
祝日シートは、内閣府のホームページからCSVをダウンロードしてきたものをそのまま貼り付けております。
特定の日を休みにしたい場合は、このシートに追加して利用できます。
休日シート
休日シートは、毎年繰り返しの休みを定義します。会社の正月休みなどがそれにあたります。
VBA
メイン処理
- カレンダー(文字部分)をクリアします。
- 入力された年と月を取得し、カレンダーにセットします。
- 画像を取得しイメージコントロールにセットします。この時画像をズームするかしないかをセットします。
- 祝日・休日を配列で取得します。
- カレンダーの日付部分をセットします。この時、祝日・休日配列と該当する日は文字を赤色にセットします。
''' カレンダーセット Private Sub cmdSetCalender_Click() On Error GoTo Err_Handler Dim nen As Integer Dim tuki As Integer Dim hiduke() As String Dim i As Integer Dim j As Integer Dim r As Integer '' 行 Dim c As Integer '' 列 Dim picFile As String Dim holiday() As String Dim userHoliday() As String ' カレンダークリア Call ClearCalender ' 年、月取得 nen = Me.Cells(4, 9).Value tuki = Me.Cells(4, 10).Value ' 年、月セット Me.Cells(12, 1).Value = nen Me.Cells(12, 4).Value = tuki ' 画像 picFile = GetPicture(tuki) If Me.chkZoom Then imgPic.PictureSizeMode = fmPictureSizeModeZoom Else imgPic.PictureSizeMode = fmPictureSizeModeClip End If imgPic.Picture = LoadPicture(picFile) ' 祝日取得 holiday = GetHoliday(nen, tuki) ' 休日取得 userHoliday = GetUserHoliday(tuki) ' 日セット '' 日付配列セット hiduke = SetDate(nen, tuki) r = 0 c = 0 For i = 15 To 20 For j = 1 To 7 Me.Cells(i, j).Value = hiduke(r, c) If hiduke(r, c) <> "" Then If holiday(CInt(hiduke(r, c))) <> "" Then Me.Cells(i, j).Font.Color = RGB(255, 0, 0) End If If userHoliday(CInt(hiduke(r, c))) <> "" Then Me.Cells(i, j).Font.Color = RGB(255, 0, 0) End If End If c = c + 1 Next j r = r + 1 c = 0 Next i Exit Sub Err_Handler: MsgBox Err.Description, vbExclamation End Sub
カレンダークリア処理
- 対象のセルをクリアします。この時、文字色を黒色にセットし、左端の日曜日は赤色に右端の土曜日は青色にします。
''' カレンダークリア Private Sub ClearCalender() On Error GoTo Err_Handler Dim i As Integer Dim j As Integer Dim lngColor As Long ' 年 Me.Cells(12, 1).Value = "" ' 月 Me.Cells(12, 4).Value = "" ' 画像 imgPic.Picture = Nothing ' 日 For i = 15 To 20 For j = 1 To 7 Me.Cells(i, j).Value = "" Me.Cells(i, j).Font.Color = RGB(0, 0, 0) If j = 1 Then Me.Cells(i, j).Font.Color = RGB(255, 0, 0) If j = 7 Then Me.Cells(i, j).Font.Color = RGB(0, 112, 192) Me.Cells(i, j).Font.TintAndShade = 0 Next j Next i Exit Sub Err_Handler: MsgBox Err.Description, vbExclamation End Sub
日付配列セット処理
- 入力された年月の1日の曜日を取得します。
- 月末の日付を取得します。開始日に1か月足して1日引きます。
- 2次元配列を用意し、第1週は取得した曜日にあわせてセットします。
''' 日付配列セット Private Function SetDate(y As Integer, m As Integer) On Error GoTo Err_Handler Dim d(5, 6) As String Dim startDate As Date Dim endD As Integer Dim youbi As Integer ' 1:日曜日 ~ 7:土曜日 Dim i As Integer Dim j As Integer Dim dd As Integer ' 日付配列初期化 For i = 0 To 5 For j = 0 To 6 d(i, j) = "" Next j Next i ' 開始曜日取得 startDate = CDate(y & "/" & m & "/1") youbi = Weekday(startDate) ' 月末日付取得 endD = CInt(Format(DateAdd("d", -1, DateAdd("m", 1, startDate)), "d")) dd = 1 For i = 0 To 5 If dd > endD Then Exit For For j = 0 To 6 If i = 0 And j < youbi - 1 Then Else If dd > endD Then Exit For d(i, j) = Trim(CStr(dd)) dd = dd + 1 End If Next j Next i SetDate = d Exit Function Err_Handler: MsgBox Err.Description, vbExclamation End Function
画像ファイル名取得処理
- 画像シートの該当月をSELECT文で取得します。
- 取得したファイル名に、カレンダー.xlsmのフォルダパスを結合させます。
''' 画像ファイル名取得 Private Function GetPicture(m As Integer) On Error GoTo Err_Handler Dim fname As String Dim cn As ADODB.Connection Dim rs As ADODB.Recordset Dim xl_file As String Dim sql As String Dim curRow As Integer 'ツールメニューの参照設定' ' Microsoft ActiveX Data Objects 2.8 Library' 'チェック' xl_file = ThisWorkbook.FullName '他のブックを指定しても良い' Set cn = New ADODB.Connection cn.Provider = "MSDASQL" #If Win64 Then ' 64bit cn.ConnectionString = "Driver={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};" & "DBQ=" & xl_file & "; ReadOnly=False;" #Else ' 32bit cn.ConnectionString = "Driver={Microsoft Excel Driver (*.xls)};" & "DBQ=" & xl_file & "; ReadOnly=False;" #End If cn.Open Set rs = New ADODB.Recordset sql = "SELECT 画像ファイル名 FROM [画像$]" _ & " WHERE" _ & " 月 = " & m rs.Open sql, cn, adOpenStatic fname = ThisWorkbook.Path & "\" & rs!画像ファイル名 rs.Close cn.Close Set rs = Nothing Set cn = Nothing GetPicture = fname Exit Function Err_Handler: MsgBox "画像取得 : " & Err.Description, vbExclamation On Error Resume Next rs.Close cn.Close Set rs = Nothing Set cn = Nothing End Function
祝日取得処理
- 祝日シートの該当月をSELECT文で取得します。
- 取得した休みの日付を添え字として配列に祝日名をセットします。
''' 祝日取得 Private Function GetHoliday(y As Integer, m As Integer) On Error GoTo Err_Handler Dim i As Integer Dim d(31) As String Dim cn As ADODB.Connection Dim rs As ADODB.Recordset Dim xl_file As String Dim sql As String Dim curRow As Integer Dim sYMD As Date Dim eYMD As Date 'ツールメニューの参照設定' ' Microsoft ActiveX Data Objects 2.8 Library' 'チェック' xl_file = ThisWorkbook.FullName '他のブックを指定しても良い' Set cn = New ADODB.Connection cn.Provider = "MSDASQL" #If Win64 Then ' 64bit cn.ConnectionString = "Driver={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};" & "DBQ=" & xl_file & "; ReadOnly=False;" #Else ' 32bit cn.ConnectionString = "Driver={Microsoft Excel Driver (*.xls)};" & "DBQ=" & xl_file & "; ReadOnly=False;" #End If cn.Open Set rs = New ADODB.Recordset sYMD = CDate(y & "/" & m & "/1") eYMD = DateAdd("d", -1, DateAdd("m", 1, sYMD)) sql = "SELECT 年月日, 祝日名 FROM [祝日$]" _ & " WHERE" _ & " 年月日 >= #" & sYMD & "# AND 年月日 <= #" & eYMD & "#" rs.Open sql, cn, adOpenStatic ' 祝日配列初期化 For i = 1 To 31 d(i) = "" Next i Do While Not rs.EOF d(Format(rs!年月日, "d")) = rs!祝日名 rs.MoveNext Loop rs.Close cn.Close Set rs = Nothing Set cn = Nothing GetHoliday = d Exit Function Err_Handler: MsgBox "祝日取得 : " & Err.Description, vbExclamation On Error Resume Next rs.Close cn.Close Set rs = Nothing Set cn = Nothing End Function
休日取得処理
- 休日シートの該当月をSELECT文で取得します。
- 取得した休みの日付を添え字として配列に祝日名をセットします。
Private Function GetUserHoliday(m As Integer) ''' ユーザ休日取得 On Error GoTo Err_Handler Dim i As Integer Dim d(31) As String Dim cn As ADODB.Connection Dim rs As ADODB.Recordset Dim xl_file As String Dim sql As String Dim curRow As Integer Dim sYMD As Date Dim eYMD As Date 'ツールメニューの参照設定' ' Microsoft ActiveX Data Objects 2.8 Library' 'チェック' xl_file = ThisWorkbook.FullName '他のブックを指定しても良い' Set cn = New ADODB.Connection cn.Provider = "MSDASQL" #If Win64 Then ' 64bit cn.ConnectionString = "Driver={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};" & "DBQ=" & xl_file & "; ReadOnly=False;" #Else ' 32bit cn.ConnectionString = "Driver={Microsoft Excel Driver (*.xls)};" & "DBQ=" & xl_file & "; ReadOnly=False;" #End If cn.Open Set rs = New ADODB.Recordset sql = "SELECT 日, 休日名 FROM [休日$]" _ & " WHERE" _ & " 月 = " & m rs.Open sql, cn, adOpenStatic ' 祝日配列初期化 For i = 1 To 31 d(i) = "" Next i Do While Not rs.EOF d(rs!日) = rs!休日名 rs.MoveNext Loop rs.Close cn.Close Set rs = Nothing Set cn = Nothing GetUserHoliday = d Exit Function Err_Handler: MsgBox "休日取得 : " & Err.Description, vbExclamation On Error Resume Next rs.Close cn.Close Set rs = Nothing Set cn = Nothing End Function
終わりに
画像ファイル名の取得、祝日・休日の取得処理でSQLを利用していますが、SELECT文を渡すとレコードセットが返されるように共通化できますね。。。
画像シートはわざわざSELECTしなくても対応できますが、今後の拡張(複数の画像セットをあらかじめ用意しておくなど)を考えるとこのままでも良いのかなと。