【AI × Excel VBA】勤務シフト表で週と月の労働時間を考慮する方法(配列+辞書利用)【再利用コード集】

アフィリエイト広告を利用しています。

勤務シフト表において、週の労働時間の制御と月の労働時間の確認をするためのVBAコードです。

勤務シフト表のヘッダの日付をもとに、週(日〜土)単位および月単位で勤務時間を自動集計します。

週管理では、月の前後にまたがる週も含めて1週間単位で厳密に管理し、シフト割当時に週40時間を超えないよう制御します。

一方、月合計は確認用として集計のみを行います。本来、月で制御したいのは標準勤務時間ではなく残業時間実績であるため、標準勤務時間の取得・確認は参考です。

シート同士を直接参照せず、配列と辞書を中心に設計することで、処理を高速化しています。

コピー利用や、AI による再生成・参考用途を想定しています。


Information
  • 配列
    複数の値を、順序を保ったまままとめて扱うためのデータ構造です。Excel VBA では、セルを 1 件ずつ操作するよりも高速に処理できるため、処理の高速化を目的としてよく使われます。
  • 辞書(Dictionary)
    複数の値を キーと値の組み合わせで管理できるデータ構造です。Excel VBA では、値の検索や判定を高速に行えるため、条件分岐や割当可否の判定などでよく使われます。

勤務シフト表で週と月の労働時間を考慮する方法

シート構成

ThisWorkbook内に、以下の5つのシートが構成されています。

【担務表(シフト表)】

【シフト割当表】

シフト割当表の画像

【シフト曜日条件表】

シフト曜日条件表の画像

【勤務時間表】

勤務時間表の画像

【祝日】

勤務時間表から標準時間を取得し、勤務時間の管理に使用するしくみです。

コード

依存関係ツリー

各プロシージャーの依存関係は以下のようになっています。

[ Dom_CreateCalendar ]
└─ AddShukujisuToTanmuWs(担務表ヘッダに祝日情報を反映して書き戻す)
  ├─ GetShukujitsuTbl(祝日シートを配列で取得 ※同一モジュール内)
  │ └─ [ Util_GetArray ]
  │   ├─ GetUsedRangeArray(使用範囲を配列で取得)
  │   └─ DebugPrintArraySize(配列サイズをデバッグ出力)
  │
  └─ AddShukujitsuToTanmuHeaderTbl(担務表ヘッダ配列へ祝日名を反映 ※同一モジュール内)

└─ GetTaishoKikan(基準月の対象期間列を取得 ※同一モジュール内)
[ Dom_CreateTanmuWs ]
└─ CreateTanmuWs(曜日条件に合うセルのみ担当者を割当+略称を表示)
  ├─ [ Util_GetArray ]
  │ ├─ GetUsedRangeArray(使用範囲を配列で取得)
  │ └─ DebugPrintArraySize(配列サイズをデバッグ出力)
  │
  ├─ [ Dom_CreateDic ]
  │ ├─ CreateShiftWariateDic(シフト→可スタッフ辞書)
  │ ├─ CreateYoubiJoukenDic(シフト→曜日条件辞書)
  │ ├─ CreateTanmuJikanDic(シフト→勤務時間辞書)
  │ ├─ CreateStaffShuKinmuJikanDic(スタッフ×週→勤務時間合計)
  │ └─ GetWeekStartDateFromDate(日付→週開始日を返す)
  │
  ├─ [ Dom_CreateCalendar ]
  │ └─ GetTaishoKikan(対象期間列を取得)
  │
  ├─ GetYoubiKeyFromTanmuHeader(祝日優先で「祝」/曜日を返す ※同一モジュール内)
  │
  ├─ [ Util_ShuffleElements ]
  │ └─ ShuffleArrayByFisherYates(候補者シャッフル)
  │
  └─ [ Pres_WorkTimeSummary ]
   └─ WriteWeekWorkTimeSummaryToTanmuWs(週合計勤務時間を出力)
[ Pres_WorkTimeSummary ]
└─ WriteWeekWorkTimeSummaryToTanmuWs(週合計勤務時間を担務表下部へ出力)
  ├─ [ Util_GetArray ]
  │ └─ GetUsedRangeArray(使用範囲を配列で取得)
  │
  ├─ [ Dom_CreateCalendar ]
  │ └─ GetTaishoKikan(対象期間列を取得)
  │
  ├─ [ Dom_CreateDic ]
  │ ├─ CreateTanmuJikanDic(シフト→勤務時間辞書)
  │ └─ CreateStaffShuKinmuJikanDic(スタッフ×週→勤務時間合計)
  │
  └─ GetRyakushoList(スタッフ略称一覧を取得 ※同一モジュール内)

└─ WriteMonthWorkTimeSummaryToTanmuWs(月合計勤務時間を担務表下部へ出力)
  ├─ [ Util_GetArray ]
  │ └─ GetUsedRangeArray(使用範囲を配列で取得)
  │
  ├─ [ Dom_CreateDic ]
  │ ├─ CreateTanmuJikanDic(シフト→勤務時間辞書)
  │ └─ CreateStaffMonthKinmuJikanDic(スタッフ→月合計勤務時間)
  │
  └─ GetRyakushoList(スタッフ略称一覧を取得 ※同一モジュール内)

各モジュール内のプロシージャ

次に、各モジュール内のプロシージャーを示します。

【モジュール: Dom_CreateCalendar】

Option Explicit


Public Sub AddShukujisuToTanmuWs()

    ' Description
    '   担務表ヘッダ配列に祝日情報を反映し、シートへ書き戻す。
    '
    ' Arguments
    '   (none)
    '
    ' Returns
    '   (none)
    '
    ' Dependency Tree
    '   AddShukujisuToTanmuWs
    '     ├─ GetShukujitsuTbl
    '     │   └─ GetUsedRangeArray
    '     └─ AddShukujitsuToTanmuHeaderTbl


    ' 担務表シート取得
    Dim tanmu_ws As Worksheet
    Set tanmu_ws = ThisWorkbook.Worksheets("担務表")

    ' 担務表ヘッダー配列取得
    Dim tanmu_header_tbl As Variant
    tanmu_header_tbl = tanmu_ws.Range("A1:AL4").Value
    
    ' 祝日配列取得
    Dim shukujitsu_tbl As Variant
    shukujitsu_tbl = GetShukujitsuTbl()

    ' ガード(祝日配列が取得できない場合)
    If IsEmpty(shukujitsu_tbl) Then
        MsgBox "shukujitsu_tbl が取得できません。", vbExclamation
        Exit Sub
    End If

    ' 祝日反映(配列更新)
    Call AddShukujitsuToTanmuHeaderTbl(tanmu_header_tbl, shukujitsu_tbl)

    ' シートへ書き戻し
    tanmu_ws.Range( _
        tanmu_ws.Cells(1, 1), _
        tanmu_ws.Cells( _
            UBound(tanmu_header_tbl, 1), _
            UBound(tanmu_header_tbl, 2) _
        ) _
    ).Value2 = tanmu_header_tbl

End Sub

Private Function GetShukujitsuTbl() As Variant

    ' Description
    '   「祝日」シートの「A1:B最終行」までを、配列として取得する
    '
    ' Dependency Tree
    '   GetShukujitsuTbl
    '     ├─ GetUsedRangeArray
    '     └─ DebugPrintArraySize


    ' 祝日シートを取得
    Dim ws As Worksheet            ' 祝日シート
    Set ws = ThisWorkbook.Worksheets("祝日")

    ' 対象ワークシートの使用範囲を配列で取得(Util_GetArray 呼び出し)
    Dim shukujitsu_tbl As Variant     ' 祝日を格納する配列
    shukujitsu_tbl = GetUsedRangeArray(ws)
    Call DebugPrintArraySize(shukujitsu_tbl, "祝日シート配列")

    ' Return: 配列を返却
    GetShukujitsuTbl = shukujitsu_tbl

End Function

Private Sub AddShukujitsuToTanmuHeaderTbl( _
    ByRef tanmu_header_tbl As Variant, _
    ByVal shukujitsu_tbl As Variant _
)

    ' Description
    '   祝日配列(shukujitsu_tbl)に一致する日付が担務表ヘッダ配列(tanmu_header_tbl)の
    '   カレンダー範囲に存在した場合、該当列の祝日行セルを更新する。
    '
    ' Arguments
    '   tanmu_header_tbl : 担務表ヘッダを格納した2次元配列(更新対象)
    '   shukujitsu_tbl   : 祝日シートを格納した2次元配列(参照のみ)
    '
    ' Returns
    '   (none)
    '
    ' Dependency Tree
    '   (none)

    
    ' 固定仕様(担務表ヘッダ)
    Const DATE_ROW As Long = 1                ' 日付行(担務表ヘッダ内)
    Const SHUKUJITSU_ROW As Long = 3          ' 祝日書き込み行
    Const CALENDAR_START_COL As Long = 2      ' B
    Const CALENDAR_END_COL As Long = 32       ' AF

    ' 祝日配列の最終行を取得
    Dim shukujitsu_last_row As Long
    shukujitsu_last_row = UBound(shukujitsu_tbl, 1)

    ' 祝日配列を走査(2行目~最終行:1行目はヘッダ)
    Dim row As Long
    For row = 2 To shukujitsu_last_row
    
        ' 祝日日付を取得(空行・日付以外はスキップ)
        If Not IsDate(shukujitsu_tbl(row, 1)) Then GoTo ContinueShukujitsuRow
        Dim shukujitsu_date As Date
        shukujitsu_date = shukujitsu_tbl(row, 1)
    
        ' 祝日名を取得(空行はスキップ)
        Dim shukujitsu_name As String
        shukujitsu_name = CStr(shukujitsu_tbl(row, 2))
        If Len(shukujitsu_name) = 0 Then GoTo ContinueShukujitsuRow
    
        ' 担務表ヘッダの日付行を走査
        Dim col As Long
        For col = CALENDAR_START_COL To CALENDAR_END_COL
    
            ' 日付が一致した列に祝日名をセット
            If tanmu_header_tbl(DATE_ROW, col) = shukujitsu_date Then
                tanmu_header_tbl(SHUKUJITSU_ROW, col) = _
                    Left(shukujitsu_name, 2)
                Exit For
            End If
    
        Next col
    
ContinueShukujitsuRow:
    Next row

End Sub


Public Sub GetTaishoKikan( _
    ByVal tanmu_tbl As Variant, _
    ByRef start_col As Long, _
    ByRef end_col As Long _
)

    ' Description
    '   担務表ヘッダ(日付行)を参照し、
    '   基準月の「月初を含む週の日曜」列を start_col、
    '   基準月の「月末を含む週の土曜」列を end_col として返す。
    '
    ' Arguments
    '   tanmu_tbl  : 担務表シートを格納した配列
    '   start_col : 対象期間の開始列(返却)
    '   end_col   : 対象期間の終了列(返却)
    '
    ' Returns
    '   (none)
    '
    ' Dependency Tree
    '   (none)


    ' 固定仕様(担務表ヘッダ)
    Const DATE_ROW As Long = 1
    Const DATE_SEARCH_START_COL As Long = 2   ' B列(日付探索の開始)
    Const ASSIGN_START_COL As Long = 9        ' I列(基準月決定に使う)


    ' 初期化
    start_col = 0
    end_col = 0

    ' ガード(エラーメッセージは上位側で表示する)
    If IsEmpty(tanmu_tbl) Or (Not IsArray(tanmu_tbl)) Then
        Exit Sub
    End If

    ' 基準日(I列の日付)
    Dim base_date As Date
    base_date = CDate(tanmu_tbl(DATE_ROW, ASSIGN_START_COL))

    ' 基準月の月初・月末を算出
    Dim base_year As Long
    base_year = Year(base_date)

    Dim base_month As Long
    base_month = Month(base_date)

    Dim month_start As Date
    month_start = DateSerial(base_year, base_month, 1)

    Dim month_end As Date
    month_end = DateSerial(base_year, base_month + 1, 0)


    ' 対象期間(月初を含む週の日曜、月末を含む週の土曜)を算出
    Dim period_start As Date
    period_start = month_start - (Weekday(month_start, vbSunday) - 1)

    Dim period_end As Date
    period_end = month_end + (7 - Weekday(month_end, vbSunday))


    ' 日付行を走査し、対象期間の開始列・終了列を特定
    '   担務表(配列)の列方向を走査
    Dim date_col As Long
    For date_col = DATE_SEARCH_START_COL To UBound(tanmu_tbl, 2)
    
        ' 日付を取得
        Dim current_date As Date
        current_date = tanmu_tbl(DATE_ROW, date_col)
    
        ' 対象期間の開始日と一致する列を取得
        If start_col = 0 Then
            If current_date = period_start Then start_col = date_col
        End If
    
        ' 対象期間の終了日と一致する列を取得
        If end_col = 0 Then
            If current_date = period_end Then end_col = date_col
        End If
    
        ' 両方見つかったら探索終了
        If start_col <> 0 And end_col <> 0 Then Exit For
    
    Next date_col


    ' ガード(エラーメッセージは上位側で表示する)
    If start_col = 0 Or end_col = 0 Then
        Exit Sub
    End If

End Sub

【モジュール: Dom_CreateDic】

Option Explicit


Public Function CreateShiftWariateDic() As Scripting.Dictionary

    ' Description
    '   シフト割当表シートを参照し、シフト名→可(〇)スタッフ辞書を作成して返す。
    '   外側辞書:Key=シフト名、value=内側辞書(可スタッフ辞書)
    '
    ' Arguments
    '   (None)
    '
    ' Returns
    '   Dictionary
    '     key   : shift_name (String)
    '     value : Dictionary
    '               key   : staff_ryakusho (String)
    '               value : True (Boolean)
    '
    ' Dependency Tree
    '   CreateShiftWariateDic
    '     ├─ GetUsedRangeArray
    '     └─ DebugPrintArraySize
    '
    ' References
    '   Microsoft Scripting Runtime


    ' シートの取得
    Dim ws As Worksheet
    Set ws = ThisWorkbook.Worksheets("シフト割当表")

    ' シートの対象範囲を配列として取得
    Dim staff_shift_kahi_tbl As Variant
    staff_shift_kahi_tbl = GetUsedRangeArray(ws)
    Call DebugPrintArraySize(staff_shift_kahi_tbl, "シフト割当表配列")

    ' 固定仕様(シフト割当表)
    Const staff_ryakusho_col  As Long = 2   ' 略称列(B列)
    Const SHIFT_START_COL     As Long = 3   ' シフト開始列(C列)
    Const HEADER_ROW          As Long = 1   ' ヘッダ行
    Const data_start_row      As Long = 2   ' データ開始行

    ' ガード(空配列)
    If IsEmpty(staff_shift_kahi_tbl) Then
        Set CreateShiftWariateDic = Nothing
        Exit Function
    End If

    ' 外側辞書:シフト名 → 可スタッフ辞書 の対応を保持する辞書
    Dim staff_shift_kahi_dic As Scripting.Dictionary
    Set staff_shift_kahi_dic = New Scripting.Dictionary

    ' 配列を列方向に走査
    Dim shift_col As Long
    For shift_col = SHIFT_START_COL To UBound(staff_shift_kahi_tbl, 2)

        ' シフト名を取得(空欄はスキップ)
        Dim shift_name As String
        shift_name = Trim$(CStr(staff_shift_kahi_tbl(HEADER_ROW, shift_col)))
        If Len(shift_name) = 0 Then GoTo NextShiftCol

        ' 外側辞書に「シフト名」が未登録の場合
        If Not staff_shift_kahi_dic.Exists(shift_name) Then

            ' 内側辞書(可スタッフ辞書)を新規作成
            Dim assignable_staff_dic As Scripting.Dictionary
            Set assignable_staff_dic = New Scripting.Dictionary

            ' 「シフト名」をキー、「可スタッフ辞書」をバリューとして外側辞書に登録
            staff_shift_kahi_dic.Add shift_name, assignable_staff_dic

        End If

        ' 内側辞書にスタッフを登録
        Dim staff_row As Long
        For staff_row = data_start_row To UBound(staff_shift_kahi_tbl, 1)

            ' 略称を取得(空欄は対象外)
            Dim staff_ryakusho As String
            staff_ryakusho = Trim$(CStr(staff_shift_kahi_tbl(staff_row, staff_ryakusho_col)))
            If Len(staff_ryakusho) = 0 Then GoTo NextStaffRow

            ' クロスポイントの値を取得(○がなければ対象外)
            Dim cell_val As String
            cell_val = Trim$(CStr(staff_shift_kahi_tbl(staff_row, shift_col)))
            If InStr(1, cell_val, "○", vbTextCompare) = 0 Then GoTo NextStaffRow

            ' 内側辞書に未登録の場合、略称を追加
            If Not staff_shift_kahi_dic(shift_name).Exists(staff_ryakusho) Then
                staff_shift_kahi_dic(shift_name).Add staff_ryakusho, True
            End If

NextStaffRow:
        Next staff_row

NextShiftCol:
    Next shift_col

    ' シフト割当表辞書を返す
    Set CreateShiftWariateDic = staff_shift_kahi_dic

End Function


Public Function CreateYoubiJoukenDic() As Scripting.Dictionary

    ' Description
    '   シフト曜日条件表シートを参照し、シフト名→曜日条件辞書を作成して返す。
    '   外側辞書:Key=シフト名、value=内側辞書(曜日条件辞書)
    '
    ' Arguments
    '   (None)
    '
    ' Returns
    '   Dictionary
    '     key   : shift_name (String)
    '     value : Dictionary
    '               key   : youbi_key (String)  "日","月","火","水","木","金","土","祝"
    '               value : True (Boolean)
    '
    ' Dependency Tree
    '   CreateYoubiJoukenDic
    '     ├─ GetUsedRangeArray
    '     └─ DebugPrintArraySize
    '
    ' References
    '   Microsoft Scripting Runtime


    ' シートの取得
    Dim ws As Worksheet
    Set ws = ThisWorkbook.Worksheets("シフト曜日条件表")

    ' シートの対象範囲を配列として取得
    Dim youbi_jouken_tbl As Variant
    youbi_jouken_tbl = GetUsedRangeArray(ws)
    Call DebugPrintArraySize(youbi_jouken_tbl, "シフト曜日条件表配列")

    ' ガード(空配列)
    If IsEmpty(youbi_jouken_tbl) Then
        Set CreateYoubiJoukenDic = Nothing
        Exit Function
    End If


    ' 固定仕様(シフト曜日条件表)
    Const SHIFT_NAME_COL   As Long = 1   ' シフト名列
    Const YOU_BI_START_COL As Long = 2   ' 曜日開始列
    Const HEADER_ROW       As Long = 1   ' ヘッダ行
    Const data_start_row   As Long = 2   ' データ開始行(シフト行)

    ' 外側辞書:シフト名 → 曜日条件辞書 の対応を保持する辞書
    Dim youbi_jouken_dic As Scripting.Dictionary
    Set youbi_jouken_dic = New Scripting.Dictionary


    ' 行方向(シフト)を走査し、内側辞書を作成
    '--------------------------------------------------------------------------
    Dim shift_row As Long
    For shift_row = data_start_row To UBound(youbi_jouken_tbl, 1)

        ' シフト名を取得(空欄はスキップ)
        Dim shift_name As String
        shift_name = Trim$(CStr(youbi_jouken_tbl(shift_row, SHIFT_NAME_COL)))
        If Len(shift_name) = 0 Then GoTo NextShiftRow

        ' 内側辞書(曜日条件辞書)を新規作成
        Dim youbi_dic As Scripting.Dictionary
        Set youbi_dic = New Scripting.Dictionary

        ' 列方向(曜日)を走査し、○の曜日のみ内側辞書に登録
        '----------------------------------------------------------------------
        Dim youbi_col As Long
        For youbi_col = YOU_BI_START_COL To UBound(youbi_jouken_tbl, 2)

            ' 曜日キーを取得(空欄はスキップ)
            Dim header_val As String
            header_val = Trim$(CStr(youbi_jouken_tbl(HEADER_ROW, youbi_col)))
            If Len(header_val) = 0 Then GoTo NextYoubiCol

            Dim youbi_key As String
            If header_val = "祝日" Then
                youbi_key = "祝"
            Else
                youbi_key = header_val
            End If

            ' クロスポイントの値を取得(○/〇がなければ対象外)
            Dim cell_val As String
            cell_val = Trim$(CStr(youbi_jouken_tbl(shift_row, youbi_col)))

            If InStr(1, cell_val, "○", vbTextCompare) = 0 _
                And InStr(1, cell_val, "〇", vbTextCompare) = 0 Then _
                GoTo NextYoubiCol

            ' 内側辞書に未登録の場合、曜日キーを追加
            If Not youbi_dic.Exists(youbi_key) Then
                youbi_dic.Add youbi_key, True
            End If

NextYoubiCol:
        Next youbi_col

        ' 外側辞書に登録(内側辞書)
        youbi_jouken_dic.Add shift_name, youbi_dic

NextShiftRow:
    Next shift_row


    ' Return
    Set CreateYoubiJoukenDic = youbi_jouken_dic

End Function


Public Function CreateTanmuJikanDic() As Scripting.Dictionary

    ' Description
    '   「勤務時間表」シートを参照し、
    '   シフト名(担務名)→勤務時間 の辞書を作成して返す。
    '
    ' Arguments
    '   (None)
    '
    ' Returns
    '   Dictionary
    '     key   : shift_name (String)
    '     value : work_hours (Double)
    '
    ' Dependency Tree
    '   CreateTanmuJikanDic
    '     ├─ GetUsedRangeArray
    '     └─ DebugPrintArraySize
    '
    ' References
    '   Microsoft Scripting Runtime


    ' シートの取得
    Dim ws As Worksheet
    Set ws = ThisWorkbook.Worksheets("勤務時間表")

    ' 使用範囲を配列で取得
    Dim work_time_tbl As Variant
    work_time_tbl = GetUsedRangeArray(ws)
    Call DebugPrintArraySize(work_time_tbl, "勤務時間表配列")

    ' ガード(空配列)
    If IsEmpty(work_time_tbl) Then
        Set CreateTanmuJikanDic = Nothing
        Exit Function
    End If

    ' 固定仕様(勤務時間表)
    Const SHIFT_NAME_COL As Long = 1
    Const WORK_HOURS_COL As Long = 2
    Const data_start_row As Long = 2

    ' 辞書を作成
    Dim tanmu_jikan_dic As Scripting.Dictionary
    Set tanmu_jikan_dic = New Scripting.Dictionary

    ' 行方向に走査して登録
    Dim row As Long
    For row = data_start_row To UBound(work_time_tbl, 1)

        Dim shift_name As String
        shift_name = Trim$(CStr(work_time_tbl(row, SHIFT_NAME_COL)))
        If Len(shift_name) = 0 Then GoTo NextRow

        Dim work_hours_val As Variant
        work_hours_val = work_time_tbl(row, WORK_HOURS_COL)
        If Not IsNumeric(work_hours_val) Then GoTo NextRow

        If Not tanmu_jikan_dic.Exists(shift_name) Then
            tanmu_jikan_dic.Add shift_name, CDbl(work_hours_val)
        End If

NextRow:
    Next row

    ' Return
    Set CreateTanmuJikanDic = tanmu_jikan_dic

End Function


Public Function CreateStaffShuKinmuJikanDic( _
    ByVal tanmu_tbl As Variant, _
    ByVal start_col As Long, _
    ByVal end_col As Long, _
    ByVal tanmu_jikan_dic As Scripting.Dictionary _
) As Scripting.Dictionary

    ' Description
    '   担務表(tanmu_tbl)を走査し、スタッフ×週(日曜基準)の勤務時間合計を集計した
    '   2段辞書を作成して返す。
    '
    '   staff_shu_kinmujikan_dic(staff)(week_start_date) = hours
    '
    ' Arguments
    '   tanmu_tbl       : 担務表シートを格納した配列
    '   start_col       : 週管理の対象開始列
    '   end_col         : 週管理の対象終了列
    '   tanmu_jikan_dic : シフト名(担務名)→勤務時間 の辞書
    '
    ' Returns
    '   Dictionary
    '
    ' Dependency Tree
    '   CreateStaffShuKinmuJikanDic
    '     └─ GetWeekStartDateFromDate


    ' 固定仕様(担務表)
    Const TANMU_SHIFT_NAME_COL As Long = 1   ' A列
    Const TANMU_DATE_ROW As Long = 1         ' 1行目
    Const TANMU_DATA_START_ROW As Long = 4   ' 4行目


    ' Return 用辞書
    Dim staff_shu_kinmujikan_dic As Scripting.Dictionary
    Set staff_shu_kinmujikan_dic = New Scripting.Dictionary


    ' 対象列×担務行を走査して集計
    '   担務表の列方向を走査
    Dim date_col As Long
    For date_col = start_col To end_col

        ' 日付取得
        Dim work_date As Date
        work_date = CDate(tanmu_tbl(TANMU_DATE_ROW, date_col))

        ' 週キー(日曜)算出
        Dim week_start_date As Date
        week_start_date = GetWeekStartDateFromDate(work_date)
        
        '  担務表(配列)の行方向を走査
        Dim tanmu_row As Long
        For tanmu_row = TANMU_DATA_START_ROW To UBound(tanmu_tbl, 1)

            ' シフト名(担務名)を取得
            Dim shift_name As String
            shift_name = Trim$(CStr(tanmu_tbl(tanmu_row, TANMU_SHIFT_NAME_COL)))
            If Len(shift_name) = 0 Then GoTo NextTanmuRow

            ' 勤務時間が定義されていないシフトは集計対象外
            If Not tanmu_jikan_dic.Exists(shift_name) Then GoTo NextTanmuRow
            
            ' シフト(担務)の標準勤務時間を取得
            Dim shift_hours As Double
            shift_hours = CDbl(tanmu_jikan_dic(shift_name))

            ' 担当者(略称)を取得(空欄は対象外)
            Dim staff As String
            staff = Trim$(CStr(tanmu_tbl(tanmu_row, date_col)))
            If Len(staff) = 0 Then GoTo NextTanmuRow

            ' 外側辞書:スタッフ未登録なら内側辞書を作成
            If Not staff_shu_kinmujikan_dic.Exists(staff) Then
                Dim inner_dic As Scripting.Dictionary
                Set inner_dic = New Scripting.Dictionary
                staff_shu_kinmujikan_dic.Add staff, inner_dic
            End If

            ' 内側辞書:スタッフ×週(日曜)単位のキーが未登録なら初期化
            '   staff_shu_kinmujikan_dic(staff)(week_start_date)
            '   の週合計を 0時間で作成する
            If Not staff_shu_kinmujikan_dic(staff).Exists(week_start_date) Then
                staff_shu_kinmujikan_dic(staff).Add week_start_date, 0#
            End If

            ' 週合計へ勤務時間を加算
            '   staff_shu_kinmujikan_dic(staff)(week_start_date)
            '   に当該シフト時間を加える
            staff_shu_kinmujikan_dic(staff)(week_start_date) = _
                CDbl(staff_shu_kinmujikan_dic(staff)(week_start_date)) + shift_hours

NextTanmuRow:
        Next tanmu_row

    Next date_col


    ' Return
    Set CreateStaffShuKinmuJikanDic = staff_shu_kinmujikan_dic

End Function


Public Function GetWeekStartDateFromDate(ByVal work_date As Date) As Date

    ' Description
    '   指定日が属する週の「日曜の日付」を返す。
    '
    ' Arguments
    '   work_date : 任意の日付
    '
    ' Returns
    '   Date
    '
    ' Dependency Tree
    '   (none)


    GetWeekStartDateFromDate = work_date - (Weekday(work_date, vbSunday) - 1)

End Function


Public Function CreateStaffMonthKinmuJikanDic( _
    ByVal tanmu_tbl As Variant, _
    ByVal target_year As Long, _
    ByVal target_month As Long, _
    ByVal tanmu_jikan_dic As Scripting.Dictionary _
) As Scripting.Dictionary

    ' Description
    '   担務表(tanmu_tbl)を走査し、対象月(target_year/target_month)の
    '   スタッフ別 月合計勤務時間辞書を作成して返す。
    '
    '   staff_month_kinmujikan_dic(staff) = hours
    '
    ' Arguments
    '   tanmu_tbl       : 担務表シートを格納した配列
    '   target_year     : 対象年
    '   target_month    : 対象月
    '   tanmu_jikan_dic : シフト名→勤務時間 の辞書
    '
    ' Returns
    '   Dictionary
    '
    ' Dependency Tree
    '   (none)


    ' 固定仕様(担務表)
    Const TANMU_SHIFT_NAME_COL As Long = 1   ' A列
    Const TANMU_DATE_ROW As Long = 1         ' 1行目
    Const TANMU_DATA_START_ROW As Long = 4   ' 4行目
    Const DATE_SEARCH_START_COL As Long = 2  ' B列(日付開始)


    ' Return 用辞書
    Dim staff_month_kinmujikan_dic As Scripting.Dictionary
    Set staff_month_kinmujikan_dic = New Scripting.Dictionary


    ' 日付行を走査し、対象月の列のみ集計
    Dim date_col As Long
    For date_col = DATE_SEARCH_START_COL To UBound(tanmu_tbl, 2)

        Dim date_text As String
        date_text = Trim$(CStr(tanmu_tbl(TANMU_DATE_ROW, date_col)))
        If Len(date_text) = 0 Then GoTo NextDateCol

        If Not IsDate(tanmu_tbl(TANMU_DATE_ROW, date_col)) Then GoTo NextDateCol

        Dim work_date As Date
        work_date = CDate(tanmu_tbl(TANMU_DATE_ROW, date_col))

        If Year(work_date) <> target_year Or Month(work_date) <> target_month Then
            GoTo NextDateCol
        End If


        ' 担務行を走査
        Dim tanmu_row As Long
        For tanmu_row = TANMU_DATA_START_ROW To UBound(tanmu_tbl, 1)

            Dim shift_name As String
            shift_name = Trim$(CStr(tanmu_tbl(tanmu_row, TANMU_SHIFT_NAME_COL)))
            If Len(shift_name) = 0 Then GoTo NextTanmuRow

            If Not tanmu_jikan_dic.Exists(shift_name) Then GoTo NextTanmuRow

            Dim staff As String
            staff = Trim$(CStr(tanmu_tbl(tanmu_row, date_col)))
            If Len(staff) = 0 Then GoTo NextTanmuRow

            Dim shift_hours As Double
            shift_hours = CDbl(tanmu_jikan_dic(shift_name))

            If Not staff_month_kinmujikan_dic.Exists(staff) Then
                staff_month_kinmujikan_dic.Add staff, 0#
            End If

            staff_month_kinmujikan_dic(staff) = _
                CDbl(staff_month_kinmujikan_dic(staff)) + shift_hours

NextTanmuRow:
        Next tanmu_row

NextDateCol:
    Next date_col


    ' Return
    Set CreateStaffMonthKinmuJikanDic = staff_month_kinmujikan_dic

End Function



' 辞書の中身をデバッグ表示するプロシージャ群
'------------------------------------------------------------------------------
Public Sub DebugPrintShiftWariateDic()

    ' シフト→可スタッフ辞書を作成(辞書が取得できなかった場合は終了)
    Dim staff_shift_kahi_dic As Scripting.Dictionary
    Set staff_shift_kahi_dic = CreateShiftWariateDic()
    If staff_shift_kahi_dic Is Nothing Then Exit Sub

    ' 辞書の中身を確認(Debug.Print)
    Call DebugPrintNestedDic(staff_shift_kahi_dic, "シフト→可スタッフ辞書")

End Sub

Public Sub DebugPrintYoubiJoukenDic()
    
    ' Dependency Tree
    '   DebugPrintYoubiJoukenDic
    '     ├─ CreateYoubiJoukenDic
    '     └─ DebugPrintNestedDic

    ' シフト→曜日条件辞書を作成(辞書が取得できなかった場合は終了)
    Dim youbi_jouken_dic As Scripting.Dictionary
    Set youbi_jouken_dic = CreateYoubiJoukenDic()
    If youbi_jouken_dic Is Nothing Then Exit Sub

    ' 辞書の中身を確認(Debug.Print)
    Call DebugPrintNestedDic(youbi_jouken_dic, "シフト→曜日条件辞書")

End Sub

Public Sub DebugPrintTanmuJikanDic()

    ' シフト→勤務時間辞書を作成(辞書が取得できなかった場合は終了)
    Dim tanmu_jikan_dic As Scripting.Dictionary
    Set tanmu_jikan_dic = CreateTanmuJikanDic()
    If tanmu_jikan_dic Is Nothing Then Exit Sub

    ' 辞書の中身を確認(Debug.Print)
    Debug.Print "シフト→勤務時間辞書 : count=" & tanmu_jikan_dic.Count

    Dim shift_name As Variant
    For Each shift_name In tanmu_jikan_dic.Keys
        Debug.Print CStr(shift_name) & " : " & CDbl(tanmu_jikan_dic(shift_name))
    Next shift_name

End Sub

Public Sub DebugPrintCreateStaffShuKinmuJikanDic()

    ' Description
    '   担務表を読み込み、対象期間を取得し、週合計辞書を作成して Debug.Print に出力する。
    '
    ' Arguments
    '   (none)
    '
    ' Returns
    '   (none)
    '
    ' Dependency Tree
    '   TestCreateStaffShuKinmuJikanDic
    '     ├─ GetUsedRangeArray
    '     ├─ GetTaishoKikan
    '     ├─ CreateTanmuJikanDic
    '     └─ CreateStaffShuKinmuJikanDic


    ' 担務表配列取得
    Dim tanmu_ws As Worksheet
    Set tanmu_ws = ThisWorkbook.Worksheets("担務表")

    Dim tanmu_tbl As Variant
    tanmu_tbl = GetUsedRangeArray(tanmu_ws)

    ' 対象期間列(週管理対象)取得
    Dim start_col As Long
    Dim end_col As Long
    Call GetTaishoKikan(tanmu_tbl, start_col, end_col)

    ' 勤務時間辞書取得
    Dim tanmu_jikan_dic As Scripting.Dictionary
    Set tanmu_jikan_dic = CreateTanmuJikanDic()

    ' 週合計辞書作成
    Dim staff_shu_kinmujikan_dic As Scripting.Dictionary
    Set staff_shu_kinmujikan_dic = CreateStaffShuKinmuJikanDic( _
        tanmu_tbl, _
        start_col, _
        end_col, _
        tanmu_jikan_dic _
    )

    ' 出力(Debug.Print)
    Debug.Print "=== staff_shu_kinmujikan_dic ==="
    Debug.Print "start_col=" & start_col & " / end_col=" & end_col
    Debug.Print "staff_count=" & staff_shu_kinmujikan_dic.Count

    Dim staff As Variant
    For Each staff In staff_shu_kinmujikan_dic.Keys

        Debug.Print "staff=" & CStr(staff)

        Dim week_dic As Scripting.Dictionary
        Set week_dic = staff_shu_kinmujikan_dic(staff)

        Dim week_start_date As Variant
        For Each week_start_date In week_dic.Keys
            Debug.Print "  week_start=" & Format$(CDate(week_start_date), "yyyy/mm/dd") _
                        & " hours=" & CDbl(week_dic(week_start_date))
        Next week_start_date

    Next staff

End Sub


' ネストした辞書の中身を表示する汎用プロシージャ
'------------------------------------------------------------------------------
Public Sub DebugPrintNestedDic(ByVal outer_dic As Scripting.Dictionary, ByVal label As String)

    ' Description
    '   外側辞書の value が Dictionary である 2 段辞書を Debug.Print で出力する。
    '
    ' Arguments
    '   outer_dic : 外側辞書(value は Scripting.Dictionary を想定)
    '   label     : デバッグ出力用の識別子
    '
    ' Returns
    '   (none)
    '
    ' Dependency Tree
    '   DebugPrintNestedDic
    '     (none)


    ' ガード
    If outer_dic Is Nothing Then
        Debug.Print label & " : outer_dic is Nothing"
        Exit Sub
    End If


    ' 辞書の中身を確認(Debug.Print)
    '--------------------------------------------------------------------------
    Debug.Print label & " : count=" & outer_dic.Count

    Dim outer_key As Variant
    For Each outer_key In outer_dic.Keys

        Debug.Print outer_key

        ' 内側辞書を取得(辞書でなければスキップ)
        Dim inner_dic As Scripting.Dictionary
        On Error Resume Next
        Set inner_dic = outer_dic(outer_key)
        On Error GoTo 0
        If inner_dic Is Nothing Then GoTo NextOuterKey

        ' 内側辞書のキーを出力
        Dim inner_key As Variant
        For Each inner_key In inner_dic.Keys
            Debug.Print "  "; inner_key
        Next inner_key

NextOuterKey:
    Next outer_key

End Sub

【モジュール: Dom_CreateTanmuWs】

Option Explicit


Public Sub CreateTanmuWs()

    ' Description
    '   シフト割当表から作成した「シフト名→可スタッフ辞書」を参照し、
    '   担務表の各日付×各シフトの未割当セルへ担当者名を割り当てる。
    '   曜日条件表(○)に一致するセルのみ割り当てる。
    '   候補者はシャッフルし、先頭要素を採用する(追加制約は入れない)。
    '
    '   追加仕様:
    '   週40時間上限を超える候補者は除外し、割当後は週合計辞書を即更新する。
    '
    ' Arguments
    '   (None)
    '
    ' Returns
    '   なし
    '
    ' Dependency Tree
    '   CreateTanmuWs
    '     ├─ GetUsedRangeArray
    '     ├─ DebugPrintArraySize
    '     ├─ CreateShiftWariateDic
    '     ├─ CreateYoubiJoukenDic
    '     ├─ GetTaishoKikan
    '     ├─ CreateTanmuJikanDic
    '     ├─ CreateStaffShuKinmuJikanDic
    '     ├─ GetWeekStartDateFromDate
    '     ├─ GetYoubiKeyFromTanmuHeader
    '     └─ ShuffleArrayByFisherYates


    ' 固定仕様(担務表)
    Const TANMU_SHEET_NAME       As String = "担務表"
    Const TANMU_SHIFT_NAME_COL   As Long = 1   ' A列
    Const TANMU_DATE_ROW         As Long = 1   ' 1行目
    Const TANMU_DATA_START_ROW   As Long = 4   ' 4行目
    Const WEEK_LIMIT_HOURS       As Double = 40#


    ' 担務表・シフト割当辞書の取得
    '--------------------------------------------------------------------------
    ' 担務表シートの取得
    Dim ws As Worksheet
    Set ws = ThisWorkbook.Worksheets(TANMU_SHEET_NAME)

    ' 担務表配列の取得
    Dim tanmu_tbl As Variant
    tanmu_tbl = GetUsedRangeArray(ws)
    Call DebugPrintArraySize(tanmu_tbl, "担務表配列")
    If IsEmpty(tanmu_tbl) Then Exit Sub

    ' シフト割当辞書の取得
    Dim staff_shift_kahi_dic As Scripting.Dictionary
    Set staff_shift_kahi_dic = CreateShiftWariateDic()
    If staff_shift_kahi_dic Is Nothing Then Exit Sub

    ' 曜日条件辞書の取得
    Dim youbi_jouken_dic As Scripting.Dictionary
    Set youbi_jouken_dic = CreateYoubiJoukenDic()
    If youbi_jouken_dic Is Nothing Then Exit Sub

    ' 週管理の対象列を取得
    Dim start_col As Long
    Dim end_col As Long
    Call GetTaishoKikan(tanmu_tbl, start_col, end_col)
    If start_col <= 0 Or end_col <= 0 Or start_col > end_col Then
        MsgBox "対象期間の取得に失敗しました。I列の日付を確認してください。", vbExclamation
        Exit Sub
    End If

    ' 勤務時間辞書の取得
    Dim tanmu_jikan_dic As Scripting.Dictionary
    Set tanmu_jikan_dic = CreateTanmuJikanDic()
    If tanmu_jikan_dic Is Nothing Then Exit Sub

    ' 週合計辞書(初期集計)を作成
    Dim staff_shu_kinmujikan_dic As Scripting.Dictionary
    Set staff_shu_kinmujikan_dic = CreateStaffShuKinmuJikanDic( _
        tanmu_tbl, _
        start_col, _
        end_col, _
        tanmu_jikan_dic _
    )
    If staff_shu_kinmujikan_dic Is Nothing Then Exit Sub


    ' 割当処理(日付列×担務行を走査)
    '--------------------------------------------------------------------------
    Dim assign_count As Long
    assign_count = 0

    ' 担務表配列の列方向を走査(週管理の対象列のみ)
    Dim date_col As Long
    For date_col = start_col To end_col

        ' 日付セルが空の列はスキップ(列の終端対策)
        Dim date_val As String
        date_val = Trim$(CStr(tanmu_tbl(TANMU_DATE_ROW, date_col)))
        If Len(date_val) = 0 Then GoTo NextDateCol

        ' 日付取得
        Dim work_date As Date
        work_date = CDate(tanmu_tbl(TANMU_DATE_ROW, date_col))

        ' 週キー(日曜)算出
        Dim week_start_date As Date
        week_start_date = GetWeekStartDateFromDate(work_date)

        ' 曜日キーを取得(祝日優先)
        Dim youbi_key As String
        youbi_key = GetYoubiKeyFromTanmuHeader(tanmu_tbl, date_col)
        If Len(youbi_key) = 0 Then GoTo NextDateCol

        ' 担務表配列の行方向を走査
        Dim tanmu_row As Long
        For tanmu_row = TANMU_DATA_START_ROW To UBound(tanmu_tbl, 1)

            ' 担務表からシフト名を取得(空欄は対象外)
            Dim shift_name As String
            shift_name = Trim$(CStr(tanmu_tbl(tanmu_row, TANMU_SHIFT_NAME_COL)))
            If Len(shift_name) = 0 Then GoTo NextTanmuRow

            ' 曜日条件(○)に一致しないセルは割当対象外:
            '   現在のシフト名が曜日条件表に定義されていない場合
            If Not youbi_jouken_dic.Exists(shift_name) Then GoTo NextTanmuRow

            '   現在の曜日(または祝日)がシフト曜日条件に該当していない場合
            If Not youbi_jouken_dic(shift_name).Exists(youbi_key) Then GoTo NextTanmuRow

            ' 既に値が入っているセルは変更しない
            Dim cell_value As String
            cell_value = Trim$(CStr(tanmu_tbl(tanmu_row, date_col)))
            If Len(cell_value) > 0 Then GoTo NextTanmuRow

            ' シフト割当辞書にシフト名が存在しない場合はスキップ
            If Not staff_shift_kahi_dic.Exists(shift_name) Then GoTo NextTanmuRow

            ' 勤務時間が定義されていないシフトは割当対象外
            If Not tanmu_jikan_dic.Exists(shift_name) Then GoTo NextTanmuRow

            ' 対象シフトの標準勤務時間を取得
            Dim shift_hours As Double
            shift_hours = CDbl(tanmu_jikan_dic(shift_name))

            ' 対象シフトに割り当て可能なスタッフ辞書を取得(取得できない場合はスキップ)
            Dim assignable_staff_dic As Scripting.Dictionary
            Set assignable_staff_dic = staff_shift_kahi_dic(shift_name)
            If assignable_staff_dic Is Nothing Then GoTo NextTanmuRow

            ' 可スタッフが存在しない場合は割当対象外
            Dim staff_count As Long    ' 割り当て可能なスタッフの人数
            staff_count = assignable_staff_dic.Count
            If staff_count = 0 Then GoTo NextTanmuRow

            ' 可スタッフ辞書のキー(スタッフ略称一覧)を配列として取得(0始まり)
            Dim shift_assignable_staff As Variant
            shift_assignable_staff = assignable_staff_dic.Keys

            ' 週40h制御:条件を満たす候補者のみ配列に格納(1回ループで作成)
            Dim candidate_list() As Variant
            ReDim candidate_list(1 To (UBound(shift_assignable_staff) - LBound(shift_assignable_staff) + 1))

            Dim candidate_idx As Long
            candidate_idx = 0

            Dim key_idx As Long
            Dim candidate_staff As String
            Dim candidate_week_hours As Double

            For key_idx = LBound(shift_assignable_staff) To UBound(shift_assignable_staff)

                ' 候補者(スタッフ略称)を取得(空は除外)
                candidate_staff = Trim$(CStr(shift_assignable_staff(key_idx)))
                If Len(candidate_staff) = 0 Then GoTo NextKeyIdx

                ' 当該週の累計勤務時間を取得(未登録なら0時間)
                candidate_week_hours = 0#

                If staff_shu_kinmujikan_dic.Exists(candidate_staff) Then
                    If staff_shu_kinmujikan_dic(candidate_staff).Exists(week_start_date) Then
                        candidate_week_hours = CDbl(staff_shu_kinmujikan_dic(candidate_staff)(week_start_date))
                    End If
                End If

                ' 今回のシフト時間を加算しても週上限以内なら候補として格納
                If (candidate_week_hours + shift_hours) <= WEEK_LIMIT_HOURS Then
                    candidate_idx = candidate_idx + 1
                    candidate_list(candidate_idx) = candidate_staff
                End If

NextKeyIdx:
            Next key_idx

            ' 条件を満たす候補が0人なら割当しない
            If candidate_idx = 0 Then GoTo NextTanmuRow

            ' 候補者リスト配列を候補数に切り詰め
            If candidate_idx < UBound(candidate_list) Then
                ReDim Preserve candidate_list(1 To candidate_idx)
            End If

            ' 候補者をシャッフル
            Dim shuffled_list As Variant
            shuffled_list = ShuffleArrayByFisherYates(candidate_list)

            ' シャッフル後の先頭を採用
            Dim assigned_staff As String
            assigned_staff = Trim$(CStr(shuffled_list(1)))

            If Len(assigned_staff) > 0 Then

                ' 担務表配列に略称を書き込む
                tanmu_tbl(tanmu_row, date_col) = assigned_staff
                assign_count = assign_count + 1

                ' 週合計辞書を即更新
                If Not staff_shu_kinmujikan_dic.Exists(assigned_staff) Then
                    Dim inner_dic As Scripting.Dictionary
                    Set inner_dic = New Scripting.Dictionary
                    staff_shu_kinmujikan_dic.Add assigned_staff, inner_dic
                End If

                If Not staff_shu_kinmujikan_dic(assigned_staff).Exists(week_start_date) Then
                    staff_shu_kinmujikan_dic(assigned_staff).Add week_start_date, 0#
                End If

                staff_shu_kinmujikan_dic(assigned_staff)(week_start_date) = _
                    CDbl(staff_shu_kinmujikan_dic(assigned_staff)(week_start_date)) + shift_hours

            End If

NextTanmuRow:
        Next tanmu_row

NextDateCol:
    Next date_col


    ' 担務表シートに書き戻し
    '--------------------------------------------------------------------------
    ws.Range( _
        ws.Cells(1, 1), _
        ws.Cells(UBound(tanmu_tbl, 1), UBound(tanmu_tbl, 2)) _
    ).Value = tanmu_tbl

    Debug.Print "担務表 割当 件数 = " & assign_count

    ' 勤務時間情報をシート出力
    Call WriteWeekWorkTimeSummaryToTanmuWs

End Sub


Private Function GetYoubiKeyFromTanmuHeader( _
    ByVal tanmu_header_tbl As Variant, _
    ByVal target_col As Long _
) As String

    ' Description
    '   担務表ヘッダ配列の指定列から、曜日条件判定に使用するキー(曜日 or 祝)を返す。
    '   祝日行に値が入っている場合は曜日よりも祝日判定を優先し、「祝」を返す。
    '
    ' Arguments
    '   tanmu_header_tbl : 担務表ヘッダを格納した2次元配列
    '   target_col       : 対象列(担務表ヘッダ配列の列番号)
    '
    ' Returns
    '   String
    '     - 祝日行に値が入っている場合 : "祝"
    '     - それ以外の場合             : 曜日行の文字列(例:"月")
    '
    ' Dependency Tree
    '   GetYoubiKeyFromTanmuHeader
    '     (none)


    ' 固定仕様(担務表ヘッダ)
    Const YOUBI_ROW As Long = 2
    Const SHUKUJITSU_ROW As Long = 3

    ' 祝日優先:祝日行に値があれば「祝」
    Dim shukujitsu_val As String
    shukujitsu_val = Trim$(CStr(tanmu_header_tbl(SHUKUJITSU_ROW, target_col)))
    If Len(shukujitsu_val) > 0 Then
        GetYoubiKeyFromTanmuHeader = "祝"
        Exit Function
    End If

    ' 祝日でない場合:曜日行の値を返す
    GetYoubiKeyFromTanmuHeader = _
        Trim$(CStr(tanmu_header_tbl(YOUBI_ROW, target_col)))

End Function

【モジュール:Pres_WorkTimeSummary】

Option Explicit


Public Sub WriteWeekWorkTimeSummaryToTanmuWs()

    ' Description
    '   担務表の週合計勤務時間を集計し、担務表の下部に表形式で出力する。
    '   表の形は「行=スタッフ」「列=週(日曜始まり)」「値=週合計時間(hours)」とする。
    '
    ' Arguments
    '   (none)
    '
    ' Returns
    '   (none)
    '
    ' Dependency Tree
    '   WriteWeekWorkTimeSummaryToTanmuWs
    '     ├─ GetUsedRangeArray
    '     ├─ GetTaishoKikan
    '     ├─ CreateTanmuJikanDic
    '     ├─ CreateStaffShuKinmuJikanDic
    '     └─ GetRyakushoList


    ' 定数
    '--------------------------------------------------------------------------
    ' 固定仕様(シート名)
    Const TANMU_SHEET_NAME As String = "担務表"
    Const SHIFT_WARIATE_SHEET_NAME As String = "シフト割当表"

    ' 固定仕様(シフト割当表)
    Const SHIFT_WARIATE_DATA_START_ROW As Long = 2
    Const SHIFT_WARIATE_STAFF_RYAKUSHO_COL As Long = 2   ' B列

    
    ' 各種データ取得(シート / 配列 / 辞書)
    ' -------------------------------------------------------------------------
    ' 担務表配列取得
    Dim tanmu_ws As Worksheet
    Set tanmu_ws = ThisWorkbook.Worksheets(TANMU_SHEET_NAME)

    Dim tanmu_tbl As Variant
    tanmu_tbl = GetUsedRangeArray(tanmu_ws)
    
    If IsEmpty(tanmu_tbl) Then
        MsgBox "担務表にデータが存在しません。処理を中止します。", vbExclamation
        Exit Sub
    End If
    
    
    ' 担務表から対象期間を取得
    Dim start_col As Long
    Dim end_col As Long
    Call GetTaishoKikan(tanmu_tbl, start_col, end_col)
    
    If start_col <= 0 Or end_col <= 0 Or start_col > end_col Then
        MsgBox "対象期間の取得に失敗しました。I列の日付を確認してください。", _
        vbExclamation
        Exit Sub
    End If


    ' 各シフトの標準勤務時間辞書を取得
    Dim tanmu_jikan_dic As Scripting.Dictionary
    Set tanmu_jikan_dic = CreateTanmuJikanDic()
    
    If tanmu_jikan_dic Is Nothing Then
        MsgBox "勤務時間表から勤務時間辞書を取得できませんでした。" & _
               "勤務時間表の内容を確認してください。", _
               vbExclamation
        Exit Sub
    End If


    ' スタッフ略称一覧配列を取得(全スタッフ対象)
    Dim shift_wariate_ws As Worksheet
    Set shift_wariate_ws = ThisWorkbook.Worksheets(SHIFT_WARIATE_SHEET_NAME)

    Dim staff_list As Variant
    staff_list = GetRyakushoList( _
        shift_wariate_ws, _
        SHIFT_WARIATE_DATA_START_ROW, _
        SHIFT_WARIATE_STAFF_RYAKUSHO_COL _
    )
    
    If IsEmpty(staff_list) Then
        MsgBox "シフト割当表からスタッフ略称を取得できませんでした。" & _
               "略称列(B列)を確認してください。", _
               vbExclamation
        Exit Sub
    End If

    '各週の勤務時間合計を取得
    '--------------------------------------------------------------------------
    ' 週勤務時間合計辞書を作成(スタッフ×週→合計時間)
    ' 例)
    ' staff_shu_kinmujikan_dic
    ' │
    ' ├─ "山田"
    ' │    ├─ #2026/03/29# → 32
    ' │    ├─ #2026/04/05# → 40
    ' │    ├─ #2026/04/12# → 24
    ' │    ├─ #2026/04/19# → 40
    ' │    └─ #2026/04/26# → 16
    Dim staff_shu_kinmujikan_dic As Scripting.Dictionary
    Set staff_shu_kinmujikan_dic = CreateStaffShuKinmuJikanDic( _
        tanmu_tbl, _
        start_col, _
        end_col, _
        tanmu_jikan_dic _
    )
    
    
    ' 出力準備
    '--------------------------------------------------------------------------
    ' 週キー(日曜)一覧を作成(start_col から end_col を 7列刻み)
    ' ※「\」は整数除算(小数点以下を切り捨てる割り算)
    Dim week_count As Long
    week_count = ((end_col - start_col) \ 7) + 1

    Dim week_list() As Variant
    ReDim week_list(1 To week_count)

    Dim wk_idx As Long
    For wk_idx = 1 To week_count

        Dim date_col As Long
        date_col = start_col + (wk_idx - 1) * 7

        week_list(wk_idx) = CDate(tanmu_tbl(1, date_col))

    Next wk_idx


    ' 出力位置を決定(担務表A列最終行 + 3行:空白2行)
    Dim last_row As Long
    last_row = tanmu_ws.Cells(tanmu_ws.Rows.Count, 1).End(xlUp).row

    Dim output_start_row As Long
    output_start_row = last_row + 3


    ' スタッフ略称の件数を取得
    Dim staff_count As Long
    staff_count = UBound(staff_list)

    ' 出力用配列を作成し値を詰める(確認1行+ヘッダ1行+スタッフ行 / スタッフ列1+週列)
    ' ※ヘッダ行、確認行を含めるために +2
    Dim out_tbl() As Variant
    ReDim out_tbl(1 To (staff_count + 2), 1 To (week_count + 1))

    ' 確認行(1行目)
    out_tbl(1, 1) = "確認"
    
    ' ヘッダ行(2行目)
    out_tbl(2, 1) = "週合計"

    ' ヘッダ行に週開始日(日曜)を設定する
    For wk_idx = 1 To week_count
        out_tbl(2, wk_idx + 1) = CDate(week_list(wk_idx))
    Next wk_idx
    
    ' 辞書の中身を配列に詰め替え
    '   各スタッフを走査
    Dim staff_idx As Long
    For staff_idx = 1 To staff_count
    
        ' 現在処理中のスタッフ略称を取得
        Dim staff_ryakusho As String
        staff_ryakusho = CStr(staff_list(staff_idx))
    
        ' 行見出し(確認行+ヘッダ行分 +2)
        out_tbl(staff_idx + 2, 1) = staff_ryakusho
    
        ' 週合計辞書に当該スタッフが存在するか確認
        If staff_shu_kinmujikan_dic.Exists(staff_ryakusho) Then
    
            ' スタッフ別の週合計辞書を取得
            Dim inner_dic As Scripting.Dictionary
            Set inner_dic = staff_shu_kinmujikan_dic(staff_ryakusho)
    
            ' 各週ごとの合計時間を配列に設定
            For wk_idx = 1 To week_count
    
                ' 現在の週キー(日曜)を取得
                Dim week_key As Date
                week_key = CDate(week_list(wk_idx))
    
                ' 当該週のデータが存在する場合はその値を設定
                ' 存在しない場合は 0 を設定
                If inner_dic.Exists(week_key) Then
                    out_tbl(staff_idx + 2, wk_idx + 1) = CDbl(inner_dic(week_key))
                Else
                    out_tbl(staff_idx + 2, wk_idx + 1) = 0#
                End If
    
            Next wk_idx
    
        Else
    
            ' 週合計辞書に存在しないスタッフは全週 0 とする
            For wk_idx = 1 To week_count
                out_tbl(staff_idx + 2, wk_idx + 1) = 0#
            Next wk_idx
    
        End If
    
    Next staff_idx

    ' 出力範囲の設定
    '--------------------------------------------------------------------------
    ' 出力列設定
    Const OUTPUT_START_COL As Long = 9   ' I列

    ' 出力行 / 出力列 取得
    Dim out_last_row As Long
    out_last_row = output_start_row + UBound(out_tbl, 1) - 1

    Dim out_last_col As Long
    out_last_col = OUTPUT_START_COL + UBound(out_tbl, 2) - 1

    ' 出力範囲を取得
    Dim out_rng As Range
    Set out_rng = tanmu_ws.Range( _
        tanmu_ws.Cells(output_start_row, OUTPUT_START_COL), _
        tanmu_ws.Cells(out_last_row, out_last_col) _
    )


    ' 前回出力範囲のクリア(固定範囲)
    '---------------------------------------------------------------------------
    ' 週数は最大6週とし、固定範囲を毎回クリアする
    Const MAX_WEEK_COUNT As Long = 6
    
    Dim week_output_last_row As Long
    week_output_last_row = output_start_row + (staff_count + 1)   ' 確認+ヘッダ+スタッフ行
    
    Dim week_output_last_col As Long
    week_output_last_col = OUTPUT_START_COL + MAX_WEEK_COUNT      ' I列 + 6 = O列
    
    tanmu_ws.Range( _
        tanmu_ws.Cells(output_start_row, OUTPUT_START_COL), _
        tanmu_ws.Cells(week_output_last_row, week_output_last_col) _
    ).ClearContents
    
    tanmu_ws.Range( _
        tanmu_ws.Cells(output_start_row, OUTPUT_START_COL), _
        tanmu_ws.Cells(week_output_last_row, week_output_last_col) _
    ).NumberFormat = "General"

    
    ' シートへ書き込み
    '--------------------------------------------------------------------------
    ' 担務表へ一括書き込み
    out_rng.Value2 = out_tbl
    
    ' ヘッダ行(2行目)の週開始日だけ表示形式を変更
    out_rng.Offset(1, 1).Resize(1, week_count).NumberFormat = "m/d"
    
    ' スタッフ列(1列目)を左寄せ(全行)
    out_rng.Columns(1).HorizontalAlignment = xlLeft

    ' 勤務時間列(2列目以降)を右寄せ(ヘッダ行から下)
    ' ※確認行は除外するため高さは -1
    out_rng.Offset(1, 1).Resize(UBound(out_tbl, 1) - 1, week_count) _
        .HorizontalAlignment = xlRight

End Sub


Public Sub WriteMonthWorkTimeSummaryToTanmuWs()

    ' Description
    '   担務表の月合計勤務時間を集計し、担務表の下部に表形式で出力する。
    '   対象月は「担務表 I列(日付行)の月」とする。
    '   表の形は「行=スタッフ」「列=月合計(hours)」とする。
    '
    ' Arguments
    '   (none)
    '
    ' Returns
    '   (none)
    '
    ' Dependency Tree
    '   WriteMonthWorkTimeSummaryToTanmuWs
    '     ├─ GetUsedRangeArray
    '     ├─ CreateTanmuJikanDic
    '     ├─ GetRyakushoList
    '     └─ CreateStaffMonthKinmuJikanDic


    ' 固定値設定
    '--------------------------------------------------------------------------
    ' 固定仕様(シート名)
    Const TANMU_SHEET_NAME As String = "担務表"
    Const SHIFT_WARIATE_SHEET_NAME As String = "シフト割当表"

    ' 固定仕様(担務表)
    Const TANMU_DATE_ROW As Long = 1
    Const TARGET_DATE_COL As Long = 9          ' I列
    Const OUTPUT_START_COL As Long = 9         ' I列

    ' 固定仕様(シフト割当表)
    Const SHIFT_WARIATE_DATA_START_ROW As Long = 2
    Const SHIFT_WARIATE_STAFF_RYAKUSHO_COL As Long = 2   ' B列


    ' 各種データ取得
    '--------------------------------------------------------------------------
    ' 担務表配列取得
    Dim tanmu_ws As Worksheet
    Set tanmu_ws = ThisWorkbook.Worksheets(TANMU_SHEET_NAME)

    Dim tanmu_tbl As Variant
    tanmu_tbl = GetUsedRangeArray(tanmu_ws)

    If IsEmpty(tanmu_tbl) Then
        MsgBox "担務表にデータが存在しません。処理を中止します。", vbExclamation
        Exit Sub
    End If


    ' 対象月の取得(I列の日付)
    Dim target_date_val As Variant
    target_date_val = tanmu_tbl(TANMU_DATE_ROW, TARGET_DATE_COL)

    If Not IsDate(target_date_val) Then
        MsgBox "担務表 I列(1行目)の日付が不正です。", vbExclamation
        Exit Sub
    End If

    Dim target_date As Date
    target_date = CDate(target_date_val)

    Dim target_year As Long
    target_year = Year(target_date)

    Dim target_month As Long
    target_month = Month(target_date)


    ' 各シフトの標準勤務時間辞書を取得
    Dim tanmu_jikan_dic As Scripting.Dictionary
    Set tanmu_jikan_dic = CreateTanmuJikanDic()

    If tanmu_jikan_dic Is Nothing Then
        MsgBox "勤務時間表から勤務時間辞書を取得できませんでした。" & _
               "勤務時間表の内容を確認してください。", _
               vbExclamation
        Exit Sub
    End If


    ' スタッフ略称一覧配列を取得(全スタッフ対象)
    Dim shift_wariate_ws As Worksheet
    Set shift_wariate_ws = ThisWorkbook.Worksheets(SHIFT_WARIATE_SHEET_NAME)

    Dim staff_list As Variant
    staff_list = GetRyakushoList( _
        shift_wariate_ws, _
        SHIFT_WARIATE_DATA_START_ROW, _
        SHIFT_WARIATE_STAFF_RYAKUSHO_COL _
    )

    If IsEmpty(staff_list) Then
        MsgBox "シフト割当表からスタッフ略称を取得できませんでした。" & _
               "略称列(B列)を確認してください。", _
               vbExclamation
        Exit Sub
    End If
    
    ' スタッフ略称の件数を取得
    Dim staff_count As Long
    staff_count = UBound(staff_list)


    ' 月勤務時間合計辞書を作成(スタッフ→月合計時間)
    Dim staff_month_kinmujikan_dic As Scripting.Dictionary
    Set staff_month_kinmujikan_dic = CreateStaffMonthKinmuJikanDic( _
        tanmu_tbl, _
        target_year, _
        target_month, _
        tanmu_jikan_dic _
    )


    ' 出力位置を決定(週合計の右隣)
    '--------------------------------------------------------------------------
    ' 週合計と同じ開始行(担務表A列最終行 + 3)
    Dim last_row As Long
    last_row = tanmu_ws.Cells(tanmu_ws.Rows.Count, 1).End(xlUp).row
    
    Dim output_start_row As Long
    output_start_row = last_row + 3
    
    ' 月合計の開始列(週合計 I~O の右隣、2列空けて開始)
    Const MAX_WEEK_COUNT As Long = 6
    Const MONTH_OUTPUT_START_COL As Long = OUTPUT_START_COL + MAX_WEEK_COUNT + 3

    
    ' 出力用配列を作成(確認1行+ヘッダ1行+スタッフ行 / スタッフ列1+合計列1)
    '--------------------------------------------------------------------------
    ' 出力用配列のサイズを調整
    Dim out_tbl() As Variant
    ReDim out_tbl(1 To (staff_count + 2), 1 To 2)

    ' 確認行(1行目)
    out_tbl(1, 1) = "確認"

    ' ヘッダ行(2行目)
    out_tbl(2, 1) = "月合計"
    out_tbl(2, 2) = DateSerial(target_year, target_month, 1)

    ' 各スタッフを走査
    Dim staff_idx As Long
    For staff_idx = 1 To staff_count

        Dim staff_ryakusho As String
        staff_ryakusho = CStr(staff_list(staff_idx))

        out_tbl(staff_idx + 2, 1) = staff_ryakusho

        If staff_month_kinmujikan_dic.Exists(staff_ryakusho) Then
            out_tbl(staff_idx + 2, 2) = CDbl(staff_month_kinmujikan_dic(staff_ryakusho))
        Else
            out_tbl(staff_idx + 2, 2) = 0#
        End If

    Next staff_idx


    ' 出力範囲の設定(固定開始列)
    '--------------------------------------------------------------------------
    Dim out_last_row As Long
    out_last_row = output_start_row + UBound(out_tbl, 1) - 1
    
    Dim out_last_col As Long
    out_last_col = MONTH_OUTPUT_START_COL + UBound(out_tbl, 2) - 1
    
    Dim out_rng As Range
    Set out_rng = tanmu_ws.Range( _
        tanmu_ws.Cells(output_start_row, MONTH_OUTPUT_START_COL), _
        tanmu_ws.Cells(out_last_row, out_last_col) _
    )
    
    ' 前回出力範囲のクリア(固定範囲)
    '--------------------------------------------------------------------------
    Dim month_output_last_row As Long
    month_output_last_row = output_start_row + (staff_count + 1)   ' 確認+ヘッダ+スタッフ行
    
    Dim month_output_last_col As Long
    month_output_last_col = MONTH_OUTPUT_START_COL + 1             ' スタッフ列 + 合計列
    
    tanmu_ws.Range( _
        tanmu_ws.Cells(output_start_row, MONTH_OUTPUT_START_COL), _
        tanmu_ws.Cells(month_output_last_row, month_output_last_col) _
    ).ClearContents
    
    tanmu_ws.Range( _
        tanmu_ws.Cells(output_start_row, MONTH_OUTPUT_START_COL), _
        tanmu_ws.Cells(month_output_last_row, month_output_last_col) _
    ).NumberFormat = "General"


    ' シートへ書き込み
    '--------------------------------------------------------------------------
    ' 担務表へ一括書き込み
    out_rng.Value2 = out_tbl

    ' ヘッダ(月)だけ表示形式を変更
    out_rng.Offset(1, 1).Resize(1, 1).NumberFormat = "m/d"

    ' スタッフ列(1列目)を左寄せ(全行)
    out_rng.Columns(1).HorizontalAlignment = xlLeft

    ' 合計列(2列目)を右寄せ(ヘッダ行から下)
    out_rng.Offset(1, 1).Resize(UBound(out_tbl, 1) - 1, 1) _
        .HorizontalAlignment = xlRight


End Sub


Private Function GetRyakushoList( _
    ByVal shift_wariate_ws As Worksheet, _
    ByVal data_start_row As Long, _
    ByVal staff_ryakusho_col As Long _
) As Variant

    ' Description
    '   シフト割当表のスタッフ略称列を走査し、全スタッフ略称(重複除外)を1始まり配列で返す。
    '   表示順はシート上の出現順を維持する。
    '
    ' Arguments
    '   shift_wariate_ws    : シフト割当表シート
    '   data_start_row      : データ開始行
    '   staff_ryakusho_col  : スタッフ略称列(例:B列=2)
    '
    ' Returns
    '   Variant
    '     - 1始まりのスタッフ略称配列
    '     - 取得できない場合は Empty
    '
    ' Dependency Tree
    '    (none)


    ' 最終行を取得(略称列基準)
    Dim last_row As Long
    last_row = shift_wariate_ws.Cells( _
        shift_wariate_ws.Rows.Count, staff_ryakusho_col _
    ).End(xlUp).row
    
    ' 略称データが存在しない場合は 0件として Empty を返す
    ' ※ユーザー通知(MsgBox)は呼び出し側で行う
    If last_row < data_start_row Then
        GetRyakushoList = Empty
        Exit Function
    End If

    ' 一意のスタッフ略称を保持するための辞書を作成
    Dim unique_staff_dic As Scripting.Dictionary
    Set unique_staff_dic = New Scripting.Dictionary

    ' 最大想定件数で一次配列を確保する
    ' ※実際の件数は staff_count で管理し、後で詰め直す
    Dim max_count As Long    ' 最大件数
    max_count = last_row - data_start_row + 1
    
    ' 一時格納用スタッフリスト(配列)
    Dim temp_staff_list() As Variant
    ReDim temp_staff_list(1 To max_count)

    ' 実際に登録されたスタッフ件数
    Dim staff_count As Long
    staff_count = 0

    ' 略称列を配列で取得
    Dim ryakusho_tbl As Variant
    ryakusho_tbl = shift_wariate_ws.Range( _
        shift_wariate_ws.Cells(data_start_row, staff_ryakusho_col), _
        shift_wariate_ws.Cells(last_row, staff_ryakusho_col) _
    ).Value2

    ' 略称列(配列)を走査
    Dim row As Long
    For row = 1 To UBound(ryakusho_tbl, 1)
    
        ' 現在の略称を取得(前後空白除去)
        Dim staff_ryakusho As String
        staff_ryakusho = Trim$(CStr(ryakusho_tbl(row, 1)))
    
        ' 空欄は対象外
        If Len(staff_ryakusho) = 0 Then GoTo NextRow
    
        ' まだ登録していない略称のみ追加(重複排除)
        If Not unique_staff_dic.Exists(staff_ryakusho) Then
            unique_staff_dic.Add staff_ryakusho, True
    
            staff_count = staff_count + 1
            temp_staff_list(staff_count) = staff_ryakusho
        End If
    
NextRow:
    Next row
    
    
    ' 取得件数で詰め直す(1始まり維持)
    Dim staff_list() As Variant
    ReDim staff_list(1 To staff_count)

    Dim idx As Long
    For idx = 1 To staff_count
        staff_list(idx) = temp_staff_list(idx)
    Next idx
    
    ' Return
    GetRyakushoList = staff_list

End Function

【モジュール: Util_GetArray】

Option Explicit


' 配列操作関連プロシージャ
'------------------------------------------------------------------------------
Sub DebugPrintArraySize(ByVal arr As Variant, ByVal label As String)

    ' Description
    ' 配列の行要素数・列要素数をイミディエイトウィンドウに出力する
    '
    ' Arguments
    ' arr   : 行列構造を持つ配列
    ' label : デバッグ出力用の識別子(シート名など)
    '
    ' Dependency Tree
    '    (none)


    ' 配列が Empty の場合処理を中断する
    If IsEmpty(arr) Then
        Debug.Print label & " : 配列が Empty です"
        Exit Sub
    End If

    ' 配列の行要素数・列要素数を出力
    Debug.Print label & _
                " 行要素数=" & (UBound(arr, 1) - LBound(arr, 1) + 1) & _
                " 列要素数=" & (UBound(arr, 2) - LBound(arr, 2) + 1)

End Sub


Function GetUsedRangeArray(ByVal ws As Worksheet) As Variant
    
    ' Description
    '   指定されたワークシートの使用範囲を判定し、
    '   Cells(1,1) から最終行・最終列までを配列として返す
    '
    ' Arguments
    '   ws  : 対象となるワークシート
    '
    ' Returns
    '   Variant
    '     ・使用範囲が存在する場合:
    '         Cells(1,1) ~ 最終行・最終列 を格納した 2 次元配列
    '     ・シートにデータが存在しない場合:
    '         Empty
    '
    ' Dependency Tree
    '     (none)
    

    ' シートにデータが存在しない場合は Empty を返す
    If ws.Cells.Find("*") Is Nothing Then
        GetUsedRangeArray = Empty
        Exit Function
    End If


    ' 最終行・最終列の取得
    Dim last_row As Long
    Dim last_col As Long

    With ws
        last_row = .Cells.Find( _
                        "*", _
                        SearchOrder:=xlByRows, _
                        SearchDirection:=xlPrevious _
                    ).row

        last_col = .Cells.Find( _
                        "*", _
                        SearchOrder:=xlByColumns, _
                        SearchDirection:=xlPrevious _
                    ).Column
    End With


    ' Return:使用範囲を配列として返す
    GetUsedRangeArray = _
        ws.Range( _
            ws.Cells(1, 1), _
            ws.Cells(last_row, last_col) _
        ).Value

End Function

【モジュール: Util_ShuffleElements】

Option Explicit


' シャッフル関連プロシージャ
'------------------------------------------------------------------------------
Function ShuffleArrayByFisherYates( _
    ByVal src_arr As Variant _
) As Variant

    ' Description
    '   指定された配列全体を対象に、
    '   フィッシャー・イェーツ法でランダムに並び替えた
    '   新しい配列を返却する
    '
    '   ・元の配列は変更しない
    '   ・要素数が 0 または 1 の場合は並び替えを行わない
    '
    ' Arguments
    '   src_arr : 並び替え対象の配列(1始まり想定)
    '
    ' Returns
    '   Variant
    '     - ランダムに並び替えられた配列
    '
    ' Dependency Tree
    '   (none)


    ' 有効要素数を取得
    Dim arr_count As Long
    arr_count = UBound(src_arr)

    ' ガード
    If arr_count <= 1 Then
        ShuffleArrayByFisherYates = src_arr
        Exit Function
    End If


    ' 作業用配列を初期化(有効要素分のみ)
    Dim work_arr() As Variant   ' 作業用配列
    ReDim work_arr(1 To arr_count)


    ' 元配列からコピー
    Dim i As Long
    For i = 1 To arr_count
        work_arr(i) = src_arr(i)
    Next i


    ' フィッシャー・イェーツシャッフル
    For i = arr_count To 2 Step -1

        Dim j As Long
        j = Int(Rnd * i) + 1

        Dim tmp As Variant
        tmp = work_arr(i)
        work_arr(i) = work_arr(j)
        work_arr(j) = tmp

    Next i


    ' Return
    ShuffleArrayByFisherYates = work_arr

End Function

使いかた

シフト表作成VBAアプリケーションに組み込んで使用する想定です。

コード実行結果

CreateTanmuWs を実行すると、以下のような結果が返ります。

各スタッフの週勤務時間が40時間以内になるように自動でシフトが割り当てられます。勤務時間の状況はシフト表下部に表示されます。

【実行前】

【実行後】

Information

ちょっとしたコツ
祝日名は、正式名称のままセルに入力すると、文字がはみ出してしまうため、左から 2 文字か 3 文字 を取り出して入力するとよいでしょう。

運営者・ポテ

以上で解説は終わりです。

VBAスキルアップの参考情報

近年は、ChatGPTをはじめとするAIの登場によって、学習のスタイルが大きく変わりました。

分からないことがあれば、AIに尋ねれば答えがすぐに見つかる時代です。

とはいえ、AIを使いこなすには、自分自身の基本的な知識や理解力が欠かせません。

全体像をつかむためには、やはり書籍などで体系的に学んでおくことが今でも有効です。

そのうえでAIを活用すれば、自分の理解度に合わせた的確な解説や、応用のヒントを得ることができます。

「学んで基礎を築く → AIで補い発展させる」──このサイクルを重ねることで、VBAスキルは着実に高まっていくでしょう。

VBAのスキルアップ

VBAを学び始めるなら

入門書は、どれを選んでも大きな差はないように感じます。

どれを選ぶかに悩むことに時間をかけるよりも、まずは手頃な一冊を手に取って進めてみるのがおすすめです。

もし迷ったときには、私はインプレス社の「いちばんやさしい」シリーズを選ぶことが多いです。

基礎を超えて力をつけたいなら

私は上級者を目指していましたので、入門書にとどまらず、このような内容の濃い一冊を選んで学んでいました。

今は誰でもAIを活用できる時代になりましたが、上級者を目指す方にとっては、AIをより上手に活用するという意味でも、こうした本は今なお価値があります。

このレベルの本を一冊持っておくことに、損はないでしょう。


資格で能力を証明したいなら

VBAのプログラミング能力を客観的に示したい場合には「VBAエキスパート試験」があります。

特に「スタンダード」の方は上級者向けです。

あなたが社内業務の改善を行う立場であっても、VBAで作成したシステムをお客様に納める立場であっても、この資格は信頼や安心につながるでしょう。

以下の公式テキストが販売されています。



プログラミングの一般教養

「独学プログラマー」というプログラミングの魅力を解説した書籍があります。

これはVBAではなくPythonを題材としていますが、プログラミングの基本的な知識や思考法、仕事の進め方まで幅広く学べます。

今はAIにコードを尋ねれば、答えが返ってくる時代です。

しかし、この本からは「コード」以上に、プログラミングに向き合う姿勢や考え方を学ぶことができるでしょう。


こちらの記事でも紹介しています。もしよろしければご覧ください。

【初心者歓迎】無料相談受付中 

運営者・ポテ

いつもありがとうございます!

限られた時間をより良く使い、日本の生産性を高めたい──

みんなの実用学を運営するソフトデザイン工房では、業務整理や業務改善アプリケーション作成のご相談を承っております。

お気軽にご相談ください。


こちらの記事でも紹介しております。

おわりに

運営者・ポテ

ご覧いただきありがとうございました!

この記事では、「勤務シフト表で週と月の労働時間を考慮する方法(配列+辞書利用)」を解説しました。

お問い合わせやご要望がございましたら、「お問い合わせ/ご要望」フォームまたはコメント欄よりお知らせください。

この記事が皆様のお役に立てれば幸いです。

なお、当サイトでは様々な情報を発信しております。よろしければトップページもあわせてご覧ください。

この記事を書いた人

運営者・ポテソフトデザイン工房|日々の業務にちょうどいい自動化を
■人生を追求する凡人 ■日本一安全で、気の向くままに自分の時間を過ごせる、こだわりのキャンプ場を作るのが夢 ■ソフトデザイン工房運営(個人事業者) - 業務改善アプリケーションをご提供 ■人生は時間そのもの。ひとりでも多くの人が「より良い人生にするために時間を使って欲しい」と願い、仕事のスキルの向上、余暇の充実、資産形成を追求。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です