Helping ordinary people create extraordinary websites!
HOME TUTORIALS SCRIPTS WEB HOSTING BLOG FORUM
Get Our Newsletter
Email:

A Class for Validating and Formatting Dates

By Tony Marston
2005-04-16


Defining the Class to Handle Dates

Class Variables

We must start by defining our date class and the class variables which we would like to persist between one function call and the next:

class DateClass

{
var $monthalpha; // array of 3-character month names
var $internaldate; // date as held in the database (yyyymmdd)
var $externaldate; // date as shown to the user (dd Mmm yyyy)
var $errors; // error messages
Class Constructor

This is followed by what is known as the 'class constructor', a function which is called automatically when an instance of this class is created. In PHP4 the name of the constructor is the same as the class name. It is used here to construct an array of month names. Note that we are forcing the index number to start at 1 instead of the default of 0.

 function DateClass ()

{
$this-<monthalpha = array(1=<'Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec');

} // DateClass
Accept date from the User

The first method (function) in this class will accept input from the user, validate it, and format it ready for writing to the database. The user may input a date in a number of different ways, so we will use regular expressions to help us decipher the user's input.

With regular expressions we can supply a pattern with any number of component parts, and if the input string matches the pattern each part of the input which matched a part of the pattern is placed in an output array.

The first regular expression will look for input in the format d(d)?m(m)?y(yyy) (1 or 2 digits, a separator, 1 or 2 digits, a separator, then 1-4 digits). For a separator I am allowing any character which is not a number or a letter.

function getInternalDate ($input)

{

$pattern = '(^[0-9]{1,2})' // 1 or 2 digits
.'([^0-9a-zA-Z])' // not alpha or numeric
.'([0-9]{1,2})' // 1 or 2 digits
.'([^0-9a-zA-Z])' // not alpha or numeric
.'([0-9]{1,4}$)'; // 1 to 4 digits

if (ereg($pattern, $input, $regs)) {
$result = $this-<verifyDate($regs[1],$regs[3],$regs[5]);
return $result;
} // if
If this fails the next regular expression will look for input in the format d(d)?MMM?y(yyy).
$pattern = '(^[0-9]{1,2})'    // 1 or 2 digits

.'([^0-9a-zA-Z])' // not alpha or numeric
.'([a-zA-Z]{1,})' // 1 or more alpha
.'([^0-9a-zA-Z])' // not alpha or numeric
.'([0-9]{1,4}$)'; // 1 to 4 digits

if (ereg($pattern, $input, $regs)) {
$result = $this->verifyDate($regs[1],$regs[3],$regs[5]);
return $result;
} // if
The next regular expression will look for input in the format d(d)?MMM?y(yyy).
$pattern = '(^[0-9]{1,2})'    // 1 or 2 digits

.'([a-zA-Z]{1,})' // 1 or more alpha
.'([0-9]{1,4}$)'; // 1 to 4 digits

if (ereg($pattern, $input, $regs)) {
$result = $this->verifyDate($regs[1],$regs[2],$regs[3]);
return $result;
} // if
The next regular expression will look for input in the format MMM?d(d)?y(yyy).
     $pattern = '(^[a-zA-Z]{1,})'  // 1 or more alpha

.'([^0-9a-zA-Z])' // not alpha or numeric
.'([0-9]{1,2})' // 1 or 2 digits
.'([^0-9a-zA-Z])' // not alpha or numeric
.'([0-9]{1,4}$)'; // 1 to 4 digits

if (ereg($pattern, $input, $regs)) {
$result = $this->verifyDate($regs[3],$regs[1],$regs[5]);
return $result;
} // if
The next regular expression will look for input in the format MMMddyyyy.
      $pattern = '(^[a-zA-Z]{1,})'  // 1 or more alpha

.'([0-9]{2})' // 2 digits
.'([0-9]{4}$)'; // 4 digits

if (ereg($pattern, $input, $regs)) {
$result = $this->verifyDate($regs[2],$regs[1],$regs[3]);
return $result;
} // if
The next regular expression will look for input in the format yyyy?m(m)?d(d).
      $pattern = '(^[0-9]{4})'      // 4 digits

.'([^0-9a-zA-Z])' // not alpha or numeric
.'([0-9]{1,2})' // 1 or 2 digits
.'([^0-9a-zA-Z])' // not alpha or numeric
.'([0-9]{1,2}$)'; // 1 to 2 digits

if (ereg($pattern, $input, $regs)) {
$result = $this->verifyDate($regs[5],$regs[3],$regs[1]);
return $result;
} // if
The next regular expression will look for input in the format ddmmyyyy.
      $pattern = '(^[0-9]{2})'      // 2 digits

.'([0-9]{2})' // 2 digits
.'([0-9]{4}$)'; // 4 digits

if (ereg($pattern, $input, $regs)) {
$result = $this->verifyDate($regs[1],$regs[2],$regs[3]);
return $result;
} // if
The next regular expression will look for input in the format yyyy?MMM?d(d).
      $pattern = '(^[0-9]{4})'      // 4 digits

.'([^0-9a-zA-Z])' // not alpha or numeric
.'([a-zA-Z]{1,})' // 1 or more alpha
.'([^0-9a-zA-Z])' // not alpha or numeric
.'([0-9]{1,2}$)'; // 1 to 2 digits

if (ereg($pattern, $input, $regs)) {
$result = $this->verifyDate($regs[5],$regs[3],$regs[1]);
return $result;
} // if
If we get to this point in the code it means that we have not found a match against any of those patterns, so we generate an error message and return an empty result to the user.
      $this->errors = 'This is not a valid date';

return FALSE;

} // getInternalDate
You may have noticed that after matching the input to a pattern function called verifyDate was called. Here is the contents of that function, with verifies that the component parts actually constitute a valid date.
   function verifyDate($day, $month, $year)

{
This first part will check for the month being supplied as characters instead of numbers, and perform a lookup on the array of month names created in the class constructor. Note that it uses strtolower() to convert the user's input to lowercase, then ucfirst() to make the first character uppercase. This is done to match the contents of $this->monthalpha.
      if (eregi('([a-z]{3})', $month)) {

$month = ucfirst(strtolower($month));
if (!$month = array_search($month, $this->monthalpha)) {
$this->errors = 'Month name is invalid';
return FALSE;
} // if
} // if
This next part will check that the year has 4 digits, filling in anything that is missing:
      if (strlen($year) == 1) {

$year = '200' .$year;
} // if
if (strlen($year) == 2) {
$year = '20' .$year;
} // if
if (strlen($year) == 3) {
$year = '2' .$year;
} // if
Now we can use the PHP checkdate() function to check that this is a valid date, and if it is we can change the format to ccyy-mm-dd ready for writing to the database.
      if (!checkdate($month, $day, $year)) {

$this->errors = 'This is not a valid date';
return FALSE;
} else {
if (strlen($day) < 2) {
$day = '0' .$day; // add leading zero
} // if
if (strlen($month) < 2) {
$month = '0' .$month; // add leading zero
} // if
$this->internaldate = $year .'-' .$month .'-' .$day;
return $this->internaldate;
} // if

return;

} // verifyDate


Tutorial Pages:
» A Class for Validating and Formatting Dates
» Defining the Class to Handle Dates
» Display date to the User
» Incrementing or Decrementing a Date
» Using this Class in Your Code
» Summary


 | Bookmark
Related Tutorials:
» Zend Framework Tutorial
» Port Scanning and Service Status Checking in PHP
» Web Database Access from Desktop Applications
» CubeCart 3.0 Installation and Configuration
» PHP Site Search Made Easy
» Installing and Configuring Drupal 6.1