PHP Dates are frustrating me - php

I'm trying to validate input in mm/yyyy format by round tripping a string. The problem:
<?php
$datestr = "06/2017";
$realdate = DateTime::createFromFormat('m/Y', $datestr);
$datestr2 = date_format($realdate,'m/Y');
echo "date in: $datestr\n";
echo "date out: $datestr2\n";
?>
yields the following:
date in: 06/2017
date out: 07/2017
Why is the second value incremented a month?

Because you did not specify a day it assumes today (the 31st). There is no June 31st so PHP assumes July 1st.
Assuming you are always working with the date formats you use in your example, you can easily work around this by specifying the first of the month for your dates:
$datestr = "01/06/2017";
$realdate = DateTime::createFromFormat('d/m/Y', $datestr);
$datestr2 = date_format($realdate,'m/Y');
echo "date in: $datestr\n";
echo "date out: $datestr2\n";
Demo

It is not necessary to include the day '01'. A ! in the Format resets all fields (year, month, day, hour, minute, second). Without !, all fields will be set to the current date and time. (-> PHP Manual)
$datestr = "06/2017";
$realdate = DateTime::createFromFormat('!m/Y', $datestr);
var_dump($realdate);
/*
object(DateTime)#2 (3) {
["date"]=> string(26) "2017-06-01 00:00:00.000000"
["timezone_type"]=> int(3)
["timezone"]=> string(13) "Europe/Berlin"
}
*/
With the ! a non-existent day is always set to 1 and the time to 00:00:00. If only the day is set, as in John Conde's solution, the date always contains the current time.

Related

DateTime not working for dates before 1970 [duplicate]

This question already has an answer here:
Create Date object in PHP for dates before 1970 in certain format
(1 answer)
Closed 4 years ago.
PHP v 5.6.2
I need to convert dates such as 18-Jul-46 to give me 18/07/1946 and no amount of DateTime functions work correctly. (As strtotime wont work for dates before 1970). They all end up giving 18/07/2046 which is incorrect.
Codes I tried so far:
$date = new DateTime("18-Jul-46");
$date->format('d/m/Y');
Another one with DateTime
$date = DateTime::createFromFormat('d-M-y', "18-Jul-46");
$date->format('d/m/Y');
Earlier also tried,
$date = date('d/m/Y', strtotime('18-Jul-46'));
None of them gave me the correct format. Any pointers or help is appreciated.
Thanks in advance!
If you have a date such as '31-Dec-18", it is ambiguous since it may refer to a date in 1918 or else a date in 2018. However, if you know that all the dates refer to the 1900s, then code such as the following is feasible given a two-digit year:
<?php
$now = new DateTime();
$formatted = "";
$arrFormattedBDays = [];
$birthdays = ['18-Jul-46','19-Aug-47','1-Jan-19','31-Dec-18'];
foreach ($birthdays as $b){
list($d,$m,$y) = explode("-",$b);
$y = '19'.$y;
$dt = new DateTime("$d-$m-$y");
$formatted = $dt->format('d/m/Y');
$arrFormattedBDays[] = $formatted;
}
var_dump($arrFormattedBDays);
Output:
array(4) {
[0]=>
string(10) "18/07/1946"
[1]=>
string(10) "19/08/1947"
[2]=>
string(10) "01/01/1919"
[3]=>
string(10) "31/12/1918"
See live code
Otherwise, by default DateTime creates a date object based on the current year which you may format according to the truth you seek to perpetuate; see here. Note: if you know that the dates all occur in the 20th century, i.e. 1901-2000, then you may amend this code by adding in a little logic; see here.
The computer doesn't know whether you mean 2000 or 1900. You can just take the last 2 digits of the year and put "19" before like:
$date = new DateTime("18-Jul-46");
$date->format('d/m/19y');
If you want to use 2000 as well, this code will use the closest number to 1970
$date = new DateTime("18-Jul-20");
$date->format('d/m/Y');
$t1 = $date->format('19y');
$t2 = $date->format('20y');
if(abs(1970-$t1)<abs(1970-$t2))
echo $t1; //Take the 19.. one
else
echo $t2; //Take the 20.. one
But in the end, you can't be sure that even 2030 would be correct.

php/mysql: strToTime error manipulating dates

I have some code for rendering dates that was working great for a couple of years and is now broken. I don't know if it has something to do with my host changing version of PHP or somehow an error crept in.
Basically, dates such as 11/30/15 are now getting rendered as 11/30/-1
Here is an example of what is going on:
$olddate = $row['date'];//in database this looks like:0000-00-00 00:00:00
$newdate = nicedate($olddate);
echo "starting date time: ".$olddate;//displays as 'starting date time: 0000-00-00 00:00:00'
echo "after transforming it with nice date: ".$newdate; //displays as 'after transforming it with nice date: 11/30/-1'
I also tried just running strtotime and get this:
echo "after transforming it with strtotime: ".nicedate($row['starttime']);//-62169966000
// gets nice data
function nicedate($datetime) {
$niceDate = strtotime($datetime);
$niceDate = date("m/d/y",$niceDate);
return $niceDate;
}
As you can see here https://3v4l.org/8gqCK it really depends on which PHP version you are using.
PHP will render the string 0000-00-00 00:00:00 to -0001-11-30 00:00:00.000000
This is an example output from DateTime:
object(DateTime)#1 (3) {
["date"]=>
string(27) "-0001-11-30 00:00:00.000000"
["timezone_type"]=>
int(3)
["timezone"]=>
string(13) "Europe/Berlin"
}
The OUTPUT also depends on the time zone:
object(DateTime)#1 (3) {
["date"]=>
string(27) "-0001-11-29 23:06:32.000000"
["timezone_type"]=>
int(3)
["timezone"]=>
string(3) "UTC"
}
This would output:
...with nice date: 11/29/-1
And here strtotime():
int(-62169987208)
So you see the date function were changed on different version, what you can do now ist just to check if the date is 0000-00-00 00:00:00:
function nicedate ( $datetime ) {
if( $datetime == "0000-00-00 00:00:00" ) return "Some value or false?";
...
...
}
You also have a look at the MySQL mode: NO_ZERO_IN_DATE
Updated approach due to the comments below:
function nicedate( $datetime ) {
if( !validateDate( $datetime ) ) return "something";
$dateTimeObject = DateTime::createFromFormat('Y-m-d H:i:s', $datetime );
return $dateTimeObject->format( "m/d/y" );
}
function validateDate($date) {
$d = DateTime::createFromFormat('Y-m-d H:i:s', $date);
return $d && $d->format('Y-m-d H:i:s') == $date;
}
function was copied from this answer or php.net
This is because 0000-00-00.... is not a valid date. What happens is simple, from year, month, day,... is alway one (1) substracted from the last.
0000 -1 = -1// year
00 - 1 = 11// month, because 12 is the highest value that datetime recognizes as month
00 - 1 = 30// day, because 31 is the highest value that datetime recognizes as day
For hours, minutes, seconds,.. it's ok, because zero is a valid value for time.
That's why it is rendered like this: -0001-11-30 00:00:00.000000

How can I set Zend DateTime Element to '0000-00-00 00:00:00'?

I am using the Zend Framework 2 DateTimeSelect. How can I set the value (either in the form class or controller) to '0000-00-00 00:00:00'? Currently it defaults to the end of the year. I get the following results when i try the following in the controller...
$date = date("0-0-0 0:0:0"); `This gives me the date as November 30th`
$date = '0000-00-00 00:00:00';`This gives me the date as November 30th`
$date = NULL; `This gives me the current date time.`
$form->get('datetime')->setValue($date);
I would like to leave this field either empty or as 0 until the task is complete.
Many Thanks
Matt
You might have a misconception as to how years are counted arround the 1 b.c and 1 a.d mark.
The last day month and year of before christus is 30th of december 1 b.c. Right after that follows the 1st January 1 a.d(Anno Domini). Historically speaking there is no year 0 it start's with year one.
Which means if we create DateTime Object and set a date to day=0, month=0, year=0 will still be in the before christus date region.
$test = new DateTime();
$test->setDate(0, 0, 0);
//I left out timezone settings so it'll take the default timezone
var_dump($test); exit;
would outup:
object(DateTime)#1 (3) { ["date"]=> string(20) "-0001-11-30 00:00:00" ["timezone_type"]=> int(3) ["timezone"]=> string(13) "Europe/Berlin" }
-0001-11-30 looks a bit weird since php counts months beginning with 0 = January, .... , 11 = December.
Now unlike the setDate method the constructor takes strings as a parameter which gets parsed into the Time Object. Which basically calls the set Date method at the end with the same
day = 0
month = 0
year = 0
which again would output:
object(DateTime)#1 (3) { ["date"]=> string(20) "-0001-11-30 00:00:00" ["timezone_type"]=> int(3) ["timezone"]=> string(13) "Europe/Berlin" }
This leads me to the conclusion that getting the out of the box DateTime Object Class to render the specific date "0000-00-00:00:00:00" is literary impossible and historically incorrect.
Could you please elaborate as to why you want to this in detail?

date_create_from_format php on certain month and date does not return correct date

I have a function in php that uses the date_create_from_format function to convert dates in format 'Ym' to datetime. It works correctly except in one case I found today and I cant find the problem. The situation is the following:
Current date: 07/31/2014.
$period value: '201409' (as the month I want to do some calc on)
$newDateCreated = date_create_from_format('Ym', $period);
This returns a new datetime created but with the value of 10/01/2014 instead of 09/01/2014
If instead of setting the value 201409 I put 201411 or 201408 the new datetime is created correctly.
The only solution I found to this was to replace
$newDateCreated = date_create_from_format('Ym', $period);
for
$newDateCreated = date_create_from_format('Ymd', $period.'01');
I believe that this have to be something with the day of the month but I cant find the real problem. Any ideas about this?
Thanks in advance.
As from the manual:
If format does not contain the character ! then portions of the
generated time which are not specified in format will be set to the
current system time.
If format contains the character !, then portions of the generated
time not provided in format, as well as values to the left-hand side
of the !, will be set to corresponding values from the Unix epoch.
The Unix epoch is 1970-01-01 00:00:00 UTC.
Example
date_create_from_format('Ym', '201409');
// Tries '2014-09-31 15:59:45', but since that date doesn't exists
// that becomes '2014-10-01':
// object(DateTime)#62 (3) {
// ["date"] => string(19) "2014-10-01 15:59:45"
// ["timezone_type"] => int(3)
// ["timezone"] => string(16) "Europe/Amsterdam"
// }
date_create_from_format('!Ym', '201409');
// object(DateTime)#62 (3) {
// ["date"] => string(19) "2014-09-01 00:00:00"
// ["timezone_type"] => int(3)
// ["timezone"] => string(16) "Europe/Amsterdam"
// }

How to parse YouTube returned date to timestamp?

YouTube returns the Updated date and Submitted on date as follows: 2010-08-22T04:46:18.000Z
Is there a PHP function, or a date mask that parses this?
$dt = DateTime::createFromFormat("Y-m-d\TH:i:s.uP", "2010-08-22T04:46:18.000Z");
var_dump($dt);
// object(DateTime)#1 (3) {
// ["date"]=>
// string(26) "2010-08-22 04:46:18.000000"
// ["timezone_type"]=>
// int(2)
// ["timezone"]=>
// string(1) "Z"
// }
This uses the DateTime class. It is timezone and fractional seconds aware. To display the date use the format method:
echo $dt->format("Y-m-d H:i:s e");
// 2010-08-22 04:46:18 Z
To convert the date to local timezone use the setTimezone method:
$dt->setTimezone(new DateTimeZone(date_default_timezone_get()));
echo $dt->format("Y-m-d H:i:s e");
// 2010-08-21 21:46:18 America/Los_Angeles
sounds like strtotime is what you're looking for.
EDIT: if this doesn't work, take a look at the Date and Time classes - there are methods for parsing dates in specified formats (like this - doesn't return a timestamp directly, but if you construct a DateTime from this, you can use it's getTimestamp-method)
Try this:
$date=substr("2010-08-22T04:46:18.000z",0,strlen("2010-08-22T04:46:18.000z")-1);
$stamp=strtotime($date);
The "z" at the end seems to be the problem for strtotime.

Categories