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!
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.
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".
The DateTime::format() function is an inbuilt function in PHP which is used to return the new formatted date according to the specified format.
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');
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:
PHP opts for the second option and makes a decision inherited from the C language date library:
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");
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With