How do you validate ISO 8601 date string (ex: 2011-10-02T23:25:42Z).
I know that there are several possible representations of ISO 8601 dates, but I\'m only interest
See http://www.pelagodesign.com/blog/2009/05/20/iso-8601-date-validation-that-doesnt-suck/. It gives this regex to use:
^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-3])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$
I suppose this does not answer your question exactly, since it will match any valid ISO 8601 date, but if that is alright then this works perfectly.
This worked for me, it uses a regular expression to make sure the date is in the format you want, and then tries to parse the date and recreate it to make sure the output matches the input:
<?php
$date = '2011-10-02T23:25:42Z';
var_dump(validateDate($date));
$date = '2011-17-17T23:25:42Z';
var_dump(validateDate($date));
function validateDate($date)
{
if (preg_match('/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})Z$/', $date, $parts) == true) {
$time = gmmktime($parts[4], $parts[5], $parts[6], $parts[2], $parts[3], $parts[1]);
$input_time = strtotime($date);
if ($input_time === false) return false;
return $input_time == $time;
} else {
return false;
}
}
You could expand further to use checkdate to make sure the month day and year are valid as well.
This is the function I use. It is similar to the answer of drew010 but works also for timestamps ending with "+01:00" or "-01:00".
function isTimestampIsoValid($timestamp)
{
if (preg_match('/^'.
'(\d{4})-(\d{2})-(\d{2})T'. // YYYY-MM-DDT ex: 2014-01-01T
'(\d{2}):(\d{2}):(\d{2})'. // HH-MM-SS ex: 17:00:00
'(Z|((-|\+)\d{2}:\d{2}))'. // Z or +01:00 or -01:00
'$/', $timestamp, $parts) == true)
{
try {
new \DateTime($timestamp);
return true;
}
catch ( \Exception $e)
{
return false;
}
} else {
return false;
}
}
I want to share my lightweight solution. It is not ideal, but might be helpful for someone.
function validISO8601Date($value)
{
if (!is_string($value)) {
return false;
}
$dateTime = \DateTime::createFromFormat(\DateTime::ISO8601, $value);
if ($dateTime) {
return $dateTime->format(\DateTime::ISO8601) === $value;
}
return false;
}
Atention!
Some valid ISO8601 dates will fail Look at the list below
NOT VALID --> '' // Correct
NOT VALID --> 'string' // Correct
VALID --> '2000-01-01T01:00:00+1200' // This is the only format function returns as valid
NOT VALID --> '2015-01 first' // Correct
NOT VALID --> '2000-01-01T01:00:00Z' // Must be valid!
NOT VALID --> '2000-01-01T01:00:00+01' // Must be valid!
Edit: By far the easiest method is to simply try to create a DateTime
object using the string, eg
$dt = new DateTime($dateTimeString);
If the DateTime
constructor cannot parse the string, it will throw an exception, eg
DateTime::__construct(): Failed to parse time string (2011-10-02T23:25:72Z) at position 18 (2): Unexpected character
Note that if you leave off the time zone designator, it will use the configured default timezone.
Second easiest method is to use a regular expression. Something like this aught to cover it
if (preg_match('/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(Z|(\+|-)\d{2}(:?\d{2})?)$/', $dateString, $parts)) {
// valid string format, can now check parts
$year = $parts[1];
$month = $parts[2];
$day = $parts[3];
// etc
}