A Class for Validating and Formatting Dates
By Tony Marston2005-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 DateClassClass Constructor
{
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
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 ()Accept date from the User
{
$this-<monthalpha = array(1=<'Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec');
} // DateClass
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)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
.'([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
$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;
} // ifThe 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;
} // ifThe 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;
} // ifThe 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;
} // ifThe 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;
} // ifThe 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;
} // ifThe 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;
} // ifIf 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';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.
return FALSE;
} // getInternalDate
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
} // ifThis 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;
} // ifNow 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
