- カテゴリ: validation
 - 掲載バージョン: Laravel 12・PHP 8.4
 - 名前空間 / FQCN / コマンド: 
after:date/Illuminate\Validation\Rule::after() - 関連: after_or_equal / before / before_or_equal / date / date_format
 - 変更履歴: Laravel 5.x から提供。
Rule::after()による fluent 指定は 5.5+。 
要点(TL;DR)
- 入力がある基準日より後かをチェックするルール
 ['ends_at' => 'required|date|after:starts_at']- 罠:比較対象の形式ミスマッチ/タイムゾーン差/
date未付与で文字列比較になる 
概要
after は日時入力が、指定した基準日時より未来側であることを検証します。基準は固定日付・他フィールド・now(現在時刻)のいずれかで指定できます。日付文字列は date / date_format などと組み合わせ、パース可能な日時として扱えるようにするのが実務の基本です。
構文 / シグネチャ
// バリデーションルール(文字列)
'field' => 'after:<date_or_field|now>'
// ルールオブジェクト(fluent)
use Illuminate\Validation\Rule;
'field' => [Rule::after('<date_or_field|now>')]
引数(表)
| 引数 | 型 | 必須 | 既定値 | 説明 | 
|---|---|---|---|---|
| date_or_field | string | Yes | なし | YYYY-MM-DD 等の絶対日付、field_name(他フィールド参照)、または now。 | 
- 戻り値:検証成功/失敗(バリデータ全体として 
Illuminate\Contracts\Validation\Validatorが true/false) - 例外/副作用:該当フィールドが検証失敗時にエラーメッセージ生成。副作用なし。
 
使用例
最小例
use Illuminate\Support\Facades\Validator;
$data = [
    'starts_at' => '2025-10-10 10:00:00',
    'ends_at'   => '2025-10-10 12:00:00',
];
$rules = [
    'starts_at' => ['required','date'],
    'ends_at'   => ['required','date','after:starts_at'],
];
$validator = Validator::make($data, $rules);
if ($validator->fails()) {
    // エラー処理
}
実務例(FormRequest・現在時刻との比較)
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class PublishRequest extends FormRequest
{
    public function rules(): array
    {
        return [
            'title'      => ['required','string','max:120'],
            'starts_at'  => ['required','date','after:now'], // 未来スケジュールのみ許可
            'ends_at'    => ['required','date','after:starts_at'],
        ];
    }
    public function messages(): array
    {
        return [
            'ends_at.after'   => '終了日時は開始日時より後で指定してください。',
            'starts_at.after' => '開始日時は現在より後の時刻を指定してください。',
        ];
    }
}
よくある落とし穴・注意
dateを併用する:after単体だとパース不能な文字列の扱いが曖昧になりがち。date/date_formatと併用して必ず日時として解釈させる。- フォーマットの一貫性:
date_format:Y-m-d H:iを両フィールドに付け、同じ書式で比較させる。 - タイムゾーン:アプリの 
config('app.timezone')とユーザー入力のタイムゾーン差異で境界ズレが起きる。受け取りを UTC で統一するか、明示的にタイムゾーンを含む書式にする。 - 境界条件:同一時刻は失敗。同値を許容するなら 
after_or_equalを使う。 - 他フィールド未入力:
after:starts_atでstarts_atが空だと期待通り動かないケース。required_with:ends_atなどで依存関係を定義。 
代替・関連APIとの比較
after_or_equal:同一時刻を許容する場合に選択。before/before_or_equal:過去側の制約が必要な場合。date/date_format:afterと必ずセットで使い、解釈の曖昧さを排除。Rule::after():配列定義で可読性を上げたい/条件分岐で柔軟に指定したい場合に有用。
通過/失敗ケース(代表例)
入力値 (starts_at / ends_at) | ルール | 結果 | ポイント | 
|---|---|---|---|
2025-10-10 10:00 / 2025-10-10 12:00 | ends_at: after:starts_at | 通過 | 12:00 は 10:00 より後 | 
2025-10-10 10:00 / 2025-10-10 10:00 | after:starts_at | 失敗 | 同一は不可 | 
2025-10-10 / 2025-10-09 | after:starts_at | 失敗 | 過去側 | 
now より未来 | after:now | 通過 | 現在時刻より後 | 
2025/10/10(スラッシュ) | `date_format:Y-m-d | after:…` | 失敗 | 
テスト例(Pest)
<?php
use Illuminate\Support\Facades\Validator;
it('validates ends_at is after starts_at', function () {
    $data = [
        'starts_at' => '2025-10-10 10:00:00',
        'ends_at'   => '2025-10-10 10:00:01',
    ];
    $rules = [
        'starts_at' => ['required','date','date_format:Y-m-d H:i:s'],
        'ends_at'   => ['required','date','date_format:Y-m-d H:i:s','after:starts_at'],
    ];
    $v = Validator::make($data, $rules);
    expect($v->passes())->toBeTrue();
});
トラブルシュート(エラー別)
| 症状/エラー | 原因 | 対処 | 
|---|---|---|
| 「The ends at must be a date after starts at.」 | ends_at が同一または過去 | after_or_equal の検討、入力調整 | 
| 想定外に通る/落ちる | フォーマット不一致や date 未併用 | date/date_format を両方へ付与 | 
| ローカルと本番で判定がズレる | TZ 差(app.timezone) | 入力を UTC に正規化/TZ を明示 | 
| 他フィールド参照で常に失敗 | 参照先が未入力 | required_with / required の組み合わせで依存性を担保 | 
参考リンク
- Laravel Docs — Validation(Date Rules / after): https://laravel.com/docs/12.x/validation#rule-after
 - Laravel API — 
Illuminate\Validation\Rule: https://laravel.com/api/12.x/Illuminate/Validation/Rule.html - PHP Manual — 
strtotime: https://www.php.net/strtotime - Carbon Docs — Parsing & Timezones: https://carbon.nesbot.com/docs/
 

  
  
  
  