Date validation in Yii

Moving on from my last post on Yii validation rules for text fields, next I am going to be looking at validating dates and date ranges.

The date validator CDateValidator was added to Yii in release 1.1.7 and provides an easy method to validate that a field contains a date, time or datetime, with the following parameters.

format option enables you to specify the date format or a list of date formats in an array.

allowEmpty – whether to allow empty or null values

for example:

public function rules()
{
return array(
           // multiple formats specified to allow for 01/02/20012 and 1/02/2012
           array('reservation_from, reservation_to ', 'date', 'format'=>array('dd/MM/yyyy','d/MM/yyyy'), 'allowEmpty'=>true),
           array('created_dt, last_updated, ', 'date', 'format'=>'yyyy-MM-dd HH:mm:ss', 'allowEmpty'=>false),
  );
}

So now we can be sure that the user has input valid date formats – what about date ranges.

If we wanted to check that the reservation_to is greater than the reservation_from we could perhaps use the compare validator for date ranges as follows:

  array('reservation_to','compare','compareAttribute'=>'reservation_from','operator'=>'>', 'allowEmpty'=>true,'message'=>'{attribute} must be greater than "{compareValue}".')

So, wouldn’t life be nice and easy if this code worked …. but it doesn’t!

The date comparison validator uses datetimestamps.  It does not convert textual dates into timestamps.  Therefore the date in the format “dd/mm/yyyy” of 16/01/2012 is greater than 10/02/2012.

It looks as though we will still need to build a custom function to convert these dates to datetimestamps first and then do the comparison test.

So here is date function to do that validation.

        public function dateCompare($attribute,$params) {

            if (empty($params['compareAttribute']) || empty($params['operator']))
               $this->addError($attribute, 'Invalid Parameters to dateCompare');

            $compareTo=$this->$params['compareAttribute'];

            if($params['allowEmpty'] && (empty($this->$attribute) || empty($compareTo)))
		return;

            //set default format if not specified
            $format=(!empty($params['format']))? $params['format'] : 'dd/MM/yyyy';
            //default operator to >
            $compare=(!empty($params['operator'])? $params['operator'] : ">";

            $start=CDateTimeParser::parse($this->$attribute,$format);
            $end=CDateTimeParser::parse($compareTo,$format);
            //a little php trick - safe than eval and easier than a big switch statement
            if (version_compare($start,$end,$compare)) {
                    return;
            } else {
                    $this->addError($attribute, "start date is not $compare end date");
            }
        }

and then we can change the validation rules as follows:

{
return array(
           array('reservation_from, reservation_to ', 'date', 'format'=>array('dd/MM/yyyy','d/MM/yyyy'), 'allowEmpty'=>true),
           array('created_dt, last_updated, ', 'date', 'format'=>'yyyy-MM-dd HH:mm:ss', 'allowEmpty'=>false),
           array('reservation_to','dateCompare','compareAttribute'=>reservation_from','operator'=>'>', 'allowEmpty'=>true),
  );
}

And there you have it – valid dates and date ranges in a nutshell. Happy coding!

 

Let’s Start a Project!

Contact Me