毎年の勤務スケジュール作成をマクロで自動化！ChatGPTさん、作成お願いします！

## 目的
毎年、弊社は年度の初めに年間の勤務スケジュールを提出しないといけないのですが、年間のスケジュールを作成するのに多くの時間がかかり、またミスも多くて修正にも時間がかかるという問題がありました。そこで、これらの問題を解決するために、ChatGPTさんの協力を得て、スケジュールを自動的に作成するExcelマクロを作成しました。

## 概要（作成条件）
このマクロは、毎年のスケジュールを自動で作成し、以下のような機能を備えています：

毎月のスケジュールを自動生成：各月の開始日（21日）から翌月の終了日（20日）までのスケジュールを生成します。
土日を自動判定：土日は自動的に「休日」としてマークされます。
有給休暇の自動配置：年間で最大10日（最低7日）の有給休暇をランダムに配置します。
連続休日の自動配置：お盆、年末年始、5月に5日間の連続休日を配置します。さらに、ランダムな日に追加で連続休日を配置し、年間で合計20日になるようにします。
年間の総勤務時間を計算：各月の総勤務時間と年間の総勤務時間を計算します。
サマリシートの作成：各月の休日数、有給数、勤務時間、連続休日数をまとめたサマリシートを作成します。

## ChatGPTさんを使って得られたメリット
今回、ChatGPTさんを活用することで以下のようなメリットを得ることができました。

工数の削減

手動でスケジュールを作成する場合、ミスを防ぐための確認作業や修正作業が多く発生し、膨大な時間がかかっていました。
ChatGPTさんの助けを借りることで、短時間で正確なマクロを作成することができ、作業時間を大幅に削減できました。

時間の有効活用

自動化により、スケジュール作成に費やしていた時間を他の重要な業務や家族サービス（自宅の大掃除と大洗濯大会）に充てることができました。

安心と信頼

ChatGPTさんによるサポートで、スケジュール作成のミスを大幅に減らし、信頼性の高いスケジュールを迅速に作成することができました。


## ChatGPTさんにコード作成を依頼するコツ

ChatGPTさんにご依頼する際には、以下の点に注意するとより効果的です：

具体的なエラーの指摘

デバッグ中に見つかったエラーは、具体的に指摘するようにしましょう。例えば、「日付配列の初期化で型の不一致エラーが発生しています」といった具体的な説明が有効です。

修正の指示を明確に

「このエラーを修正してほしい」といった具体的な指示を与えましょう。また、「この部分を修正することで他の部分も影響を受ける可能性があるので、全体を確認して修正してください」といった指示を追加すると、エラーの再発を防ぐことができます。
全体の確認を促す：

修正が一部分に留まらず、全体のコードに影響を与える可能性があることを意識して、ChatGPTさんに全体を確認させるように指示します。これにより、修正によって生じる新たなエラーを未然に防ぐことができます。

## 結論
このマクロを使用することで、毎年のスケジュール作成の手間とミスを大幅に削減することができました。ChatGPTさんの協力を得ることで、短期間で効率的なマクロを作成することができ、大変助かりました。皆さんもぜひ試してみてください。

## 画面
マクロを起動するスイッチです。初期状態ではこれ一つのみで、
押せば勝手にその年のスケジュールを作成します。
※今後、使うならいつに長期休暇/有給を取りたいから、ここでだとか、
　この月は休み多めだとかのパラメータをセルに入れて、それを元に
　作成するように出来たらいいなと。
![スイッチ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820956/215d5cc7-e18d-f85c-5000-88737009eab2.png)
年間の月ごとの総勤務時間、休みの日数などのサマリ画面
![サマリ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820956/6b3d35c3-ac0e-14ea-870b-c6aeff2498e3.png)


長期休暇がない通常月の感じ
![a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820956/736b8332-ce8b-779f-1375-7e3969f05573.png)

長期休暇がある月※年末（31日、30日は勤務、元日からは長期休暇）
![年末年始.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820956/31687c81-a79f-7672-1036-fd59f3fb6c8f.png)




## コード
<details>
<summary>VBAコード</summary>

```VBA
Sub CreateJapaneseWorkSchedule()
    Application.ScreenUpdating = False
    Application.Calculation = xlCalculationManual
　　Dim ws As Worksheet
    Dim summarySheet As Worksheet
    Dim monthNames As Variant
    Dim dayNames As Variant
    Dim i As Integer, j As Integer, k As Integer
    Dim startDate As Date, endDate As Date
    Dim totalHours As Double
    Dim daysOffCount As Integer
    Dim paidLeaveCount As Integer
    Dim consecutiveDaysOffCount As Integer
    Dim fiscalYear As Integer
    Dim existingSheet As Worksheet
    Dim summaryPosition As Integer
    Dim annualTotalHours As Double
    Dim paidLeaveDates() As Date
    Dim consecutiveLeaveDates() As Date
    Dim rndMonth As Integer, rndDay As Integer
    Dim rndDate As Date
    Dim totalPaidLeaveDays As Integer
    Dim totalConsecutiveLeaveDays As Integer
    Dim data() As Variant
    Dim currentDate As Date
    Dim rowIndex As Integer
    
    ' Initialize arrays
    monthNames = Array("7月", "8月", "9月", "10月", "11月", "12月", "1月", "2月", "3月", "4月", "5月", "6月")
    dayNames = Array("日曜日", "月曜日", "火曜日", "水曜日", "木曜日", "金曜日", "土曜日")
    fiscalYear = 2024
    
    ' Initialize paid leave dates
    ReDim paidLeaveDates(6)
    paidLeaveDates(0) = DateSerial(fiscalYear, 6, 24)
    paidLeaveDates(1) = DateSerial(fiscalYear, 7, 15)
    paidLeaveDates(2) = DateSerial(fiscalYear, 9, 9)
    paidLeaveDates(3) = DateSerial(fiscalYear, 10, 20)
    paidLeaveDates(4) = DateSerial(fiscalYear, 11, 13)
    paidLeaveDates(5) = DateSerial(fiscalYear + 1, 1, 5)
    paidLeaveDates(6) = DateSerial(fiscalYear + 1, 3, 4)
 
    ' Initialize consecutive leave dates
    ReDim consecutiveLeaveDates(2)
    consecutiveLeaveDates(0) = DateSerial(fiscalYear, 8, 12)
    consecutiveLeaveDates(1) = DateSerial(fiscalYear + 1, 1, 1)
    consecutiveLeaveDates(2) = DateSerial(fiscalYear + 1, 5, 1)

 ' Add 5 random consecutive leave days to fill up to 20 days
    totalConsecutiveLeaveDays = 15
    Do While totalConsecutiveLeaveDays < 20
        rndMonth = Int((12) * Rnd) + 6
        rndDay = Int((28) * Rnd) + 1
        rndDate = DateSerial(fiscalYear, rndMonth, rndDay)
        If rndDate > DateSerial(fiscalYear, 6, 20) And rndDate < DateSerial(fiscalYear + 1, 6, 21) Then
            ReDim Preserve consecutiveLeaveDates(UBound(consecutiveLeaveDates) + 1)
            consecutiveLeaveDates(UBound(consecutiveLeaveDates)) = rndDate
            totalConsecutiveLeaveDays = totalConsecutiveLeaveDays + 5
        End If
    Loop

' Add up to 3 more paid leave days to make a total of 10
    totalPaidLeaveDays = 7
    Do While totalPaidLeaveDays < 10
        rndMonth = Int((12) * Rnd) + 6
        rndDay = Int((28) * Rnd) + 1
        rndDate = DateSerial(fiscalYear, rndMonth, rndDay)
        If rndDate > DateSerial(fiscalYear, 6, 20) And rndDate < DateSerial(fiscalYear + 1, 6, 21) Then
            ReDim Preserve paidLeaveDates(UBound(paidLeaveDates) + 1)
            paidLeaveDates(UBound(paidLeaveDates)) = rndDate
            totalPaidLeaveDays = totalPaidLeaveDays + 1
        End If
    Loop

' Create or clear Summary Sheet
    On Error Resume Next
    Set summarySheet = ThisWorkbook.Sheets("Summary")
    On Error GoTo 0
    If summarySheet Is Nothing Then
        Set summarySheet = ThisWorkbook.Sheets.Add(After:=ThisWorkbook.Sheets(1))
        summarySheet.Name = "Summary"
    Else
        summarySheet.Cells.Clear
    End If
    
' Set up summary sheet headers
    summarySheet.Cells(1, 1).Value = "月度"
    summarySheet.Cells(1, 2).Value = "休日数"
    summarySheet.Cells(1, 3).Value = "有給数"
    summarySheet.Cells(1, 4).Value = "勤務時間"
    summarySheet.Cells(1, 5).Value = "連続休日数"
    annualTotalHours = 0
    For i = 0 To 11
    
    ' Calculate the start and end dates for each month period
        startDate = DateSerial(fiscalYear, 6 + i, 21)
        endDate = DateSerial(fiscalYear, 7 + i, 20)
     
    ' Adjust for the year change
        If Month(startDate) > 12 Then
            startDate = DateSerial(fiscalYear + 1, Month(startDate) - 12, 21)
        End If
        If Month(endDate) > 12 Then
            endDate = DateSerial(fiscalYear + 1, Month(endDate) - 12, 20)
        End If
     
     ' Create or clear existing worksheet for each month
        On Error Resume Next
        Set existingSheet = ThisWorkbook.Sheets(fiscalYear & "年度" & monthNames(i) & "度")
        On Error GoTo 0
        If Not existingSheet Is Nothing Then
            existingSheet.Cells.Clear
            Set ws = existingSheet
        Else
            Set ws = ThisWorkbook.Sheets.Add(After:=ThisWorkbook.Sheets(ThisWorkbook.Sheets.Count))
            ws.Name = fiscalYear & "年度" & monthNames(i) & "度"
        End If
       
     ' Initialize data array
        ReDim data(DateDiff("d", startDate, endDate), 7)
        totalHours = 0
        daysOffCount = 0
        paidLeaveCount = 0
        consecutiveDaysOffCount = 0
    　
      ' Determine maximum monthly hours
        Select Case Month(endDate)
            Case 1, 3, 5, 7, 8, 10, 12
                maxMonthlyHours = 177
            Case 4, 6, 9, 11
                maxMonthlyHours = 171
            Case 2
                maxMonthlyHours = 160
        End Select
        
        ' Fill in the dates and days of the week
        For j = 0 To DateDiff("d", startDate, endDate)
            currentDate = startDate + j
            rowIndex = j + 3
            data(j, 0) = Month(currentDate)
            data(j, 1) = Day(currentDate)
            data(j, 2) = dayNames(Weekday(currentDate, vbSunday) - 1)
    　  
        ' Initialize attributes
            data(j, 7) = ""
        
        ' Check if the day is a weekend
            If data(j, 2) = "土曜日" Or data(j, 2) = "日曜日" Then
                data(j, 7) = "休日"
                daysOffCount = daysOffCount + 1
            End If
　      
        ' Check if the day is a paid leave
            For k = LBound(paidLeaveDates) To UBound(paidLeaveDates)
                If currentDate = paidLeaveDates(k) Then
                    data(j, 7) = "有給"
                    paidLeaveCount = paidLeaveCount + 1
                    Exit For
                End If
            Next k
        
        ' Check if the day is a consecutive leave
            For k = LBound(consecutiveLeaveDates) To UBound(consecutiveLeaveDates)
                If currentDate >= consecutiveLeaveDates(k) And currentDate < consecutiveLeaveDates(k) + 5 Then
                    data(j, 7) = "連続休日"
                    consecutiveDaysOffCount = consecutiveDaysOffCount + 1
                    Exit For
                End If
            Next k
    
        ' Check if the day is a working day
            If data(j, 7) = "" Then
                data(j, 3) = "9:00"
                data(j, 4) = "19:00"
                data(j, 5) = "12:00 - 13:00"
                data(j, 6) = 8 ' 9:00 to 19:00 with 1 hour break
                totalHours = totalHours + 8
            Else
                data(j, 3) = ""
                data(j, 4) = ""
                data(j, 5) = ""
                data(j, 6) = 0
            End If
        Next j
    
    ' Write data to worksheet
        ws.Cells(3, 1).Resize(UBound(data, 1) + 1, UBound(data, 2) + 1).Value = data
    
    ' Autofit columns for better visibility
        ws.Columns("A:H").AutoFit
    
    ' Set total monthly hours
        ws.Cells(1, 2).Value = totalHours & " 時間"
       
    ' Add to summary sheet
        summarySheet.Cells(i + 2, 1).Value = ws.Name
        summarySheet.Cells(i + 2, 2).Value = daysOffCount
        summarySheet.Cells(i + 2, 3).Value = paidLeaveCount
        summarySheet.Cells(i + 2, 4).Value = totalHours
        summarySheet.Cells(i + 2, 5).Value = consecutiveDaysOffCount
        
    ' Update annual total hours
        annualTotalHours = annualTotalHours + totalHours
    Next i
    
    ' Add annual total hours to summary sheet
    summarySheet.Cells(15, 1).Value = "年間合計勤務時間"
    summarySheet.Cells(15, 2).Value = annualTotalHours & " 時間"
    Application.ScreenUpdating = True
    Application.Calculation = xlCalculationAutomatic
    
    MsgBox "勤務表が正常に作成されました！"
End Sub