DateTime::createFromFormat How to set custom init date - php

At 2022-09-30 i encountered weird behaviour of DateTime::createFromFormat, for pattern 'Y-m' and date '2022-02' it returns 2022-03-02, now i know this is happening cause php will populate missing date values.
But today i wanna write some test cases with pattern !Y-m or Y-m| but i cant reproduce the error because now is 2022-10-03 so $d->createFromFormat('Y-m', '2022-02'); will not overflow to march, so can i somehow force \DateTime::createFromFormat to return value as if it was launched on 2022-09-30 ?
I also tried creating new instance of DateTime and call createFromFormat on it, instead of static call:
$d1 = new \DateTime('2022-09-30');
$d2 = $d1->createFromFormat('Y-m', '2022-02');
print_r($d2->format('Y-m-d')); // returns 2022-02-03, expected 2022-03-02
Also i am using php 7.4

Parsing an incomplete date and defining the missing components user-specifically is possible with the class Dt.
$dateFragment = '2022-02';
$dateInit = '2000-01-15 04:30';
$regEx = '/^(?<Y>\d{4})-(?<m>\d{1,2})$/'; //4 digit year, hyphen, 1-2 digit month
$timeZone = "Europe/Berlin";
$date = Dt::createFromRegExFormat($regEx,$dateFragment,$timeZone,$dateInit);
echo $date->format('Y-m-d H:i'); //2022-02-15 04:30
The dateFragment returns only the month and year. A regular expression defines how the fragment is to be interpreted. Regular expressions are far more powerful than normal formatting. The missing information (day, hour, minute) is taken from dateInit.

The definition of createFromFormat (https://www.php.net/manual/en/datetime.createfromformat.php) says that the arguments are in reverse order.

Related

PHP convert week number and year back to Carbon?

I'm using format W-Y for weeknumber & year.
e.g. the final week of 2018 would be represented as '52-2018'.
But I can't get Carbon or DateTime to convert it back.
>>> Carbon::createFromFormat('W-Y', '01-2018')
InvalidArgumentException with message 'The format separator does not match
The separation symbol could not be found
Trailing data'
DateTime::createFromFormat (which is what Carbon extends) doesn't support the W formatting character, unfortunately.
The easiest way to work around this is to create a new DateTime (or Carbon) instance, and use the native setISODate method to set the year and week number:
$str = '01-2018';
list ($week, $year) = explode('-', $str);
$d = new DateTime;
$d->setISODate($year, $week);
See https://3v4l.org/g33QV
A string of the form '01-2018' can also be converted to '2018W01' with preg_replace, which can then be processed directly by DateTime and Carbon.
$str = '01-2018';
$dateTime = new DateTime(preg_replace('~^(\d\d)-(\d\d\d\d)$~','$2W$1',$str));
While with the accepted solution we always get the current time for the date, here it is always 00:00:00.
Demo: https://3v4l.org/mo6dQ

PHP difference function doesn't format hours and seconds with leading zero [duplicate]

I runned into few examples where people share code for calculating the difference between two days.
Eg.
$now = new DateTime();
$itemDate->diff($now)->format("%r%a")
But almost always these types of posts don't really have an explanation about what format parameters are about. I'm okay with regular Date format parameters but (as in this case) not sure about eg. %r.
When doing difference between DateTimeInterface objects, DateInterval object will be returned. You don't have DateTime's anymore, you have interval, and intervals are formatted different as DateTime objects. Format is explained here: http://php.net/manual/en/dateinterval.format.php
r - Sign "-" when the difference is negative, empty when positive
a - Total number of days as a result of a DateTime::diff() or (unknown) otherwise.
As an example,
<?php
$now = new DateTime();
$d = new DateTime('2019-01-01T15:03:01.012345Z');
$x = $d->diff($now)->format("%r%a");
echo $x;
?>
Output: string(4) "-287"

PHP week date conversion

My date formatted like this "2000-5-1". First digit represents 4 digit year. The second is number of week in year, and the last one represents number of day in week.
No matter what I do, function always returns false, my code is following:
date_create_from_format("Y-W-N", "2000-5-1")
(docs)
Please avoid solutions that are using magic words like "+1 day" etc.
Creating a DateTime object from a compound format with year/week/day is described in the compound formats section of the supported date and time formats section of the PHP Docs:
$x = new DateTime("2000-W05-1");
var_dump($x);
Note that the week number requires a leading zero
Result is a DateTime object for 2000-01-31
If you look at the documantation of DateTime::createFromFormat (which is what you are using with an alias) and date(), there is not a 100% overlap of the formats, so you have a problem.
This is what I found that you could use as an alternative: DateTime::setISODate
$date = explode('-','2000-5-1');
$newDate = new DateTime();
$newDate->setISODate($date[0], $date[1], $date[2]);
setISODate will take the year, week and day as explained in the documentation to create a DateTime object.

Fatal error: Call to a member function format() on boolean passing in Wordpress ACF Datepicker to template

Here is my code:
$original_date = get_field('event_date');
$date = DateTime::createFromFormat('lFdY', strtotime($original_date));
$new_date = $date->format('l, F d, Y');
This code is in a custom post loop in a shortcode and called in the Wordpress admin.
I have also tried it without the strtotime. I am using PHP 5.6.
The event_date field is from an Advance Custom Fields date picker.
If I just pass the field, I get my intended output (the input from the custom post admin page), but without whitespace and commas. I also set this, save and display values in the acf in WP.
This is the error:
Fatal error: Call to a member function format() on boolean on the line
with $new_date variable.
Then if I use:
$date = date("l, F d, Y", strtotime($original_date));
The loop throws an error, undefined variable, for each instance of the post.
You should pass the string directly to the createFromFormat method:
$date = DateTime::createFromFormat('lFdY', $original_date);
The boolean you're receiving is because createFromFormat is failing and returning false.
If you're still receiving an error, get_field() is likely not returning what you think it is.
Try using this .. <?php echo date('l, F d, Y', strtotime(get_field('event_date')));?> it is working at my end
Make sure your get_field('event_date') returns you the date in 20160113 format If not then change the return format from ACF setting in WP back-end.
DateTime::createFromFormat returns false if it fails to convert the input string using the format specified.
In your case, you're taking an $original_date, converting it to a numeric timestamp, and trying to pass that in to DateTime::createFromFormat, which isn't going to work, hence the error. You'll need to pass in the original date instead:
$date = DateTime::createFromFormat('lFdY', $original_date);
PHP currently can not parse that specific format string. You can demonstrate this with an easy case that should "obviously" work. This:
DateTime::createFromFormat('lFdY', date('lFdY', time()));
returns false. The issue is specifically because of the lack of space between l and F in the format string and between the day-of-week and month in your input string.
You should use a different date format. If you can remove the text representation of the day-of-week (because it's not actually necessary to disambiguate the date), or at least get a space between the day-of-week and the month, that would be best.
Since you have existing data in your database in an unhelpful format, you could write a relatively simple pre-processor to remove the day-of-week from the input string:
$new_date = substr($original_date, strpos($original_date, 'y') + 1);
$date = DateTime::createFromFormat('FdY', $new_date);
(This example assumes always english day names, in lowercase, and the input is always valid. You may need more complicated code for your actual data.)
Nitty, gritty details: When PHP processes the l formatter (day of week), it requires seeing one of the characters in: ,;:/.-(), a space, tab, or end-of-string as an indication of where to stop reading.
So, if your date string is FridayJuly082016, because there are no spaces whatsoever in the input date, the code continues reading the entire string, and then fails because (literally) FridayJuly082016 is not in the list of days of the week.
Unfortunately for your particular case, this is also not likely to be "fixed". You have an extremely unusual date format, and making this particular case work in the code would make it considerably more complicated, for a questionable and rare use case.
#jbafford I found a solution.
First I save the date format to yymmdd in the ACF datepicker field
Then I used this code to extract the year month and date separately and then formatted the strtotime result:
$odate = get_field('event_date');
$y = substr($odate, 0, 4); $m = substr($odate, 4, 2); $d = substr($odate, 6, 2);
$new_date = date('l, F j, Y', strtotime("{$d}-{$m}-{$y}"));
What confused me I think and got me hung up was the presumption that I had to pass l or the day into the strtotime and that I had to match input with the intended formatted output. PHP date doesn't need that much info to accomplish the task. Thanks for all of your input!

Convert and insert two date formats MYSQL

I'm facing an issue with managinging dates, some dates pass others dont. I want to produce an insertable date for mysql. there are two possible types of post dates
yyyy-mm-dd //should go without conversion
m/d/yyyy // should be converted
I'm using this
$date = $_REQUEST['date'];
$date_regex = '/(0[1-9]|1[012])[- \/.](0[1-9]|[12][0-9]|3[01])[- \/.](19|20)\d\d/';
if(preg_match($date_regex, $date)){
$date = DateTime::createFromFormat('m/d/Y',$date)->format('Y-m-d');}
problems
I realised this regex is failing for dates like
2/5/2013
but has been working for
12/12/2013
so I removed it BUT still
DateTime::createFromFormat('m/d/Y',$date)->format('Y-m-d');
is also failing for m/d/yyyy
This date thing has got my head spinning for the last 6 hours.
In this case, there is no need to use DateTime::createFromFormat because m/d/yyyy is one of the recognized date formats (see "American month, day and year"). Just convert it to a DateTime object and let the constructor handle the format and forget the regex:
$date = $_REQUEST['date'];
$datetime = new DateTime($date);
$datex = $datetime->format('Y-m-d');
The reason DateTime::createFromFormat('m/d/Y',$date) fails for dates like 2/5/2013 is because you are forcing it to be specifically 'm/d/Y' and that date does not fit that pattern. You can see a list of all date formats here. Specifically, m expects there to be a leading zero (like 02), so when you give it one without that, it won't recognize it. Same goes for d. In this case you would have to use n and j respectively. But, like I said, let the constructor do the hard work for you.

Categories