日付バリデーションは“入力のゆらぎを正しい日付に整えるための基盤”
日付入力は業務システムで最もトラブルが起きやすい領域です。
「2026/02/30」「2026-13-01」「20260218」「2/18」など、ユーザーが入力する形式は本当にバラバラです。
さらに、業務では「開始日 ≤ 終了日」「未来日は不可」「過去日は不可」など、追加のルールも絡みます。
ここでは、初心者でも理解しやすいように、
- 文字列としての形式チェック
- 実在する日付かどうかのチェック
- 業務ルール(範囲・前後関係)のチェック
という3段階で、実務で使える日付バリデーションを解説します。
文字列として正しい形式かどうかをチェックする
「YYYY-MM-DD」や「YYYY/MM/DD」を厳密にチェックする
日付は DateTime.Parse に頼るとカルチャ依存で事故が起きるため、
業務では TryParseExact を使って「許可する形式を明示」するのが鉄則です。
using System;
using System.Globalization;
public static class DateValidator
{
private static readonly string[] Formats =
{
"yyyy-MM-dd",
"yyyy/MM/dd"
};
public static bool TryParseDate(string input, out DateTime date)
{
return DateTime.TryParseExact(
input,
Formats,
CultureInfo.InvariantCulture,
DateTimeStyles.None,
out date);
}
}
C#例:正しい形式と誤った形式
DateValidator.TryParseDate("2026-02-18", out var d1); // OK
DateValidator.TryParseDate("2026/02/18", out var d2); // OK
DateValidator.TryParseDate("2026/2/18", out _); // NG(ゼロ埋め必須)
DateValidator.TryParseDate("2026-13-01", out _); // NG(存在しない月)
DateValidator.TryParseDate("2026-02-30", out _); // NG(存在しない日)
C#ここでの重要ポイントは、
「形式」と「実在する日付かどうか」を同時にチェックできる
という点です。
実在する日付かどうかをチェックする
TryParseExact が通れば「存在する日付」であることが保証される
TryParseExact は、
「2026-02-30」や「2026-13-01」のような存在しない日付を自動的に弾いてくれます。
つまり、
- 形式が正しい
- 実在する日付である
この2つを一度に満たすことができます。
ただし、業務ではさらに「意味的に正しいか」をチェックする必要があります。
業務ルール:日付の前後関係をチェックする
「開始日 ≤ 終了日」を保証する
予約・勤怠・期間指定などでは、
開始日と終了日の前後関係が正しいかどうかが必須です。
public static bool IsValidDateRange(DateTime start, DateTime end, bool allowEqual = true)
{
return allowEqual ? start <= end : start < end;
}
C#例:前後関係のチェック
DateTime start = new DateTime(2026, 2, 18);
DateTime end = new DateTime(2026, 2, 20);
IsValidDateRange(start, end); // true
IsValidDateRange(end, start); // false
C#ここでの重要ポイントは、
「等しい日付を許すかどうか」を引数で切り替えられるようにする
ことです。
業務ルール:許可範囲(未来日禁止・過去日禁止など)
「今日より未来は不可」「過去日は不可」などのチェック
業務によっては、次のような制約があります。
- 過去日は入力不可(例:予約)
- 未来日は入力不可(例:実績登録)
- 今日を含むかどうか
これもユーティリティ化できます。
public static bool IsNotFuture(DateTime date)
{
return date <= DateTime.Today;
}
public static bool IsNotPast(DateTime date)
{
return date >= DateTime.Today;
}
C#例:未来日・過去日の判定
IsNotFuture(new DateTime(2026, 2, 18)); // 今日以前なら OK
IsNotPast(new DateTime(2026, 2, 19)); // 今日以降なら OK
C#文字列入力から一気に業務ルールまでチェックする
総合的なバリデーション結果を返すクラス
実務では、
「どこがダメだったのか」を画面に返す必要があります。
そのため、結果をオブジェクトで返す形が便利です。
public sealed class DateValidationResult
{
public bool IsValid { get; }
public string? ErrorMessage { get; }
public DateTime? Date { get; }
private DateValidationResult(bool isValid, string? errorMessage, DateTime? date)
{
IsValid = isValid;
ErrorMessage = errorMessage;
Date = date;
}
public static DateValidationResult Success(DateTime date)
=> new DateValidationResult(true, null, date);
public static DateValidationResult Fail(string message)
=> new DateValidationResult(false, message, null);
}
C#総合チェックメソッド
public static class DateInputValidator
{
public static DateValidationResult Validate(
string input,
DateTime? min = null,
DateTime? max = null)
{
if (!DateValidator.TryParseDate(input, out var date))
{
return DateValidationResult.Fail("日付の形式が正しくありません。(例: 2026-02-18)");
}
if (min.HasValue && date < min.Value)
{
return DateValidationResult.Fail($"日付は {min.Value:yyyy-MM-dd} 以降である必要があります。");
}
if (max.HasValue && date > max.Value)
{
return DateValidationResult.Fail($"日付は {max.Value:yyyy-MM-dd} 以前である必要があります。");
}
return DateValidationResult.Success(date);
}
}
C#例:入力チェック
var result = DateInputValidator.Validate(
"2026-02-18",
min: new DateTime(2026, 1, 1),
max: new DateTime(2026, 12, 31));
if (!result.IsValid)
{
Console.WriteLine(result.ErrorMessage);
}
else
{
Console.WriteLine($"OK: {result.Date}");
}
C#実務で意識すべきポイント
書式を固定することが最重要
日付はカルチャ依存が強く、2026/02/18 を「MM/DD/YYYY」と解釈する環境もあります。
業務では必ず、
TryParseExactを使う- 許可する書式を明示する
- カルチャは
InvariantCultureに固定する
という方針にしておくと事故を防げます。
バリデーションは「入力直後」と「保存直前」の2段階で行う
画面側でチェックしても、
API や DB に渡る前にもう一度チェックするのが安全です。
まとめ:日付バリデーションは“入力の揺れを吸収する安全装置”
日付バリデーションの本質は、
- 文字列として正しいか
- 実在する日付か
- 業務ルールに合っているか
という3段階のチェックを行い、
「システムが安心して扱える DateTime に変換する」ことです。
このユーティリティを持っておくと、
日付入力まわりのバグが激減し、
画面・API・DB のすべてで一貫したチェックができるようになります。

