Viewed   145 times

Hi I seem to be having trouble getting the datetime method to work as expected? I may be doing something wrong?

// Passes OK 
$dateTime = DateTime::createFromFormat('d/m/Y', '12/12/2012' );
var_dump($dateTime);

// should fail but returns  - 2016-09-25 
$dateTime = DateTime::createFromFormat('d/m/Y', '56/56/2012' );
var_dump($dateTime);

// correctly returns False 
$dateTime = DateTime::createFromFormat('d/m/Y', '56/56/fail' );
var_dump($dateTime);

// should fail but returns 2019-08-29 09:58:10
$dateTime = DateTime::createFromFormat('m/d/Y', '90/90/2012' );
var_dump($dateTime);

 Answers

1

The thing about DateTime::createFromFormat is that there are two kinds of unexpected input it recognizes: the kind that generates errors, and the kind that generates warnings.

Input such as '56/56/fail' produces an error, so false is returned and everything is good. However, '56/56/2012' gives not an error but a warning, and is actually parsed as the 56th day of the 56th month of 2012. Since 2012 does not have 56 months, PHP internally changes this to 2016 + 8 months = Aug 2016. And since that month does not have 56 days, we have another compensation to Sep 2016 + (56 - 31) days = 25 Sep 2016. So while unexpected, this is in fact correct.

If you want to disallow this automatic adjustment, you have to wrap the DateTime factory method and use DateTime::getLastErrors as reference:

$dateTime = DateTime::createFromFormat('d/m/Y', '56/56/2012');
$errors = DateTime::getLastErrors();
if (!empty($errors['warning_count'])) {
    echo "Strictly speaking, that date was invalid!n";
}

See it in action.

Wednesday, August 24, 2022
5

This is the way to go. However, since what seems you want to do is to render the DateTime class extensible, I'd suggest you use static instead of self:

namespace NoiseLabsDateTime;

class DateTime extends DateTime
{
    static public function createFromFormat($format, $time)
    {
        $ext_dt = new static();
        $parent_dt = parent::createFromFormat($format, $time);

        if (!$parent_dt) {
            return false;
        }

        $ext_dt->setTimestamp($parent_dt->getTimestamp());
        return $ext_dt;
    }
}

It's not necessary if you don't plan on extending the class, but if someone ever does, it will prevent him from having to do the same workaround again.

Monday, November 7, 2022
3

You need to use the ISO-8601 week numbering year which is o if you want the year for the ISO-8601 week. From the docs:

ISO-8601 week-numbering year. This has the same value as Y, except that if the ISO week number (W) belongs to the previous or next year, that year is used instead. (added in PHP 5.1.0)

$dueDate->format('W , o');
Thursday, December 15, 2022
 
1

That is the expected behaviour, the subtraction acts on the original object which is then returned. This can be seen by the 246 in the var_dump() outputs, denoting that they're one and the same object.

If you wish to keep the original object untouched, you'll need to clone it before doing the subtraction.

$currentDT   = new DateTime('2011-12-13 14:15:16');
$filterRange = new DateInterval('PT30S');
$filterDate  = clone $currentDT;
$filterDate->sub($filterRange);
var_dump($currentDT, $filterDate);
Monday, November 14, 2022
 
2

The reason for this behaviour is that when you don't specify the missing parts of a date/time input to DateTime::createFromFormat, it uses the values from the current local date and time. In Auckland, that is October 31st and so it tries to make a date out of September 31 2019, which comes out as October 1 2019. To avoid this problem, use a ! at the start of the format string; this will instead substitute values from January 1 1970, 00:00:00 (the Unix Epoch) as required for those that are not specified in the time value:

echo DateTime::createFromFormat('!F-Y', 'September-2019')
    ->setTimeZone(new DateTimeZone('Pacific/Auckland'))
    ->format('Y-m-d');

Output:

2019-09-01

Demo on 3v4l.org

Monday, November 7, 2022
Only authorized users can answer the search term. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :