A Class for Validating and Formatting Dates
by Tony MarstonTonyMarston.net
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
{
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
{
$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
.'([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;
} // if
The next regular expression will look for input in the format d(d)?MMM?y(yyy). .'([^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
$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). .'([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
$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. .'([^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
$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). .'([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
$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. .'([^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
$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). .'([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
$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. .'([^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
$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. 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
} // if
This next part will check that the year has 4 digits, filling in anything that is missing: $month = ucfirst(strtolower($month));
if (!$month = array_search($month, $this->monthalpha)) {
$this->errors = 'Month name is invalid';
return FALSE;
} // if
} // if
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. $year = '200' .$year;
} // if
if (strlen($year) == 2) {
$year = '20' .$year;
} // if
if (strlen($year) == 3) {
$year = '2' .$year;
} // if
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
$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
Options:
Printer Friendly
Email Friend
About The Author:
I have been a software engineer, both designing and developing, since 1977. I have worked with a variety of 2nd, 3rd and 4th generation languages on a mixture of mainframes, mini- and micro-computers. I have worked with flat files, indexed files, hierarchical databases, network databases and relational databases. The user interfaces have included punched card, paper tape, teletype, block mode, CHUI, GUI and web. I have written code which has been procedural, model-driven, event-driven, component-based and object oriented. I have built software using the 1-tier, 2-tier, 3-tier and Model-View-Controller (MVC) architectures. After working with COBOL for 16 years I switched to UNIFACE in 1993, starting with version 5, then progressing through version 6 to version 7. In the middle of 2002 I decided to teach myself to develop web applications using PHP and MySQL.
I have been a software engineer, both designing and developing, since 1977. I have worked with a variety of 2nd, 3rd and 4th generation languages on a mixture of mainframes, mini- and micro-computers. I have worked with flat files, indexed files, hierarchical databases, network databases and relational databases. The user interfaces have included punched card, paper tape, teletype, block mode, CHUI, GUI and web. I have written code which has been procedural, model-driven, event-driven, component-based and object oriented. I have built software using the 1-tier, 2-tier, 3-tier and Model-View-Controller (MVC) architectures. After working with COBOL for 16 years I switched to UNIFACE in 1993, starting with version 5, then progressing through version 6 to version 7. In the middle of 2002 I decided to teach myself to develop web applications using PHP and MySQL.
