PHP验证ISO 8601日期字符串

PHP验证ISO 8601日期字符串,php,validation,iso8601,Php,Validation,Iso8601,如何验证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';

如何验证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;
    }
}

编辑:到目前为止,最简单的方法是使用字符串创建一个
DateTime
对象,例如

$dt = new DateTime($dateTimeString);
如果
DateTime
构造函数无法解析字符串,它将抛出异常,例如

DateTime::_构造():无法分析位置18(2)处的时间字符串(2011-10-02T23:25:72Z):意外字符

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

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

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
}
看。它使该正则表达式可以使用:

^([\+-]?\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 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

一些有效的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!

碳处理这部分真的很好

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'));
}

这看起来不对。“白天”部分不应该是两位数吗?@Phil-我想你是对的。我更新了帖子以反映这一点。a)不要使用不区分大小写的标志
T
Z
是唯一适用的字母字符,两者都应为大写。b)
Z
不是唯一有效的时区指示器。请参见,您还应该允许在日期字符串()前面添加可选的
+
-
。可能一个
([+|-]?)
就足够了,但是DateTime构造函数并不局限于ISO 8601输入。@Grayside我不太清楚你的意思。我没有说这件事limited@Phil如果你想检查它是否是一个有效的iso日期,那么让它允许其他非iso的日期格式就不会验证iso格式。这似乎是最干净的方法,除了时区偏移可以包括冒号或不在标准中之外,但是date函数是否使用它取决于是使用date_ISO8601还是“c”来指定格式。
strotime($value)$value
不可解析,则code>返回
false
<代码>$date=date(date_ISO8601,$timestamp)带有
$timestamp=false包含最小日期(1970-01-01T01:00:00+0100)。所以这个例子很糟糕。不要使用@MrBoolean,对。然后将“1970-01-01T01:00:00+0100”与
$value
进行比较,并返回
false
。但是
strotime
还将解析类似于一天前的
2015-01 first
等内容。此时此函数失败。我已修复此函数,现在它适用于所有正确的类型。此正则表达式甚至将类似字符串的
3401
视为有效日期。使用风险自负。
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'));
}