Function for difference calculation between datetime (months) - php

my goal is to calculate the number of months between two dates including the starting month.
I am using this function to calculate.
function number_months($date1, $date2){
$begin = new DateTime(date('Y-m-d', strtotime($date1)));
$end = new DateTime(date('Y-m-d', strtotime($date2)));
$diff = $end->diff($begin);
return ($diff->format('%y') * 12) + $diff->format('%m') + 1;
}
In most cases in works fine, but when the function parameters are for example:
$date1 = 2015-11-04 00:00:00
$date2 = 2017-02-01 00:00:00
Function returns:
15
Should be 16. What am I missing? I did reseach here on Stackoverflow, have tried various implementations of provided code, but the problem still ocurs.
Thanks.

11-04 to 12-04 = 1 month.
12-04 to 01-04 = 1 month.
01-04 to 02-01 = 0 month.
Result diff->format('%m') = 2.
($diff->format('%y') * 12) + $diff->format('%m') + 1 = 1*12 + 2 + 1 = 15;
It's true.

The problem is that the user will set the start and end date of project. And I need to create a input for every month the project is going to be set. So i need number 16 in this case.
Thanks to comments i realised that DateTime::diff() works in full units when it comes to years, months and days.
I solved my problem by setting the start and end date to 1st of the month. So now my function returns number of months between two dates including starting and ending month.
function number_months($date1, $date2){
$begin = new DateTime(date('Y-m-d', strtotime($date1)));
$end = new DateTime(date('Y-m-d', strtotime($date2)));
$begin->modify('first day of this month')->setTime(12, 00);
$end->modify('first day of this month')->setTime(12, 00);
$diff = $end->diff($begin);
return ($diff->format('%y') * 12) + $diff->format('%m') + 1;
}

Related

Create function to see if date range equals a month or part month

I'm creating a function to check whether 2 dates equal a full month or part of a month.
I'm trying with this inside my if statement:
$result["from_date"] = $_GET["from_date"];
$result["to_date"] = $_GET["to_date"];
$start = strtotime($result["from_date"]);
$stop = strtotime($result["to_date"]);
$diff = ($stop - $start); //Diff in seconds
$timespan = ($diff / 86400) + 1;
echo 'timespan - '.$timespan.'<br>';
if(cal_days_in_month(CAL_GREGORIAN, ChangeDateFormat($result["from_date"], 'm'), ChangeDateFormat($result["from_date"], 'Y')) == $timespan) {
return true;
}
I've used the dates 2018-10-01 and 2018-10-31 which is returning the timespan as 31.041666666667 meaning its returning true in the above if.
I have also tried the dates 2018-08-01 and 2018-08-30 which does not return true, so thats working correctly.
I'ts just October that is playing up and I cannot work out why.
As I wrote in comments this is due to daylight savings.
You can use DateTime to calculate the number of days between to dates (and add one).
$result["from_date"] = "2018-10-01";
$result["to_date"] = "2018-10-31";
$start = new DateTime($result["from_date"]);
$stop = new DateTime($result["to_date"]);
$diff = $stop->diff($start)->format("%a") +1;
echo 'timespan - '.$diff.' days<br>';

Efficiently check if exactly 2 days passed from given datetime in my case

I have following code that add 2 days to a given date.
$myDate = 2018-07-28 11:00:00; // the date is picked from db
$penaltyDays = 2;
$date1 = new DateTime($myDate);
$date1->add(new DateInterval("P{$penaltyDays}D")); // add N days
$now = new DateTime();
$interval = $date1->diff($now); // get difference
$days = $interval->d; // difference in days
I want value of $days must be 0 after passing exactly 48 hours. If 3 days are passed the value of $days should be -1.
I will also appreciate if someone tell me efficient/proper way to get the result.
To make an efficient code according to your specification then I would rather use strtotime than DateTime.
This code checks if the current time is larger than the database time + two (or three) days in seconds.
$myDate = "2018-07-28 11:00:00";
$unix = strtotime($myDate);
if(time() > ($unix + 86400*3)){
$days = -1;
}else if(time() > ($unix + 86400*2)){
$days = 0;
}else{
$days = "something else";
}
Echo $days;
https://3v4l.org/d6Q15

DateTime diff returning wrong value

I would like to return the number of days between NOW and some datetime using DateTime object. My dates are:
$now = "2018-03-08 14:00:00";
$last = "2018-02-06 20:00:00";
And I do it like this:
$now = new DateTime();
$last_dt = new DateTime($last);
$difference = $last_dt->diff($now);
$difference->format('%d');
$num_of_days = $difference->d;
For some weird reason, the value of $num_of_days is 1 (instead of like 30)
Anybody knows why please?
Thank you
You need to use DateInterval::$days to get the total in days.
DateInterval::$d is just the number of days but in "grouping form", i.e. 32 days difference will return 2 for DateInterval::$d and 1 for DateInterval::$m.
$last = "2018-04-10 20:00:00";
$now = new DateTime();
$last_dt = new DateTime($last);
$difference = $last_dt->diff($now);
echo "Difference: ".$difference->m." months and ".$difference->d." days, or ".$difference->days." days in total";
Result
Difference: 1 months and 2 days, or 33 days in total
Demo
You can see more in the manual

Need a equivalent solution for vbscript command cdbl(now) with php

With vbscript i can retrieve a double value from the current date/time with the command cdbl(now).
Now = '09.05.2015 21:44:10'
cdbl(Now) = 42133,9056712963
I'm looking for a equivalent solution with php that will give me back a double value from the current date/time.
cdbl return datetime in microsoft format. before comma date - number of days since 1 January 1900. After comma time - 24 hours is 1. So if you use dates within Unix epoch (code may be not effective,i wanted make it more understandable)
function cdbl($str) {
$datetime0 = new DateTime('1970-01-01');
$datetime = new DateTime($str);
// 25560 - days from 1 Jan 1900 to 1 Jan 1970
$cdbl = $datetime->diff($datetime0)->days + 25569;
// Remove time from string - it is the sane as 00:00
$str0 = preg_replace('/((T|\s+).+)$/','', $str);
// The number of seconds since the day start
$time = strtotime($str) - strtotime($str0);
// The number of seconds wittin a day
$timefullday = strtotime("$str0 + 1 day") - strtotime($str0);
$cdbl += $time / $timefullday;
return $cdbl;
}
echo cdbl('09.05.2015 21:44:10');
result:
42133.905671296
As you can see, there is a problem of rounding. If print result of the calculation time before summing, the answer will be the same as yours. I've never done calculating tasks, so I can not tell you what to do with it. The only suggestion is convert to a string :)
Well, if you choose to work outside of Unix dates you should write some code
The following function returns the current Unix timestamp as a double value:
function cdblnow(){
// time in seconds since 1 Jan 1970 (GMT)
$timeunix = time();
// add the timezone offset
$TimeZone = "Asia/Bangkok";
$dateTimeZone = new DateTimeZone($TimeZone);
$dateTime = new DateTime("now", $dateTimeZone);
$timeOffset = $dateTimeZone->getOffset($dateTime);
$timeunix = $timeunix + $timeOffset;
// determines the days between 1 Jan 1970 and today
$days = intval($timeunix / 86400);
// second count from today
$secondsremains = $timeunix % 86400;
// 25569 days difference between microsoft and unix time stamp start
$now_date = $days + 25569;
// 0.0000115741 represents one second at the cdbl-function from microsoft
$now_time = $secondsremains * 0.0000115741;
return $now_date + $now_time;}
This function returns the unix time stamp from a double:
function GetUnixTimeFromCdblNow($cdbl){
$days = intval($cdbl);
$seconds = round($cdbl - $days,9);
$timeunix = (($days -25569) * 86400);
$timeunix = $timeunix + intval($seconds / 0.0000115740);
return $timeunix;}

Why does date gives me a wrong date?

I want to calculate a date based on a timestamp and some other informations.
My function looks like:
function getLastDeliveryDate($timestamp,$endOfMonth=true,$extraMonth=0){
$days = 0;
$extraDays = 0;
$endOfCurrentMonth = 0;
$tsDay = 86400;
if($endOfMonth){
$endOfCurrentMonth = date("t", $timestamp) - date("d",$timestamp);
//rest of days in current month. In this sample 16 days
}
for($i=0;$i<$extraMonth;$i++){
$x = $i + 1;
$date = new DateTime(date("Y-m-d", $timestamp)); //create dateobject to add a month
$date->modify("+{$x} month"); // add the month (next month)
$extraDays += date("t", strtotime($date->format("Y-m-d")));
// get the days of the selected month and add them to count
// in this case its 31 + 30 + 31 = 92
}
$days = $endOfCurrentMonth + $extraDays;
// count everything together 16 + 92 = 108 days
return date("d.m.y", $timestamp + ($tsDay*$days));
//returning date with 108 days added.
}
As a sample I call the function like:
// the timestamp is 2015-07-15
echo getLastDeliveryDate(1436911200, true, 3);
// should return 2015-10-31
But this return 2015-10-30 and I don't know why. But 108 Days shold be 2015-10-31. Whats going wrong here ?
If I call
echo getLastDeliveryDate(1436911200, true, 2);
Its correct and gives me 2015-09-30
Actually I allways want the last day of the month.
EDIT:
Wired, if I test this here: IDEONE everything works fine. Im my Project it doesn't :(
You need to create the datetime object before the loop:
$date = new DateTime(date("Y-m-d", $timestamp)); //create dateobject to add month
// simpler alternative: $date = new DateTime("#$timestamp");
for($i=0;$i<$extraMonth;$i++){
$date->modify("+1 month"); // add the month (next month)
// $extraDays += date("t", strtotime($date->format("Y-m-d")));
// you can reduce this line to:
$extraDays += $date->format("t");
}
// Result: 15-10-31
otherwise there is always 31 added because you use the day of the timestamp + 1 month.
Note:
You can reduce the whole function to this:
function getLastDeliveryDate($timestamp,$endOfMonth=true,$extraMonth=0){
$date = new DateTime("#$timestamp");
$date->modify("+$extraMonth month");
if ($endOfMonth)
$date->modify("last day of this month");
return $date->format("d.m.y");
}
The problem is the daylight savings time. You loose one hour on the 25th of october 2015. Since your timestamp is exactly 0:00:00 you lose one hour resulting in "30.10.2015 23:00:00" what should actually be 0:00:00
function getLastDeliveryDate($timestamp,$endOfMonth=true,$extraMonth=0){
$days = 0;
$extraDays = 0;
$endOfCurrentMonth = 0;
$tag = 86400;
if(date( 'H',$timestamp)==0){$timestamp+=3601;}
if($endOfMonth){
$endOfCurrentMonth = date("t", $timestamp) - date("d",$timestamp);
}
$date = new DateTime(date("Y-m-d", $timestamp));
for($i=0;$i<$extraMonth;$i++){
$date->modify("+1 month");
$extraDays += $date->format("t");
}
$days = $endOfCurrentMonth + $extraDays;
return date("d.m.y", $timestamp + ($tag*$days));
}
echo getLastDeliveryDate(1436911200, true, 3);
This code has a dirty fix for this problem by adding one hour and one second if your datetime is fixed to 0:00:00. When you don't care about the hours themselves, then this solution will fix your problem and is viable in any case. If you care about the hours, you have to check whether you are in daylight savings time or not and act acordingly.

Categories