验证ISO 8601日期字符串


Validate ISO 8601 date string

如何验证ISO 8601日期字符串(例如:2011-10-02T23:25:42Z)

我知道ISO 8601日期有几种可能的表示形式,但我只对验证我上面给出的示例格式感兴趣。

这对我来说很有效,它使用一个正则表达式来确保日期是您想要的格式,然后尝试解析日期并重新创建它以确保输出与输入匹配:

<?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;
    }
}

您可以进一步扩展使用checkdate来确保月、日和年也是有效的

我想分享我的轻量级解决方案。这是不理想的,但可能对某些人有帮助。

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;
}
(4)

!

一些有效的ISO8601日期将失败查看下面的列表

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:到目前为止,最简单的方法是简单地尝试使用字符串创建DateTime对象,例如

$dt = new DateTime($dateTimeString);

如果DateTime构造函数不能解析字符串,它将抛出异常,例如

DateTime::__construct(): Failed to parse time string (2011-10-02T23:25:72Z) at position 18 (2): Unexpected character

注意,如果不使用时区指示符,它将使用配置的默认时区。

第二个最简单的方法是使用正则表达式。像这样的东西可以覆盖它

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
}

参见http://www.pelagodesign.com/blog/2009/05/20/iso-8601-date-validation-that-doesnt-suck/。它给出了这个正则表达式:

^(['+-]?'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)?)?)?)?$

我想这并不能完全回答你的问题,因为它将匹配任何有效的ISO 8601日期,但如果这是正确的,那么它就可以完美地工作。

这是我使用的函数。它类似于drew010的答案,但也适用于以"+01:00"或"-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;
    }
}

Carbon处理的很好

use Carbon'Carbon;
use Carbon'Exceptions'InvalidFormatException;
...
/** @test */
public function checking_iso8601_date()
{
    $this->expectException(InvalidFormatException::class);
    Carbon::createFromFormat('c', '2021-05-11 20:03:45+02:00');
    $this->assertInstanceOf(Carbon::class, Carbon::createFromFormat('c', '2021-05-11T20:03:45+02:00'));
}

您可以对DateTime

执行相同的操作
use DateTime;
...
/** @test */
public function checking_iso8601_date()
{
    $this->assertInstanceOf(DateTime::class, DateTime::createFromFormat('Y-m-d'TH:i:sP', '2021-05-11T20:03:45+02:00'));
    $this->assertFalse(DateTime::createFromFormat('Y-m-d'TH:i:sP', '2021-05-11 20:03:45+02:00'));
}