Check string is valid date in Carbon with overflow and relative format flags

Viewed 1962

I need a method like this:

function check_date_format($date, $allowOverflow = false, $allowRelativeFormats = false)

which was return bool if string is correct date/time according to the boolean flags.

Where $allowOverflow = false means dates that are overflow like 2020-13-13 (2021-01-13) are not correct, and $allowRelativeFormats = false means that relative dates like 'today', 'tomorow' 'x day ago' etc. are incorrect

There is any possibility to write that functions using Carbon / DateTime class without defining own arrays like $availableFormats inside this function?

Examples to understood my expected result:

check_date_format('asdgasd'); // false
check_date_format('2020-02-01'); // true
check_date_format('2020-02-30'); // false
check_date_format('2020-02-30', true); // true
check_date_format('10:00'); // true
check_date_format('tomorrow'); // false
check_date_format('tomorrow', false, true); // true
check_date_format('now'); // false

I tried to use date_parse() in such way:

function check_date_format($date, $allowOverflow = false, $allowRelativeFormats = false)
{
    $dateInfo = date_parse($date);
    $isCorrectDate = $dateInfo['error_count'] === 0;
    if ($isCorrectDate) {
        $isRelative = array_key_exists('relative', $dateInfo);
        $isOverflowed = $dateInfo['warning_count'] > 0;

        if (!$allowOverflow && $isOverflowed) {
            return false;
        }
        if (!$allowRelativeFormats && ($isRelative || strtolower(trim($date)) === 'now')) {
            return false;
        }
        return true;
    }
    return false;
}

but this solution assumes that 'warnings' means overflows which I'm not sure.

1 Answers

Checking if a date can be created can be done by simply trying it:

try {
    $date = @Carbon::parse('asdgasd');
} catch (InvalidFormatException $_) {
    $date = false;
}

$canBeCreated = ($date !== false);

Checking if a string is a relative format is supported out of the box by Carbon:

$hasRelativeFormat = Carbon::hasRelativeKeywords('tomorrow');

But for the overflow, there is no way that could handle all formats at once. For instance if you have strict format input you can check overflow happened or not:

Carbon::parse('2020-02-01')->format('Y-m-d') === '2020-02-01'; // true => no overflow
Carbon::parse('2020-02-30')->format('Y-m-d') === '2020-02-30'; // false => overflow

But this trick is no longer possible if "January 1st 2020" is allowed. And the overflow actually happen inside PHP timelib extension (inside new DateTime() constructor), this behavior is not part of the library code, so it's on your business-side code to decide what input to allow if you want to restrict it and decide how to detect an overflow happened.

Generally speaking, it can be safer not to mix all those checks in one single function with a matrix of boolean flags making various combinations of checks, I would rather keep them separated.

Related