Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP DateTime::createFromFormat behavoiur

Tags:

date

php

datetime

Today I've encountered something confusing for me with the behaviour of the \DateTime::createFromFormat function.

In my case I have a string, representing the date in the following format m/Y (05/2017). When I want to convert the string to DateTime object I've encountered the following issue:

$date = \DateTime::createFromFormat('m/Y', '02/2017');

When I dump the $date variable, the date property inside is '2017-03-03 11:06:36.000000'

But if I add the date before the month $date = \DateTime::createFromFormat('d/m/Y', '01/02/2017'); I get back an object with correct date property. (unfortunately I cant change the format of the date and add the day. It must be m/Y).

The fix I've come up with is to concatenate the first day of the month to the date string I have $date = '01/'.$dateString; but I rather not to do that because it's hardcoded.

What is wrong here? Does the createFromFormat function lack information of how to create the object? I'm quite confused with this. Thanks for everyone's help in advance!

like image 901
Whiplash Avatar asked May 31 '17 11:05

Whiplash


People also ask

How do we use DateTime objects in PHP give examples?

A few examples of creating DateTime objects with valid time string: $yesterday = new DateTime('yesterday'); $twoDaysLater = new DateTime('+ 2 days'); $oneWeekEarly = new DateTime('- 1 week'); The second parameter of the DateTime's constructor allows us to specify a timezone.

What is the format of DateTime?

For example, the "d" standard format string indicates that a date and time value is to be displayed using a short date pattern. For the invariant culture, this pattern is "MM/dd/yyyy". For the fr-FR culture, it is "dd/MM/yyyy". For the ja-JP culture, it is "yyyy/MM/dd".

What is new DateTime in PHP?

The DateTime::format() function is an inbuilt function in PHP which is used to return the new formatted date according to the specified format.


2 Answers

By default, PHP will populate missing date values with those of the current date/time; so

$date = \DateTime::createFromFormat('m/Y', '02/2017');

will populate the missing day value with the current date; and as 31st February is an invalid date, it will roll forward into March. Likewise, hours/minutes/seconds will be populated with the missing time values based on the current time.

If you want to force the behaviour of forcing to the beginning of the month/time, then modify your mask with a leading !

$date = \DateTime::createFromFormat('!m/Y', '02/2017');

This will populate the missing day with the 1st of the month, and the time with 00:00:00

Alternatively, a trailing | will have the same effect

$date = \DateTime::createFromFormat('m/Y|', '02/2017');
like image 132
Mark Baker Avatar answered Nov 11 '22 19:11

Mark Baker


You cannot store incomplete dates, not at least in a dedicated date format that can be used for complex date calculations (nothing prevents you from creating your own MonthYear class). So when you create a DateTime() object with incomplete information something needs to happen:

  • Crash
  • Use some default values

PHP opts for the second option and makes a decision inherited from the C language date library:

  1. Assume that missing data means "now"
  2. Try to fix automatically the invalid dates that this algorithm can create

In this case, Feb 2017 becomes 31 Feb 2017 (because "now" is 31 May 2017) and PHP follows this reasoning: February only had 28 days in year 2017 but I have three more; the user probably wants to move these three extra days into March. Thus 3 Mar 2017.

I see no reason to avoid hard-coding 01 because, after all, it is a hard-coded value (why the first day of the month and not the last one or any other day?).

$input = '05/2017';
$date = \DateTime::createFromFormat('d/m/Y', "01/$input");
like image 25
Álvaro González Avatar answered Nov 11 '22 19:11

Álvaro González