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' : ''); });メルマガ購読の申し込みはこちらから。