Laravel 標準の Date バリデーションは、次のときに TRUE を返します。
| OR | 値がPHPの DateTime クラスのインスタンスである |
|
|---|---|---|
| AND | 値が strtotime で理解できる文字列である |
|
date_parse で年月日を返す |
||
checkdate で年月日が妥当である |
文字列の具体例でまとめると以下のようになります。
| 文字列 | バリデーション | MySQL保存 | |
|---|---|---|---|
| 例01 | now | FALSE | |
| 例02 | +1 day | FALSE | |
| 例03 | next Thursday | FALSE | |
| 例04 | 2016-09-30 + 1day | TRUE | × |
| 例05 | 30 September 2016 | TRUE | × |
| 例06 | 2016-09-30 | TRUE | ◯ |
| 例07 | 20160930 | TRUE | ◯ |
| 例08 | 2016/09/30 | TRUE | ◯ |
| 例09 | 09/30/2016 | TRUE | × |
| 例10 | 09-30-2016 | FALSE | |
| 例11 | 30/09/2016 | FALSE | |
| 例12 | 2016-09-30 10:10:00 | TRUE | ◯ |
date_parse を通すため 例01〜例03のような論理指定は弾かれますが、例04のような記述では前半部分が年月日の配列値を返すためバリデーションは通ります。
また、アメリカ式の月日年(例09)が通って、ヨーロッパ式の日月年(例11)は弾かれます(これは環境のタイムゾーンに影響されるでしょう)。
いずれにせよ、バリデーションに通ってもそのままデータベースに保存できるとは限りません。
データベース保存を前提にするなら、ISO-8601 の "YYYY-MM-DD" 書式に限定したほうが何かと都合が良いですね。
date_format による ISO-8601限定
入力され日付のフォーマットを限定するために date_format が用意されています。引数は date_parse_from_format を通して処理されます。
date と date_format は両方を同時に使用することはできません。
'date' => 'date_format:Y-m-d', 'datetime' => 'date_format:Y-m-d H:i:s',
Date と Datetime の拡張
データベースの保存フィールドで Date と Datetime を区別し、入力フォームのインターフェースもこの2つしかないならば、date_format を使用せずに、date バリデーションを拡張してしまうこともできます。
書式を正規表現で限定してからオリジナルのバリデーションを通せばよいでしょう。
/**
* date (without datetime)
*
* @param string $attribute
* @param string $value
* @return true
*/
protected function validateDate($attribute, $value)
{
// YYYY-MM-DD に限定する
if (!preg_match('/^[0-9]+-[0-9]+-[0-9]+$/', $value)) return false;
return parent::validateDate($attribute, $value);
}
/**
* datetime
*
* @param string $attribute
* @param string $value
* @return bool
*/
public function validateDatetime($attribute, $value)
{
// YYYY-MM-DD hh:mm に限定する
if (!preg_match('/^[0-9]+-[0-9]+-[0-9]+ ([0-9]+):([0-9]+)/', $value, $m)) return false;
return parent::validateDate($attribute, $value);
}
validateDete() は標準の置き換えなので protected 宣言ですが validateDatetime() は追加関数として public で宣言しています。
日付入力のフォームインターフェイス
入力バリデーションとして Date と Datetime を用意したならば、入力フォームもそれに対応しなければなりませんが、HTML5 の日付フォームはブラウザの対応に依存し、非対応な環境を無視したとしてもユーザーインターフェイスが人によって異なりサポートが難しいものです。
私たちのプロジェクトの管理画面では、Bootstrapベースの SmartAdmin を導入してインターフェイスの統一を図っています。
SmartAdmin の日付フォームは jQuery UI Datepicker と Bootstrap Timepicker の組み合わせを採用していますが、HTML5の datetime や datetime-local には対応してません。スクリプトを書くことで datetime 属性(厳密には datetime-local 属性)の入力フォームを実現する必要があります。

bladeソース(の概念)と対応するjQueryスクリプト
<div class="input-group-datetime">
<input type="hidden" name="date_start" value="{{ old('date_start') }}">
<input class="datepicker">
<input class="timepicker">
</div>
$('.input-group-datetime').on('change', 'input:visible', function() {
// 日付または時刻が変更された
var $parent = $(this).parents('.input-group-datetime'),
dt = $parent.find('.datepicker').val(),
tm = $parent.find('.timepicker').val();
if (dt && !tm) {
// 時刻が空なら00:00で補完
tm = '00:00';
$parent.find('.timepicker').val(tm);
}
if (!dt) {
// 日付が空なら時刻も削除
$parent.find('.timepicker').val('');
}
// 日時を合成して値を格納
$parent.find(':hidden').val((dt) ? dt + ' ' + tm + ':00' : '');
});
メルマガ購読の申し込みはこちらから。
