【入門編】【初心者向け】Taskオブジェクトの「Start」と「Finish」をVBAで安全に書き換えるための日付計算の基礎 – Project VBA解析バイブル

スポンサーリンク

【初心者向け】Project VBAでタスクの開始日・終了日を安全に操作する:カレンダー考慮の日付計算の基礎

皆さん、こんにちは! プロジェクト管理の強力な味方であるMicrosoft Project。そして、そのProjectをさらにあなたの思い通りに動かすための「Project VBA」の世界へようこそ!

「マクロの記録」でVBAの世界に足を踏み入れた方も多いかもしれませんね。しかし、そこから一歩踏み込んで、Projectのスケジュールエンジンと真正面から向き合い、日付を自在に操れるようになると、業務自動化の可能性は飛躍的に広がります。

今回は、Project VBAの基本中の基本でありながら、多くの人が「これでいいのかな?」と迷いがちなTaskオブジェクトの「Start」と「Finish」プロパティを、安全に、そしてProjectのスケジュールエンジンを壊さずに書き換えるための日付計算の基礎について、優しく、そして本質的に解説していきます。

ここをクリアすれば、Project VBAの基本はバッチリですよ!

1. なぜProject VBAで日付操作が必要なのか?

「タスクの日付変更くらい、手動でサッとやればいいじゃないか!」そう思われた方もいるかもしれません。もちろん、数個のタスクならそれでも良いでしょう。

しかし、以下のようなシーンではどうでしょうか?

  • 数百のタスクを持つプロジェクトで、特定条件のタスクの開始日を一斉に1週間ずらしたい。
  • 特定のイベント発生時に、関連する複数タスクの期日を自動で再設定したい。
  • 外部システムからインポートしたデータに基づいて、タスクの日付を自動調整したい。

こんな時、手動で一つずつ変更していては、時間もかかるし、ヒューマンエラーのリスクも高まります。VBAを使えば、これらの作業を瞬時に、正確に、そして繰り返し実行できるようになります。

そして、Projectで日付を操作する上で最も重要なのは、「Projectのスケジュールエンジンを壊さないこと」です。単に日付を文字列として扱うのではなく、Projectが持つカレンダー情報やタスクの依存関係を考慮した上で、適切に日付を計算し、設定する必要があります。

2. Taskオブジェクトの「Start」と「Finish」プロパティ

まず、Project VBAでタスクの日付を操作する際に、最も基本となるのが`Task`オブジェクトの`Start`プロパティと`Finish`プロパティです。

Taskオブジェクトとは?

Project VBAでは、Project内の様々な要素を「オブジェクト」として扱います。タスクもその一つで、`Task`オブジェクトとして表現されます。特定のタスクに対してVBAから操作を行いたい場合、まずそのタスクを`Task`オブジェクトとして取得することから始まります。

‘ 例えば、現在選択されているタスクを取得する場合
Dim objTask As MSProject.Task
Set objTask = ActiveSelection.Tasks.Item(1) ‘ 選択されている最初のタスク

StartプロパティとFinishプロパティ

`Task`オブジェクトには、そのタスクの開始日と終了日を管理するための`Start`プロパティと`Finish`プロパティがあります。

  • `Task.Start`: タスクの開始日を示します。
  • `Task.Finish`: タスクの終了日を示します。

これらのプロパティは`Date`型(日付と時刻を保持できるデータ型)で、VBAから直接読み書きが可能です。

‘ 例: 選択中のタスクの開始日と終了日をメッセージボックスで表示
MsgBox “開始日: ” & objTask.Start & vbCrLf & “終了日: ” & objTask.Finish

シンプルに日付を設定するだけなら、このプロパティに直接`Date`型の値を代入するだけでOKです。しかし、Projectのスケジュールエンジンを考慮した「安全な」日付計算を行うには、もう少し工夫が必要です。

3. DateAdd関数だけではダメな理由:Projectのカレンダーの重要性

VBAで日付の加減算を行う際、`DateAdd`関数を使うのが一般的ですね。例えば、今日から5日後を計算するなら、`DateAdd(“d”, 5, Date)`のように書きます。

しかし、Project VBAでタスクの日付を操作する場合、単純な`DateAdd`関数だけでは不十分なケースがほとんどです。なぜでしょうか?

それは、Projectが「稼働日カレンダー」を持っているからです。

Projectのカレンダーとは?

一般的な日付計算は、土日や祝日などの概念を持たず、ただ連続した日付として計算します。しかし、Projectは違います。

Projectには、プロジェクト全体やリソース、タスクごとに「いつが稼働日で、いつが非稼働日か」を定義するカレンダーが存在します。

例えば、多くのプロジェクトでは土日を非稼働日として設定しています。

イメージ図:一般的な日付 vs. Projectの日付

一般的な日付:
月 火 水 木 金 土 日 月 火
1日 2日 3日 4日 5日 6日 7日 8日 9日
←— 5日後 —>

Projectのカレンダー(土日休み):
月 火 水 木 金 [土] [日] 月 火
1日 2日 3日 4日 5日 (6日)(7日) 8日 9日
←——- 5稼働日後 ——–>
(日付としては8日になる)

この例のように、もし月曜日の1日から「5日後」を計算したい場合、一般的な`DateAdd`関数だと土曜日の6日になります。しかし、Projectのカレンダーが土日を非稼働日としている場合、「5稼働日後」は翌週月曜日の8日になるはずです。

Projectのタスクの開始日や終了日は、このカレンダーに基づいて決定されるため、VBAで日付を操作する際も、このカレンダーを考慮する必要があります。

4. Projectのカレンダーを考慮した安全な日付計算:`Application.DateAdd`

ご安心ください! Project VBAには、このカレンダーを考慮した上で日付を計算してくれる、非常に便利なメソッドが用意されています。それが、`Application.DateAdd`メソッドと`Application.DateSubtract`メソッドです。

これらのメソッドは、Projectのスケジュールエンジンが内部で利用しているカレンダーロジックを、VBAから直接利用できるようにしてくれる、まさに「極限の知見」とも言える重要な機能です。

`Application.DateAdd`メソッドの基本

`Application.DateAdd`メソッドは、指定した日付に、指定した期間を、指定したカレンダーに基づいて加算した日付を返します。

Application.DateAdd(Date, Duration, [Calendar])

  • `Date`: 基準となる日付を指定します。(例: `objTask.Start`)
  • `Duration`: 加算したい期間を指定します。ここでは期間の単位を指定します。
  • 期間の単位は、`PjUnit`列挙型(`pjDays`、`pjWeeks`、`pjHours`など)で指定します。
  • 期間の量は、数値で指定します。(例: 5日なら `5`)
  • 例えば、「5日」なら `ProjDur(5, pjDays)` のように `ProjDur` 関数を使って指定します。これはProject特有の期間の表現方法です。
  • `Calendar`(省略可能): どのカレンダーに基づいて計算するかを指定します。
  • 省略した場合は、アクティブなプロジェクトのカレンダーが使用されます。
  • 通常は `ActiveProject.Calendar` を指定するのが最も安全です。

同様に、日付を減算する場合は`Application.DateSubtract`メソッドを使用します。

Application.DateSubtract(Date, Duration, [Calendar])

具体例:5稼働日後を計算してみよう!

例えば、今日から5稼働日後を計算する場合:

Dim dtToday As Date
dtToday = Date ‘ 今日の日付を取得

‘ 5稼働日後を計算(アクティブなプロジェクトのカレンダーを使用)
Dim dtFiveWorkingDaysLater As Date
dtFiveWorkingDaysLater = Application.DateAdd(dtToday, ProjDur(5, pjDays), ActiveProject.Calendar)

MsgBox “今日: ” & dtToday & vbCrLf & _
“5稼働日後: ” & dtFiveWorkingDaysLater

このコードを実行すると、土日やプロジェクトのカレンダーで設定された非稼働日をスキップして、正確な「5稼働日後」の日付が計算されます。これこそが、Projectのスケジュールエンジンを理解し、そのロジックをVBAから利用するということなんです!

5. 実践!安全な日付変更VBAコード

それでは、実際に選択中のタスクの開始日を1週間(5稼働日)後にずらすVBAコードを書いてみましょう。

シナリオ

1. Projectで任意のタスクを選択します。
2. 以下のVBAコードを実行します。
3. 選択したタスクの開始日が、Projectのカレンダーに基づいて5稼働日後に変更されます。

Sub ShiftTaskStartDateByFiveWorkingDays()

‘==========================================================
‘ 選択中のタスクの開始日を、Projectカレンダーを考慮して
‘ 5稼働日後にシフトするマクロ
‘==========================================================

Dim objApp As MSProject.Application ‘ Projectアプリケーションオブジェクト
Dim objTask As MSProject.Task ‘ 選択中のタスクオブジェクト
Dim dtOriginalStart As Date ‘ 元の開始日を保持する変数
Dim dtNewStart As Date ‘ 新しい開始日を保持する変数

‘ エラーハンドリングの開始
On Error GoTo ErrorHandler

‘ Projectアプリケーションオブジェクトを設定
Set objApp = MSProject.Application

‘ 選択中のタスクが一つもない場合のエラーチェック
If objApp.ActiveSelection.Tasks.Count = 0 Then
MsgBox “タスクが選択されていません。操作したいタスクを選択してください。”, vbExclamation
GoTo CleanUp
End If

‘ 選択中の最初のタスクを取得
‘ ※複数タスクが選択されている場合でも、ここでは最初のタスクのみを対象とします。
Set objTask = objApp.ActiveSelection.Tasks.Item(1)

‘ 元の開始日を取得
dtOriginalStart = objTask.Start

‘ — ここが重要! Projectのカレンダーを考慮して日付を計算 —
‘ Application.DateAdd を使用して、元の開始日から5稼働日後を計算します。
‘ ProjDur(5, pjDays) で「5稼働日」という期間を指定しています。
‘ ActiveProject.Calendar を指定することで、プロジェクトのカレンダーに基づいて計算されます。
dtNewStart = objApp.DateAdd(dtOriginalStart, ProjDur(5, pjDays), ActiveProject.Calendar)

‘ 新しい開始日をタスクに設定
‘ この代入により、Projectのスケジュールエンジンが自動的に再計算を行います。
objTask.Start = dtNewStart

MsgBox “タスク「” & objTask.Name & “」の開始日を更新しました。” & vbCrLf & _
“元の開始日: ” & Format(dtOriginalStart, “yyyy/mm/dd”) & vbCrLf & _
“新しい開始日: ” & Format(dtNewStart, “yyyy/mm/dd”), vbInformation

CleanUp:
‘ オブジェクトの解放(メモリリーク防止のために非常に重要!)
Set objTask = Nothing
Set objApp = Nothing ‘ Applicationオブジェクトは通常解放不要だが、念のため

Exit Sub ‘ 正常終了

ErrorHandler:
‘ エラーが発生した場合の処理
MsgBox “エラーが発生しました。” & vbCrLf & _
“エラー番号: ” & Err.Number & vbCrLf & _
“エラー内容: ” & Err.Description, vbCritical
GoTo CleanUp ‘ エラー発生時もクリーンアップ処理へ

End Sub

コードの解説

1. オブジェクトの宣言と取得:

  • `MSProject.Application`オブジェクトと`MSProject.Task`オブジェクトを宣言しています。VBAでProjectを操作する際の基本ですね。
  • `Set objApp = MSProject.Application`でProjectアプリケーション自体を参照します。
  • `Set objTask = objApp.ActiveSelection.Tasks.Item(1)`で、現在Project画面で選択されている最初のタスクを取得します。

2. 元の開始日の取得:

  • `dtOriginalStart = objTask.Start`で、変更前の開始日を一時的に変数に保持します。

3. カレンダー考慮の日付計算(ここが核心!):

  • `dtNewStart = objApp.DateAdd(dtOriginalStart, ProjDur(5, pjDays), ActiveProject.Calendar)`
  • `objApp.DateAdd`: Projectのアプリケーションオブジェクトが持つ日付計算メソッドを呼び出します。
  • `dtOriginalStart`: 計算の基準となる日付。
  • `ProjDur(5, pjDays)`: 「5稼働日」という期間を指定します。`pjDays`は日単位、`5`はその量です。
  • `ActiveProject.Calendar`: 現在アクティブなプロジェクトのカレンダーに基づいて計算するよう指示します。これにより、土日や祝日をスキップした正確な稼働日計算が可能になります。

4. 新しい開始日の設定:

  • `objTask.Start = dtNewStart`で、計算された新しい開始日をタスクの`Start`プロパティに代入します。Projectはこれを検知し、自動的に関連タスクや全体スケジュールを再計算してくれます。

5. エラーハンドリングとオブジェクトの解放:

  • `On Error GoTo ErrorHandler`でエラー発生時の処理を指定し、プログラマブルなエラー対処を可能にしています。
  • `Set objTask = Nothing`のように、使い終わったオブジェクトは必ず`Nothing`を設定して解放しましょう。これはメモリリークを防ぎ、VBAコードの安定性とパフォーマンスを保つ上で非常に重要なプラクティスです。

6. よくある落とし穴と注意点

安全に日付を操作するためには、いくつかの注意点も理解しておきましょう。

6.1. タスクの種類と制約

Projectには「自動スケジュール」タスクと「手動スケジュール」タスクがあります。

  • 自動スケジュールタスク: Projectのスケジュールエンジンが、期間、依存関係、リソース、カレンダーに基づいて開始日・終了日を自動計算します。VBAで`Start`や`Finish`を直接書き換えると、Projectはこれを「制約」として解釈し、場合によっては他のタスクのスケジュールに影響を与えたり、制約の種類を変更したりします。
  • 手動スケジュールタスク: ユーザーが開始日・終了日・期間を直接入力し、Projectはそれを基本的に変更しません。VBAで直接`Start`や`Finish`を書き換えても、基本的には入力した値がそのまま適用されます。

今回の例では、自動スケジュールタスクを前提としていますが、もし「指定日以前に終了」のような強い制約が手動で設定されているタスクに対してVBAで日付を代入すると、その制約が解除されるか、新しい制約(例: 「指定日に開始」)に上書きされる可能性があります。

もし、意図せず制約を変更したくない場合は、`Task.ConstraintType`や`Task.ConstraintDate`などのプロパティを事前に確認・操作することも検討してください。

6.2. 時間情報について

`Task.Start`や`Task.Finish`プロパティは`Date`型であるため、内部的には日付だけでなく時刻情報も持っています。

通常、VBAから日付のみを代入した場合(例: `objTask.Start = #2023/04/01#`)、Projectはプロジェクトの既定の稼働開始時刻(通常は午前9時)や稼働終了時刻(通常は午後5時)を自動的に適用してくれます。

しかし、もしVBAから`objTask.Start = CDate(“2023/04/01 10:30:00”)`のように時刻を含めて代入すると、その指定した時刻が優先されます。初心者の方はまず日付だけを意識すれば大丈夫ですが、より細かく時間を制御したい場合は、この点も覚えておくと良いでしょう。

6.3. オブジェクトの解放を忘れずに

先ほどのコードにも書きましたが、`Set objTask = Nothing`のように、使用し終わったProjectオブジェクトは必ず解放してください。これを怠ると、VBAコードの実行が重くなったり、Projectアプリケーションが不安定になったりする原因となります。

7. まとめ

いかがでしたでしょうか?

今回は、Project VBAでタスクの開始日・終了日を安全に操作するための基礎として、以下の重要なポイントを解説しました。

  • Taskオブジェクトの`Start`と`Finish`プロパティが日付操作の基本であること。
  • Projectの稼働日カレンダーの存在と、一般的な`DateAdd`関数だけでは不十分な理由。
  • `Application.DateAdd`メソッドと`Application.DateSubtract`メソッドを使って、Projectのカレンダーを考慮した正確な日付計算を行う方法。
  • 実用的なVBAコードと、プログラミング初心者でも安心できる丁寧な解説。
  • 日付操作における注意点と、オブジェクトの適切な解放の重要性。

これらの知識を習得すれば、あなたのProject VBAスキルは格段に向上し、より複雑で実用的な自動化ツールを開発できるようになるはずです。

ここをクリアすれば、Project VBAの基本はバッチリですよ!
ぜひ、今日の知識を活かして、あなたのProject業務をさらに効率化していってくださいね!

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