I know how to calculate the number of days between two dates as shown below, but, how can I return the difference as a negative number if it's in the past?
This is what I'm using:
$today = new DateTime('now'); // today is 2015-09-02
$date1 = new DateTime("2015-08-13"); // 20 days ago
$diff = $today->diff($date1)->format("%a");
echo "diff is $diff"; // shows 20 but I want it to return -20
I've tried reversing the variables but it doesn't seem to care about the order.
DateInterval has the invert property that specifies whether they're positive or negative.
You can output it like
$interval->format("%r%a");
r stands for
Sign "-" when negative, empty when positive
See DateInterval::format docs.
$today = new DateTime('now'); // today is 2015-09-02
$date1 = new DateTime("2015-08-13"); // 20 days ago
$diff = $today->diff($date1)->format("%r%a");
Output will be -20. Also you can swap the dates likes following example. Output will be 20.
$today = new DateTime('now'); // today is 2015-09-02
$date1 = new DateTime("2015-08-13"); // 20 days ago
$diff = $date->diff($today)->format("%r%a");
this works fine in my project.
{{ \Carbon\Carbon::parse($firstdate)->diffInDays($seconddate,false) }}
output can be : -20
(Laravel)
Related
I am trying to retrieve the number of days for a PHP interval. When I run the following piece of code on http://sandbox.onlinephpfunctions.com/:
$duration = new \DateInterval('P1Y');
echo $duration->format('%a');
echo "Done";
I get:
(unknown)Done
What am I doing wrong?
The '%a' will return the number of days only when you take a time difference otherwise it will return unknown.
You can use '%d' to get the days but it will also return 0 in the case of new \DateInterval('P1Y') as it does not convert years to days.
One easy way to get the number of days is to create a DateTime at zero time, add the interval to it, and then get the resulting timestamp:
<?php
$duration = new \DateInterval('P1Y');
$intervalInSeconds = (new DateTime())->setTimeStamp(0)->add($duration)->getTimeStamp();
$intervalInDays = $intervalInSeconds/86400;
echo $intervalInDays;
echo " Done";
The problem is here:
$duration->format('%a');
As the manual says, "Total number of days as a result of a DateTime::diff() or (unknown) otherwise".
You need a valid dateInterval object returned by DateTime's diff() method to make the "a" parameter work with DateInterval::format() function:
$now = new DateTime(date('Y-m-d H:i:s'));
$duration = (new DateTime("+1 year"))->diff($now);
echo $duration->format('%a');
Looks like if the DateInterval object is not created by DateTime::diff(), it won't work.
Hope it helps.
You have to create the interval with real dates:
<?php
$interval = date_diff(new DateTime, new DateTime('+1 year'));
echo $interval->format('%a'), PHP_EOL; // 365
if you want something aware of the year or month context, use this, february will return 28 days, leap years will have their additional day
function interval2days($day, $interval) {
$date = clone $day;
$start = $date->getTimeStamp();
$end = $date->add($interval)->getTimeStamp();
return ($end-$start)/86400;
}
I have 28 unique events, one event per day. Events repeat after 28. is 1. event again.
Lets say first event is 1970-01-01. Event 28 is 1970-01-28.
Today is 2015-10-16, how do I find out what event should be today? How do I find out what event should be for any given date? (just dates > 1970-01-01 and < 9999-12-31).
I was thinking of converting date to timestamp, then do modulo 28*24*60*60, and then convert it back to date, but I'm afraid that there might be some margin. Any ideas?
You may use DateTime::diff function as follow:
$datetime1 = date_create('1970-01-28');
$datetime2 = date_create('2015-10-16');
$interval = date_diff($datetime2, $datetime1);
/// Get total number of days
$days = $interval->format('%a');
/// Get the remainder of the division by the number of events
$eventNumber = $days % 28;
Another solution is to use unix timestamp to get date differences in terms of seconds. And since 01-01-1970 is zero by definition, all you have to do is:
$today = mktime(); // Or $today = mktime(12,0,0,10,16,2015);
$mod = floor($today/86400) % 28;
It's the equivalent of the MySQL to_days() function.
Is there a builtin PHP function that does this, or do I need to cobble something together?
You'd need to write your own but it's not hard:
$now = new DateTime();
$zero = new DateTime('0000-00-00'); // -0001-11-30 - Nov 30, 1 BC. Interesting.
$diff = $now->diff($zero);
echo $diff->format('%a days'); // 735728 days
Demo using the literal year zero. You obviously would want to put a valid date in there instead.
$now = new DateTime();
$zero = new DateTime('0001-01-01');
$diff = $now->diff($zero);
echo $diff->format('%a days'); // 735330 days
Demo
As a one liner:
echo (new DateTime())->diff(new DateTime('0001-01-01'))->format('%a days');
As a function:
function toDays($date) {
return (new DateTime())->diff(new DateTime($date))->format('%a');
}
You can use the Julian day count, i.e. with cal_to_js(), see http://www.php.net/manual/de/function.cal-to-jd.php, even if there was no year 0 in the Gregorian calendar.
I want to add an x number of week days (e.g. 48 weekday hours) to the current timestamp. I am trying to do this using the following
echo (strtotime('2 weekdays');
However, this doesn't seem to take me an exact 48 hours ahead in time. For example, inputting the current server time of Tuesday 18/03/2014 10:47 returns Thursday 20/03/2014 00:00. using the following function:
echo (strtotime('2 weekdays')-mktime())/86400;
It can tell that it's returning only 1.3 weekdays from now.
Why is it doing this? Are there any existing functions which allow an exact amount of weekday hours?
Given you want to preserve the weekdays functionality and not loose the hours, minutes and seconds, you could do this:
$now = new DateTime();
$hms = new DateInterval(
'PT'.$now->format('H').'H'.
$now->format('i').'M'.
$now->format('s').'S'.
);
$date = new DateTime('2 weekdays');
$date->add($hms);//add hours here again
The reason why weekday doesn't add the hours is because, if you add 1 weekday at any point in time on a monday, the next weekday has to be tuesday.
The hour simply does not matter. Say your date is 2014-01-02 12:12:12, and you want the next weekday, that day starts at 2014-01-03 00:00:00, so that's what you get.
My last solution works though, and here's how: I use the $now instance of DateTime, and its format method to construct a DateInterval format string, to be passed to the constructor. An interval format is quite easy: it starts with P, for period, then a digit and a char to indicate what that digit represents: 1Y for 1 Year, and 2D for 2 Days.
However, we're only interested in hours, minutes and seconds. Actual time, which is indicated using a T in the interval format string, hence we start the string with PT (Period Time).
Using the format specifiers H, i and s, we construct an interval format that in the case of 12:12:12 looks like this:
$hms = new DateInterval(
'PT12H12M12S'
);
Then, it's a simple matter of calling the DateTime::add method to add the hours, minutes and seconds to our date + weekdays:
$weekdays = new DateTime('6 weekdays');
$weekdays->add($hms);
echo $weekdays->format('Y-m-d H:i:s'), PHP_EOL;
And you're there.
Alternatively, you could just use the basic same trick to compute the actual day-difference between your initial date, and that date + x weekdays, and then add that diff to your initial date. It's the same basic principle, but instead of having to create a format like PTXHXMXS, a simple PXD will do.
Working example here
I'd urge you to use the DateInterface classes, as it is more flexible, allows for type-hinting to be used and makes dealing with dates just a whole lot easier for all of us. Besides, it's not too different from your current code:
$today = new DateTime;
$tomorrow = new DateTime('tomorrow');
$dayAfter = new DateTime('2 days');
In fact, it's a lot easier if you want to do frequent date manipulations on a single date:
$date = new DateTime();//or DateTime::createFromFormat('Y-m-d H:i:s', $dateString);
$diff = new DateInterval('P2D');//2 days
$date->add($diff);
echo $date->format('Y-m-d H:i:s'), PHP_EOL, 'is the date + 2 days', PHP_EOL;
$date->sub($diff);
echo $date->format('Y-m-d H:i:s'), PHP_EOL, 'was the original date, now restored';
Easy, once you've spent some time browsing through the docs
I think I have found a solution. It's primitive but after some quick testing it seems to work.
The function calculates the time passed since midnight of the current day, and adds it onto the date returned by strtotime. Since this could fall into a weekend day, I've checked and added an extra day or two accordingly.
function weekDays($days) {
$tstamp = (strtotime($days.' weekdays') + (time() - strtotime("today")));
if(date('D',$tstamp) == 'Sat') {
$tstamp = $tstamp + 86400*2;
}
elseif(date('D',$tstamp) == 'Sun') {
$tstamp = $tstamp + 86400;
}
return $tstamp;
}
Function strtotime('2 weekdays') seems to add 2 weekdays to the current date without the time.
If you want to add 48 hours why not adding 2*24*60*60 to mktime()?
echo(date('Y-m-d', mktime()+2*24*60*60));
The currently accepted solution works, but it will fail when you want to add weekdays to a timestamp that is not now. Here's a simpler snippet that will work for any given point in time:
$start = new DateTime('2021-09-29 15:12:10');
$start->add(date_interval_create_from_date_string('+ 3 weekdays'));
echo $start->format('Y-m-d H:i:s'); // 2021-10-04 15:12:10
Note that this will also work for a negative amount of weekdays:
$start = new DateTime('2021-09-29 15:12:10');
$start->add(date_interval_create_from_date_string('- 3 weekdays'));
echo $start->format('Y-m-d H:i:s'); // 2021-09-24 15:12:10
I am aware this topic is pretty exhausted, but obviously not quite enough!
$temp_d1 = new DateTime(date('Y-m-d', $fromTime)); // 2012-01-01
$temp_d2 = new DateTime(date('Y-m-d', $endTime)); // 2013-02-01
$interval = $temp_d2->diff($temp_d1);
$monthsAhead = $interval->format('%m'); // returns 1, but I am expecting 13
How do you calculate the number of months between two dates without wrapping within a 12 month scale?
I was confusing exactly what:
$monthsAhead = $interval->format('%m');
does.
Obviously, format('%m') is just formatting the month component of the DateInterval object, not necessarily 'give me the interval as a number of months'.
In my case, I was looking for/to do this:
$monthsAhead = $interval->m + ($interval->y * 12);
http://www.php.net/manual/en/class.dateinterval.php
Hope this helps other fools in the future!