The goal is to diff two dates.
I have a DateTime object stored in my db table under timestamp column. I use Doctrine to retrieve the date, Once retrieved the date from my db it looked like this by var_dump;
array(1) {
[0]=>
array(1) {
["timestamp"]=>
object(DateTime)#321 (3) {
["date"]=>
string(26) "2016-08-03 11:03:36.000000"
["timezone_type"]=>
int(3)
["timezone"]=>
string(13) "Europe/London"
}
}
}
the retrieved object was assigned to a $result variable now to get to the DateTime object I did this $result[0][timestamp].
To retrieve the actual data i did this $date1 = $result->format('Y-m-d H:i:s'); according to this documentation
So now that i have retrieved the date a row was inserted into my db I need another date as of current time.
i.e:
$date1 = $result->format('Y-m-d H:i:s');
$date2 = new DateTime();
$test = $date1->diff($date2);
diff according to this documentation
this gives me this error:
Error: Call to a member function diff() on a non-object
Any idea why i get this error message looks like am doing things the right way according to the docks. Maybe there is another way do diff two dates OPP way.
UPDATE:
Ok so yes it is true if I use $date1 = $result->format('Y-m-d H:i:s'); its no longer a object its a stiring.
So now my code looks like this:
$test = $result->diff(new DateTime());
var_dump($test);
it returns DateInterval object but what do i make out of it:
object(DateInterval)#317 (15) {
["y"]=>
int(0)
["m"]=>
int(0)
["d"]=>
int(0)
["h"]=>
int(1)
["i"]=>
int(27)
["s"]=>
int(5)
["weekday"]=>
int(0)
["weekday_behavior"]=>
int(0)
["first_last_day_of"]=>
int(0)
["invert"]=>
int(0)
["days"]=>
int(0)
["special_type"]=>
int(0)
["special_amount"]=>
int(0)
What i need if Date1 diff to Date2 is > than 30 mins I want to take some actions.
It is because method format returns string, but not object. Try to use:
$test = $result->diff(new DateTime());
$date1 = $result->format('Y-m-d H:i:s');
$date1 is now a string which doesn't have a format() method.
Try this instead:-
$date1 = $result->format('Y-m-d H:i:s');
$date2 = new DateTime();
$test = $result->diff($date2);
After you do $date1 = $result->format('Y-m-d H:i:s');. $date1 is no more a DateTime object, rather a string representation of date and time.
Hence skip this line. Don't format, and then check for difference. That will give you a DateTimeInterval object.
For anyone who doesn't know what diff() does, it compares two dates and returns the difference -- but unlikely other subtraction methods, diff() never returns a negative value. It doesn't matter if the first date is larger or smaller than the second date.
Now, if that is not a concern for this case, the next step is to access the necessary values in the DateInterval object.
$diff=(array)$date1->diff($date2); // calculate the difference and cast as an array
$labels=array("y"=>"year","m"=>"month","d"=>"day","h"=>"hour","i"=>"minute");
// filter the $diff array to only include the desired elements and loop
foreach(array_intersect_key($diff,$labels) as $k=>$v){
if(($k!="i" && $v>0) || $v>30){
// $labels[$k] = $v > 30 minutes, take some action
}
}
Related
How to create split second DateInterval in PHP?
For example:
0.123456 sec
?
interval_spec of DateInterval::__construct
does not have F nor f similarly to DateInterval::format that supports split seconds.
Relative format listing of DateInterval::createFromDateString also does not mention any fraction of a sec.
But the DateInterval class properties listing shows:
f
Number of microseconds, as a fraction of a second.
I was able to get DateInterval with a split second by using the DateTime::diff of two DateTimes with a split seconds
example:
$formatStr = 'Y-m-d H:i:s.u';
$dateTimeStr = '2000-01-01 00:00:00.0';
$timeZone = new \DateTimeZone('UTC');
$timerDateTimeStart = \DateTimeImmutable::createFromFormat($formatStr, $dateTimeStr, $timeZone);
$formatStr = 'Y-m-d H:i:s.u';
$dateTimeStr = '2000-01-01 00:00:00.123456';
$timeZone = new \DateTimeZone('UTC');
$timerDateTimeEnd = \DateTimeImmutable::createFromFormat($formatStr, $dateTimeStr, $timeZone);
$timerDiff = $timerDateTimeStart->diff($timerDateTimeEnd);
$intervalStr = $timerDiff->format('%Y-%M-%D %H:%I:%S.%f');
echo 'Interval (yyyy-mm-dd hh:mm:ss.sfract): ' . $intervalStr;
gives:
Interval (yyyy-mm-dd hh:mm:ss.sfract): 00-00-00 00:00:00.123456
since DateTime supports the split second time_format in its constructor and DateTime::createFromFormat understands
u Microseconds (up to six digits) Example: 45, 654321
BTW: don't you think that u in case of working with the DateTime and F or f in case of DateInterval has a potential for making your day a little bit less boring?
One of my workaround could be to create two DateTime with a split second precision and then diff to get the DateInterval with the same split second precision but I would like to get the same result with just the DateInterval.
Do you know how to create DateInterval having 0.123456 sec by using just the DateInterval?
Solution based on the accepted answer:
$dateInterval = DateInterval::createFromDateString("1 day, 2 hours, 3 minutes, 1 second, 123456 microsecond");
$intervalStr = $dateInterval->format('%D %H:%I:%S.%F');
echo 'Interval (dd hh:mm:ss.sfract): ' . $intervalStr . PHP_EOL;
gives:
Interval (dd hh:mm:ss.sfract): 01 02:03:01.123456
There is a way to do this using DateInterval::createFromDateString:
$di = DateInterval::createFromDateString('123456 microseconds');
var_dump($di);
Output:
object(DateInterval)#1 (16) {
["y"]=>
int(0)
["m"]=>
int(0)
["d"]=>
int(0)
["h"]=>
int(0)
["i"]=>
int(0)
["s"]=>
int(0)
["f"]=>
float(0.123456)
["weekday"]=>
int(0)
["weekday_behavior"]=>
int(0)
["first_last_day_of"]=>
int(0)
["invert"]=>
int(0)
["days"]=>
bool(false)
["special_type"]=>
int(0)
["special_amount"]=>
int(0)
["have_weekday_relative"]=>
int(0)
["have_special_relative"]=>
int(0)
}
Demo on 3v4l.org
From the manual:
time
A date with relative parts. Specifically, the relative formats supported by the parser used for strtotime() and DateTime will be used to construct the DateInterval.
How can I tell if a variable that contains a stampdate like this “2015-05-12 15:32:53” is less or more than an hour comparing it with current timestamp? Is there any good function in PHP that I can use to compare with this time format?
I have this code:
$date = date('Y-m-d h:i:s a', time()); //Current time e.g. "“2015-05-12 13:32:53”
$timetocomp; //Contains “2015-05-12 15:32:53”
My question is how I can compare them to know if 2 hours have passed or not.
Try DateTime
$timetocomp = "2015-06-27 09:10:53"; // its 2015-05-28 08:5x:xx now
$dateTimeToCompare = DateTime::createFromFormat('Y-m-d H:i:s', $timetocomp);
var_dump($dateTimeToCompare);
$dateTimeNoW = new DateTime();
$diff = $dateTimeToCompare->diff($dateTimeNoW);
if($diff->h >= 1 or $diff->d > 0 or $diff->m > 0 or $diff->y > 0) {
echo "difference of at least 1 hour";
} else {
echo "difference less than 1 hour";
}
Edit: My mistake was that I assumed $diff would contain the difference for each size, but its seperated as var_dump($diff) showed.
object(DateInterval)#3 (15) {
["y"]=> int(0)
["m"]=> int(0)
["d"]=> int(30)
["h"]=> int(0)
["i"]=> int(15)
["s"]=> int(13)
["weekday"]=> int(0)
["weekday_behavior"]=> int(0)
["first_last_day_of"]=> int(0)
["invert"]=> int(1)
["days"]=> int(30)
["special_type"]=> int(0)
["special_amount"]=> int(0)
["have_weekday_relative"]=> int(0)
["have_special_relative"]=> int(0)
}
So I updated the If-clause to also chck the days, months and years.
If you are trying to check weather string contains that format or not, try using regular expression and then try figure out the actual date and comparing.
When I run this the first one is correctly created into a date. The second one fails, returning a boolean and so I cannot format. Is the time out of range?
//works correctly
$startDate = "2015-05-06 10:49:20.637133";
$start = DateTime::createFromFormat('Y-m-d h:m:s.u',$startDate);
echo $start->format('m/d/y');
//doesn't work correctly
$startDate = "2015-05-12 15:49:06.821289";
$start = DateTime::createFromFormat('Y-m-d h:m:s.u',$startDate);
echo $start->format('m/d/y');
Code to reproduce the error
Check DateTime::getLastErrors():
php > var_dump(DateTime::createFromFormat('Y-m-d h:m:s',"2015-05-12 15:49:06"));
bool(false)
php > var_dump(DateTime::getLastErrors());
array(4) {
["warning_count"]=>
int(1)
["warnings"]=>
array(1) {
[19]=>
string(27) "The parsed date was invalid"
}
["error_count"]=>
int(1)
["errors"]=>
array(1) {
[11]=>
string(30) "Hour can not be higher than 12"
Change the h to a big H, since the small one is 12-hours format and the big one is 24-hours format.
You can see all formats in the manual. And a quote from there:
h 12-hour format of an hour with leading zeros 01 through 12
H 24-hour format of an hour with leading zeros 00 through 23
Means right now your code fails, because there is no 15 in the 12 hour format.
In addition to the other answers, for standard formats understood by DateTime you don't need to create from a format:
$startDate = "2015-05-12 15:49:06.821289";
$start = new DateTime($startDate);
echo $start->format('m/d/y');
I'm trying to compare to DateTime objects in PHP.
$Time1 = DateTime::createFromFormat('UP', '1409900072+0200');
$Time2 = new DateTime('2014-09-05 07:54:32');
The Time2 use the defoult which is Europe/Copenhagen, comparing yields the following
if ($Time2 > $Time1){
echo "true \n";
} else {
echo "false \n";
}
true
object(DateTime)#1 (3) {
["date"]=>
string(19) "2014-09-05 06:54:32"
["timezone_type"]=>
int(1)
["timezone"]=>
string(6) "+02:00"
}
object(DateTime)#2 (3) {
["date"]=>
string(19) "2014-09-05 07:54:32"
["timezone_type"]=>
int(3)
["timezone"]=>
string(17) "Europe/Copenhagen"
}
The way I understand it is the actual local time for Time1 is 08:54:32, so how can I get the comparison at the same timezone?
Thanks in advance
The really weird part is your initial value of 1409900072+0200. If 1409900072 is a UNIX timestamp, passing a particular timezone with it makes little sense. And it seems to cause PHP to create the instance incorrectly; it creates the instance with the time set to the UTC value (6:54), but the timezone offset of +0200 (where the time should actually be 8:54).
Arguably this should be filed as a bug report; but arguably the input data is nonsensical to begin with.
If you're feeding in a UNIX timestamp, then ignore any timezone information it may contain and explicitly set the timezone to UTC, then it all works as expected:
$t1 = DateTime::createFromFormat('U+', '1409900072+0200', new DateTimeZone('UTC'));
$t2 = new DateTime('2014-09-05 07:54:32', new DateTimeZone('Europe/Copenhagen'));
var_dump($t1 > $t2); // true
Note that PHP before 5.3.9 seems to have problems with the createFromFormat call; you'll probably have to filter out the trailing timezone by hand if you need to support those versions.
Convert both DateTimes to UTC (setTimeZone('UTC')) and then compare them.
<?php
$Time1 = DateTime::createFromFormat('UP', '1409900072+0200');
$Time2 = new DateTime('2014-09-05 07:54:32');
// convert
$utc = new DateTimeZone('UTC');
$time1_utc = clone $Time1;
$time1_utc->setTimeZone($utc);
$time2_utc = clone $Time2;
$time2_utc->setTimeZone($utc);
var_dump($Time1,$Time2);
var_dump($time1_utc,$time2_utc);
I have a string in this format: 2013-07-31T19:20:30.45-07:00 and I want to parse it so that I can, for example, say what day of the week it is. But I'm struggling to cope with the timezone offset. If I do date_parse("2013-07-31T19:20:30.45-07:00") then I end up with something like this:
array(15) {
["year"]=> int(2013)
["month"]=> int(7)
["day"]=> int(31)
["hour"]=> int(19)
["minute"]=> int(20)
["second"]=> int(30)
["fraction"]=> float(0.45)
["warning_count"]=> int(0)
["warnings"]=> array(0) { }
["error_count"]=> int(0)
["errors"]=> array(0) { }
["is_localtime"]=> bool(true)
["zone_type"]=> int(1)
["zone"]=> int(420)
["is_dst"]=> bool(false)
}
It's done something with the timezone, but what do I do with 420 if I want to, for example, show information about the timezone?
In case it matters, I have previously set my default timezone using date_default_timezone_set('UTC').
UPDATE: If the string has a positive timezone, eg 2013-07-31T19:20:30.45+07:00 then the last part of the date_parse() output is:
["is_localtime"]=> bool(true)
["zone_type"]=> int(1)
["zone"]=> int(-420)
["is_dst"]=> bool(false)
}
420 is zone in minutes.
420/60 = 7
I want to parse it so that I can, for example, say what day of the
week it is.
If you want to know what day of the week it is, you have many options. For example you can use date and mktime-functions:
$parsed = date_parse("2013-07-31T19:20:30.45-07:00");
$unix_timestamp = mktime($parsed['hour'], 0, 0, $parsed['month'], $parsed['day'], $parsed['year'], (int)$parsed['is_dst']);
echo date('l', $unix_timestamp);
So you want to show the information about timezone? You can get the time zone name by using timezone_name_from_abbr function:
$name = timezone_name_from_abbr("", -1*$parsed['zone']*60, false); // NB: Offset in seconds!
var_dump($name);
$timezone = new DateTimezone($name);
var_dump($timezone);
2013-07-31T19:20:30.45-07:00
^ y-m-d ^ time ^ timezone offset
I'm guessing the timezone is -7 hours from UTC.
Keep in mind that some countries have half-hour timezones, or even minute timezones. This is probably why you get the timezone in minutes.