はじめに 「深夜時間判定」は“割増賃金の境界線をコードにする作業”
勤務時間の中でも、
「22:00〜翌5:00」は“深夜労働”として割増賃金の対象になる、というルールがよくあります。
この“深夜時間”を正しく判定できないと、
残業代の計算が狂ったり、法令違反になったりと、かなり重い問題につながります。
でも、やることの本質はシンプルで、
「勤務時間帯」と「深夜時間帯(22:00〜翌5:00)」の“重なっている部分”を取り出すだけです。
ここでは、
まず「1日の中の深夜時間帯の考え方」から始めて、
「勤務時間との重なりを計算するユーティリティ」まで、
初心者向けにかみ砕いて説明していきます。
深夜時間帯の基本イメージを整理する
深夜時間は「22:00〜翌5:00」という“日付をまたぐ帯”
深夜時間のややこしさは、
「22:00〜24:00」と「0:00〜5:00」にまたがっていることです。
例えば「2026/02/18 21:00〜2026/02/19 02:00」の勤務なら、
深夜時間は「22:00〜24:00」と「0:00〜2:00」の合計 4時間です。
つまり、深夜時間判定の本質は、
「ある勤務時間帯が、22:00〜翌5:00のどこにどれだけ重なっているか」を求めることです。
1日分の深夜時間帯を DateTime で表現する
「その日の22:00〜翌5:00」を作る
まずは、「ある日付に対する深夜時間帯」を DateTime で表現してみます。
public static (DateTime NightStart, DateTime NightEnd) GetNightRange(DateTime anyTime)
{
DateTime date = anyTime.Date; // その日の 0:00
DateTime nightStart = date.AddHours(22); // 当日 22:00
DateTime nightEnd = date.AddDays(1).AddHours(5); // 翌日 5:00
return (nightStart, nightEnd);
}
C#例えば、anyTime が 2026/02/18 10:00 なら、
nightStart=2026/02/18 22:00nightEnd=2026/02/19 05:00
という“その日の深夜時間帯”が取れます。
ここでのポイントは、
「深夜時間帯は“日付をまたぐ1本の帯”として扱う」
というイメージを持つことです。
勤務時間と深夜時間の“重なり”を計算する
1日の深夜帯と勤務時間の重なりを求める
次に、「ある勤務時間帯が、その日の深夜帯とどれだけ重なるか」を計算します。
public static TimeSpan GetNightWorkDurationForOneDay(DateTime workStart, DateTime workEnd)
{
if (workEnd <= workStart)
return TimeSpan.Zero;
var (nightStart, nightEnd) = GetNightRange(workStart);
DateTime overlapStart = workStart > nightStart ? workStart : nightStart;
DateTime overlapEnd = workEnd < nightEnd ? workEnd : nightEnd;
if (overlapEnd <= overlapStart)
return TimeSpan.Zero;
return overlapEnd - overlapStart;
}
C#使い方の例です。
DateTime workStart = new DateTime(2026, 2, 18, 21, 0, 0); // 21:00
DateTime workEnd = new DateTime(2026, 2, 19, 2, 0, 0); // 翌 2:00
TimeSpan night = GetNightWorkDurationForOneDay(workStart, workEnd);
Console.WriteLine(night.TotalHours); // 4 (22:00〜2:00)
C#ここでの重要ポイントは、
「勤務時間帯」と「深夜時間帯」の“重なり”を、overlapStart と overlapEnd で切り出していることです。
overlapStart = max(workStart, nightStart)overlapEnd = min(workEnd, nightEnd)
という形は、「2つの時間帯の共通部分」を求める定番パターンなので、ぜひ覚えておいてください。
勤務が複数日にまたがる場合への対応
日をまたぐ勤務を“日ごとに分割して”考える
「20:00〜翌6:00」のように、勤務自体が深夜帯をまたぐこともあります。
この場合は、勤務時間を“日ごとに分割して”考えるのが安全です。
public static TimeSpan GetNightWorkDuration(DateTime workStart, DateTime workEnd)
{
if (workEnd <= workStart)
return TimeSpan.Zero;
TimeSpan totalNight = TimeSpan.Zero;
DateTime current = workStart;
while (current < workEnd)
{
DateTime dayEnd = current.Date.AddDays(1); // その日の 24:00
DateTime segmentEnd = workEnd < dayEnd ? workEnd : dayEnd;
TimeSpan nightForDay = GetNightWorkDurationForOneDay(current, segmentEnd);
totalNight += nightForDay;
current = dayEnd;
}
return totalNight;
}
C#使い方の例です。
DateTime workStart = new DateTime(2026, 2, 18, 20, 0, 0); // 20:00
DateTime workEnd = new DateTime(2026, 2, 19, 6, 0, 0); // 翌 6:00
TimeSpan night = GetNightWorkDuration(workStart, workEnd);
Console.WriteLine(night.TotalHours); // 7 (22:00〜5:00 + 0:00〜5:00 のうち重なる部分)
C#このように、
「勤務時間を日ごとに区切り、その日ごとの深夜帯との重なりを足し合わせる」
という構造にしておくと、どんな長さの勤務にも対応できます。
「深夜時間が含まれているか?」の判定
単純なブール判定ユーティリティ
「この勤務に深夜時間が1分でも含まれているか?」だけ知りたい場合は、
合計深夜時間が 0 より大きいかどうかを見るだけでOKです。
public static bool HasNightWork(DateTime workStart, DateTime workEnd)
{
return GetNightWorkDuration(workStart, workEnd) > TimeSpan.Zero;
}
C#使い方の例です。
Console.WriteLine(HasNightWork(
new DateTime(2026, 2, 18, 9, 0, 0),
new DateTime(2026, 2, 18, 18, 0, 0))); // false
Console.WriteLine(HasNightWork(
new DateTime(2026, 2, 18, 21, 30, 0),
new DateTime(2026, 2, 19, 0, 30, 0))); // true
C#ここでの重要ポイントは、
「“含まれているかどうか”と“何時間か”を分けて考える」ことです。
まずは TimeSpan で量を出し、その上にブール判定を載せると、ロジックが整理されます。
実務での注意点:タイムゾーンと日付の基準
DateTimeKind とローカル時間の扱い
深夜時間判定は、「どのタイムゾーンの 22:00〜5:00 か」が非常に重要です。
日本の就業規則なら「日本時間の 22:00〜5:00」
海外拠点なら、その国のローカル時間での 22:00〜5:00
というように、前提が変わります。
そのため、実務では次のような方針を決めておくと安全です。
アプリ内部では DateTime をローカル時間(Kind = Local)で扱う
あるいは DateTimeOffset を使って、タイムゾーンを明示的に持つ
そして、「深夜時間判定は必ずローカル時間に変換してから行う」
というルールにしておくと、UTC とのズレで事故る可能性を減らせます。
まとめ 「深夜時間判定ユーティリティ」は“割増対象時間を正確に切り出す道具」
深夜時間判定は、
単に「22時以降かどうか」ではなく、
「勤務時間帯と 22:00〜翌5:00 の重なりを正確に取り出す」処理です。
押さえておきたいポイントは次の通りです。
深夜時間帯は「その日の 22:00〜翌5:00」という“日付をまたぐ1本の帯”として表現する。
勤務時間帯との重なりは、overlapStart = max(workStart, nightStart) と overlapEnd = min(workEnd, nightEnd) で求める。
勤務が複数日にまたがる場合は、勤務を日ごとに区切り、各日の深夜帯との重なりを合計する。
「含まれているか?」の判定は、まず合計深夜時間を TimeSpan で出してから、0より大きいかどうかで判断する。
タイムゾーン(どのローカル時間の 22:00〜5:00 か)を明確にし、その前提をコード全体で統一する。
ここまで理解できれば、
“なんとなく 22時以降を深夜扱いしている”状態から抜け出して、
“割増賃金や法令に耐えうる、実務で使える深夜時間判定ユーティリティ”を
自分の C# プロジェクトにしっかり組み込めるようになります。
