VBAで勤務時間や作業時間を計算していると、「なぜ時刻同士を引き算できるのか」「なぜ1時間を足すだけで時刻が変わるのか」と疑問に思ったことはありませんか。
例えば、次のようなコードは問題なく動作します。
Debug.Print #18:30# - #09:00#
一見すると「時刻同士を計算している」ように見えますが、VBA内部では時刻を文字列として扱っているわけではありません。
実際にはシリアル値という数値へ変換して計算しています。
この仕組みを理解しておくと、
- 時間の加算・減算
- 日付をまたぐ時間計算
- 勤務時間の集計
- 経過時間の算出
などで、「思った結果にならない」というトラブルを減らせます。
この記事では、VBAで日付や時刻がどのように管理されているのかを解説し、シリアル値を利用した時間計算の基本を実務目線で紹介します。
✅時間計算を理解するために知っておきたいシリアル値
VBAでは、日付や時刻を「日付型」として扱います。
しかし、内部では日付や時刻そのものを保存しているわけではありません。
実際にはシリアル値という数値で管理されています。
この仕組みを理解すると、「なぜ足し算や引き算だけで時間計算ができるのか」が自然に理解できるようになります。
まずはシリアル値とは何かを見ていきましょう。
・シリアル値とは
シリアル値とは、日付と時刻を1つの数値で表現する仕組みです。
例えば、
| 表示 | シリアル値 |
|---|---|
| 1日 | 1 |
| 2日 | 2 |
| 0:00 | 0 |
| 12:00 | 0.5 |
| 18:00 | 0.75 |
というように、
- 整数部分が日付
- 小数部分が時刻
を表しています。
つまり、
45500.75
のような値であれば、
- 45500日目
- 18時
という意味になります。
VBAでは、この数値を使って日付や時刻の計算を行っています。
VBAだけでなく、Excelでも日付や時刻はシリアル値として管理されています。セル上でのシリアル値の仕組みや時間計算との関係について詳しく知りたい方は、Excelのシリアル値を解説した記事も参考にしてください。
・なぜシリアル値で管理しているのか
もし時刻を文字列として管理していた場合、
09:00
18:00
をそのまま引き算することはできません。
文字列には大小比較はできますが、時間としての計算はできないためです。
一方、シリアル値で管理されていれば、
0.75 - 0.375
のように数値同士の計算になります。
そのため、
- 時間の足し算
- 時間の引き算
- 日付との差分
- ○日後・○時間後
といった処理が簡単に実現できます。
この設計のおかげで、VBAでは複雑な時間計算も通常の四則演算だけで処理できるのです。
VBAでは日付や時刻もDate型として管理されています。実際に変数がどのデータ型になっているか確認したい場合は、VarType関数の使い方もあわせて確認してみてください。
✅実際にシリアル値を確認してみる
シリアル値は普段は表示されませんが、VBAから簡単に確認できます。
内部でどのような値になっているかを見ることで、時間計算の仕組みをより理解しやすくなります。
・シリアル値を取得するサンプル
まずは現在の日時がどのようなシリアル値になっているか確認してみます。
このコードでは、現在日時を変数へ格納し、その内部値をイミディエイトウィンドウへ出力しています。
変数名も「現在日時」であることが分かる名前にしているため、後から見直したときも処理内容を理解しやすくなります。
Sub CheckSerialValue()
'現在の日時を取得
Dim currentDateTime As Date
currentDateTime = Now
'シリアル値を表示
Debug.Print CDbl(currentDateTime)
End Sub
実行すると、
45872.625
のような数値が表示されます。
環境によって数値は異なりますが、小数部分が含まれていることが分かります。
ここで重要なのは、「Date型だから文字列ではない」ということです。
表示は日付や時刻でも、内部では数値として管理されているため、四則演算が行えるようになっています。
・実務ではDate型のまま扱う理由
シリアル値は便利ですが、普段の開発で「45872.625」のような値を直接扱うことはほとんどありません。
実務ではDate型のまま扱い、必要な場面だけシリアル値で考えるほうが保守性は高くなります。
例えば勤務時間を計算する場合も、
Dim startTime As Date
Dim endTime As Date
startTime = #9:00:00 AM#
endTime = #6:00:00 PM#
Debug.Print endTime - startTime
このようにDate型で記述したほうが、
- 変数の役割が分かりやすい
- 後から仕様変更しやすい
- コードを読む人も理解しやすい
というメリットがあります。
シリアル値を直接記述するよりも、VBA本来の日付型を利用し、内部ではシリアル値で計算されているという仕組みを理解しておくことが、実務では重要です。
外部ファイルやセルから取得した値を時間計算へ利用する場合は、Date型として扱えるか事前に確認することが重要です。判定方法については、日付かどうか判定する方法を参考にしてください。
✅シリアル値を利用した時間計算の基本
シリアル値の仕組みを理解すると、VBAの時間計算は単純な四則演算で行われていることが分かります。
ここでは、実際によく使う時間計算を例に見ていきましょう。
・時間を加算する方法
例えば、「現在時刻から2時間後を求めたい」という場面はよくあります。
このような場合も、シリアル値では「1日=1」という考え方を利用します。
2時間は1日の24分の2なので、
2 / 24
を加算すれば2時間後になります。
日付だけでなく、月や年をまたぐ計算ではDateSerial関数を利用すると安全です。詳しい使い方は、DateSerial関数の完全ガイドをご覧ください。
・なぜこの書き方をするのか
時間だけを文字列として結合する方法では、日付をまたぐ計算や時刻の繰り上がりに対応できません。
一方、Date型へ時間を加算する方法なら、VBAがシリアル値として処理するため、翌日になる場合も自動的に計算されます。
そのため、勤務時間や予約時間など、実務で日付をまたぐ可能性がある処理でも流用しやすいコードになります。
Sub AddTwoHours()
'現在日時を取得
Dim currentDateTime As Date
currentDateTime = Now
'2時間後を計算
Dim afterTwoHours As Date
afterTwoHours = currentDateTime + (2 / 24)
Debug.Print afterTwoHours
End Sub
・実務で利用するときのポイント
このコードでは「2時間」を直接記述していますが、仕様変更が想定される場合は、加算する時間を変数として管理すると保守しやすくなります。
また、時間単位だけでなく、「30分」なら30 / 1440(1日=1440分)、「30秒」なら30 / 86400(1日=86400秒)という考え方で計算できます。
・時間の差を求める方法
勤務時間や作業時間を集計するときは、開始時刻と終了時刻の差を求める場面が多くあります。
Date型同士を引き算すると、VBAは内部でシリアル値の差を計算します。
・なぜDate型同士を計算するのか
時刻を「09:00」「18:00」のような文字列で管理すると、時間の計算を自分で実装しなければなりません。
Date型同士なら、VBAがシリアル値へ変換して計算してくれるため、コードを簡潔に保てます。
Sub CalculateWorkingHours()
'開始時刻
Dim startTime As Date
startTime = #9:00:00 AM#
'終了時刻
Dim endTime As Date
endTime = #6:00:00 PM#
'経過時間
Dim elapsedTime As Double
elapsedTime = endTime - startTime
Debug.Print elapsedTime
End Sub
この例では、elapsedTimeには「0.375」が格納されます。
これは9時間ではなく、「1日の0.375日分」という意味です。
時間数として表示したい場合は、
Debug.Print elapsedTime * 24
のように24を掛けることで「9」が表示されます。
・実務で利用するときのポイント
勤務時間や作業時間を時間単位で集計する場合は、シリアル値のままではなく、「×24」を行って時間数へ変換すると分かりやすくなります。
一方で、Excelセルへ時間として出力する場合は、Date型のまま扱ったほうが表示形式を柔軟に変更できます。
✅日付をまたぐ時間計算で注意するポイント
シリアル値を理解していても、日付をまたぐ時間計算では思わぬ結果になることがあります。
特に夜勤や24時間稼働するシステムでは、この違いを理解しておくことが重要です。
・時刻だけを比較すると正しい結果にならない
例えば、
- 開始:23:00
- 終了:2:00
という勤務時間を考えてみます。
時刻だけで計算すると、
2:00 - 23:00
となるため、マイナスの値になります。
しかし実際は翌日の2時なので、勤務時間は3時間です。
・なぜこの問題が起こるのか
時刻だけを設定した場合、VBAは同じ日付として扱います。
そのため、終了時刻のほうが小さい値になり、負の時間として計算されます。
このようなケースでは、日付も含めて管理するか、翌日にまたぐことを考慮した処理を追加する必要があります。
実務では勤怠管理や設備監視などで頻繁に発生するため、時刻だけではなく日時として扱う設計が推奨されます。
日付をまたぐ処理では、月末や月初をまたぐケースも少なくありません。月末処理を安全に行う方法については、DateSerialを利用した月末取得も参考になります。
✅シリアル値を意識すべき場面と意識しなくてもよい場面
シリアル値は便利な仕組みですが、すべてのコードで意識する必要はありません。
重要なのは、「内部では数値で管理されている」という仕組みを理解したうえで、普段はDate型として扱うことです。
・実務ではDate型を基本にする
シリアル値を直接記述すると、
0.375
が何時間なのか分かりにくくなります。
一方、
Dim startTime As Date
Dim endTime As Date
のようにDate型で記述すれば、コードを読んだ人にも処理内容が伝わりやすくなります。
Date型と文字列を混在させると、「型が一致しません」エラーが発生することがあります。原因や対処法について詳しく知りたい方は、型が一致しませんエラーの解説記事も参考にしてください。
・なぜDate型を使うのか
保守性を考えると、コードは「VBAが理解できる」だけでなく、「人が理解できる」ことも重要です。
Date型を利用していれば、表示形式の変更や時間計算も柔軟に対応できるため、将来的な仕様変更にも強くなります。
・実務で意識すべきポイント
シリアル値を直接扱うのは、
- 時間を数値へ換算するとき
- 経過時間を計算するとき
- Excelのセル値を解析するとき
などに限定し、それ以外はDate型を利用することをおすすめします。
「普段はDate型、仕組みとしてシリアル値を理解しておく」という考え方が、実務では最も扱いやすい設計になります。
シリアル値は内部での管理方法であり、画面へ表示する形式とは異なります。表示形式を変更したい場合は、Format関数で日付や時刻を整形する方法もあわせて確認してみてください。
✅まとめ
VBAでは、日付や時刻は見た目どおりの文字列ではなく、シリアル値という数値で管理されています。
この仕組みを理解すると、時間の足し算や引き算が四則演算だけで実現できる理由が分かります。
今回のポイントをまとめると、次のとおりです。
- 日付・時刻はシリアル値として管理されている
- 整数部分が日付、小数部分が時刻を表している
- Date型同士の計算は内部でシリアル値を利用している
- 時間数へ変換するときは24を掛ける
- 日付をまたぐ計算では日時全体で管理することが重要
- 実務ではシリアル値を直接扱うより、Date型を利用するほうが保守しやすい
シリアル値そのものを直接操作する機会は多くありません。しかし、この仕組みを理解していると、時間計算で予期しない結果になったときの原因を見つけやすくなります。
日付や時刻を扱うマクロを作成する際は、「内部ではシリアル値、コードではDate型」という考え方を意識すると、読みやすく保守しやすいプログラムを作成できます。