PHP validate ISO 8601 date string

后端 未结 5 1557
半阙折子戏
半阙折子戏 2020-12-15 06:02

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

相关标签:
5条回答
  • 2020-12-15 06:32

    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.

    0 讨论(0)
  • 2020-12-15 06:36

    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.

    0 讨论(0)
  • 2020-12-15 06:38

    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;
        }
    }
    
    0 讨论(0)
  • 2020-12-15 06:42

    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!
    
    0 讨论(0)
  • 2020-12-15 06:47

    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
    }
    
    0 讨论(0)
提交回复
热议问题