Number of decimal months between two dates - php

How do you find the number of decimal months between two dates in php?
I tried the code below:
$date1 = '2010-01-25';
$date2 = '2010-02-20';
$ts1 = strtotime($date1);
$ts2 = strtotime($date2);
$year1 = date('Y', $ts1);
$year2 = date('Y', $ts2);
$month1 = date('m', $ts1);
$month2 = date('m', $ts2);
$day1 = date('d', $ts1);
$day2 = date('d', $ts2);
$diff = (($year2 - $year1) * 12) + ($month2 - $month1);
but it only gives me whole months. I want with decimals. Like 1.5 months or 1.4 months.

First off use DateTime::diff to compare your dates. This will give you a DateInterval result object.
Then I would do something like this:
$months = ($interval->y * 12) + $interval->m; // Total number of whole months
$months += number_format($interval->d / 30, 1); // Add the month fraction
Working example: http://3v4l.org/f6n3r

Dividing amount of days by 30 days is an easy implementation. It is not acceptable for sensitive calculations such as invoices or other finance related stuff.
There is an awesome DateTime extension called Carbon
$start = Carbon::create(2010, 1, 25, 0, 0, 0);
$end = Carbon::create(2010, 2, 20, 0, 0, 0);
echo $start->floatDiffInMonths($end); // "0.90437788018433"
It considers amount of days in a month, leap year and other things.
Keep in mind that calculation happens including time, so if you add 24 hours to $end, then 20 Feb 2010 will also be included:
$start = Carbon::create(2010, 1, 25, 0, 0, 0);
$end = Carbon::create(2010, 2, 20, 24, 0, 0);
echo $start->floatDiffInMonths($end); // "0.94009216589862"
It also supports daylight saving times in different timezones, for that, you'll need to use floatDiffInRealMonths

try this:
function monthNb ($vStartDate,$vEndDate) // dates are of format 2013-11-27
{$vStart = strtotime($vStartDate);
$vEnd = strtotime($vEndDate);
$vDiff = abs($vEnd - $vStart); // here abs in case theres a mix in the dates
$vMonths = $vDiff / 1036800; // number of seconds in a month of 30 days
return $vMonths;}
this will give you roughly the difference in months if all months would have 30 days. It can't really get more precise since months don't all have the same number of days. you could do a custom fonction to divide by the number of seconds corresponding to the number of days in the month of the end date, but then 1,5 month ending in january would not mean the same as 1,5 months ending in april. Understand that like Marc B pointed out in his comment, this value can never be precise since months do not have the same number of days.

Related

Calculation of no of hours & more on using date Y-m-d H:i:s

I have below 2 dates with hours & time.
Format: Y-m-d H:i:s
$day1 = 2016-10-01 02:00:00
$day2 = 2016-10-02 03:00:00
calculating no of days using
$interval = $day1->diff($day2);
echo $interval->format('%a');
this gives me 1 day but actually it must be 2 days cause it more than 25hours.
So on the basis of hours how can we get no of days?
From what you mentioned, we are supposed to round it to the next day value if it exceeds 24 hrs.
The logic is pretty simple.
Store the hour difference between two dates in $hoursDiff.
Calculate the no. of days i.e the floor value $days.
Check if there's any additional difference e.g 1 day + remaining 1 hour $remaining
If remaining value exists then add 1 day to $day. Otherwise keep it as it is.
$day1 = '2016-10-01 02:00:00'; // Declare as string
$day2 = '2016-10-02 03:00:00'; // Declare as string
$hoursDiff = round((strtotime($day2) - strtotime($day1))/3600, 1);
$days = floor($hoursDiff / 24);
$remaining = ($hoursDiff % 24);
$dayDiff = $remaining ? ($days + 1) : $days;

How to get the difference between two dates with 360 days/year, 30 days/month format?

I can get the difference between two dates (DD/MM/YY format) with the following code;
$date1 = new DateTime("1986-04-27");
$today = new DateTime("now");
$interval = $date1->diff($today);
$year = $interval->format('%y');
$month = $interval->format('%m');
$day = $interval->format('%d');
It works perfect when calculating 1 year 2 months but when I'm trying to calculate 1 year 2 months 3 days, it doesn't give me the accurate result.
I would like to get the difference between two dates, using 360 days for a year, 30 days for a month, without calculating leap years..
For example; if a month has 31 days the system will calculate it as 30 days.
If a year has 365 days, the system will calculate it as 1 year 5 days. (360 + 5)
How can I do that?
Thank you..
Here is the way to do it:
function diff360($date1, $date2) {
$date1 = new DateTime($date1);
$date2 = new DateTime($date2);
$diff = $date1->diff($date2);
$days = ($date2->format('d') + 30 - $date1->format('d')) % 30;
return array(
"y" => $diff->y,
"m" => $diff->m,
"d" => $days,
"totaldays" => $diff->y * 360 + $diff->m * 30 + $days
);
}
$result = diff360("2016-02-06", "2016-03-06");
var_export($result);
Output:
array (
'y' => 0,
'm' => 1,
'd' => 0,
'totaldays' => 30,
)
Just get the number of days and substract the years / months.
$totalDays = $interval->format('%a');
$years = 0;
$months = 0;
while ($totaldays >= 360) { $years++; $totaldays -=360; }
while ($totaldays >= 30) { $months++; $totaldays -=30; }
$days = $totalDays
But why do you need a broken date format?
The DateTime class will calculate a difference based on real dates. It's kind of random whether it will work or not in your example. If you want to use custom lengths for months, ignore leap years etc. then you will have to create custom functions yourself.
I don't really understand the point of doing this though?

date_diff returns 0 if the difference is over a year

I am using this function to get month difference between two dates.
$interval = date_diff(date_create('2015-10-08'), date_create('2014-10-10'));
$total_months = $interval->format('%m');
RESULT: 11 (That's Correct!)
But, When the difference is over a year, then,
$interval = date_diff(date_create('2015-11-08'), date_create('2014-10-10'));
$total_months = $interval->format('%m');
RESULT: 0 (That's Wrong!)
why is it returns 0? Is there any way by which I can get difference between any 2 dates? Thanks!
2015-11-08 to 2014-10-10 is 12 months become a year. So it returns 0 month. Calculate the number of years from the $interval then add (year * 12) to the number of months. Example here...
$interval = date_diff(date_create('2015-11-08'), date_create('2014-10-10'));
$year = $interval->format('%Y');
echo $total_months = $interval->format('%m') + $year * 12;
Or better:
$total_months = $interval->y * 12 + $interval->m;
You have years and months as fields, no need to use format to obtain parts as texts for later adding the parts!
It is a bit tricky and needs a work round , try the following, that could
be it.
$first = new DateTime('2015-11-08',new DateTimeZone('America/New_York'));
$second = new DateTime('2014-10-10',new DateTimeZone('America/New_York'));
$diff = $second->diff($first);
$months = (Int)($diff->days/30);
echo "The two dates have $months months between them.";
Output:The two dates have 13 months between them.

PHP: parse string in format yW into a timestamp

I have a string in the format yW. Year followed by the week number. I would like to get a timestamp. I am using Php 5.2.17 on Windows.
strtotime() does not seem to be working reliably. For the string '1142' it should return the first day of the 42nd week of 2011.
Any suggestions on how to do this?
Give this a go, will work on windows also...
$date = '1201';
$y = substr($date, 0, 2) + 2000;
$w = substr($date, 2);
$ts = mktime(0, 0, 0, 0, 0, $y) + ($w * 604800);
subtract 1 from week if week 1 is the first week of the year
strtotime() does not accept that particular format. However, it can work with year and week number values if they're formatted as 2011W42.
// Convert 1142 to 2011W42
$reformatted = '20'.substr_replace('1142', 'W', 2, 0);
$timestamp = strtotime($reformatted);
See Compound Formats for details on this particular format.
Another option is the setIDODate() method on the DateTime class.
sscanf('1142', '%2d%2d', $year, $week);
$date = new DateTime('#0');
$date->setISODate(2000 + $year, $week);
$timestamp = $date->format('U');

How to get the first day of a given week number in PHP (multi-platform)?

What is the simplest way to do it in PHP ?
I want the date of the Monday of a given week number of a year (example : week number 3 of 2009)
Thanks !
EDIT : If you use Linux only machines, use cletus' solution, however I am looking for something that can work on Windows AND Linux.
It's simple on PHP 5.3
echo date('M d',strtotime('2013W15'));
where 15 is the number of week. But for the number below ten make sure it is in the format of 01, 02 for first week and second week.
Yet another solution:
<?php
$week = 3;
$year = 2009;
$timestamp = mktime( 0, 0, 0, 1, 1, $year ) + ( $week * 7 * 24 * 60 * 60 );
$timestamp_for_monday = $timestamp - 86400 * ( date( 'N', $timestamp ) - 1 );
$date_for_monday = date( 'Y-m-d', $timestamp_for_monday );
?>
A nice way to get this in a clean way is by using php DateTime class.
$year = 2015;
$week_no = 1;
$date = new DateTime();
$date->setISODate($year,$week_no);
echo $date->format('d-M-Y');
This would result into : 29-12-2014
You can use strptime() to get the time.
$time = strptime('1 23 2009', '%w %U %Y');
This will get the time for the Monday (day 1, 0 is Sunday, 6 is Saturday) of the 23rd week of 2009. If you want to format this into a date, use date().
$date = date('d F Y', $time);
This next script gives the 7 days of an specific week of a year
$time = new DateTime();
$time->setISODate(2016, 13);
for($i=0;$i<7;$i++){
echo $time->format('d-M-Y') . '<br />';
$time->add(new DateInterval('P1D'));
}
Seems to be working and not dependent of the server OS :
<?php
$week = 4;
$year = 2013;
$timestamp_for_monday = mktime( 0, 0, 0, 1, 1, $year ) + ((7+1-(date( 'N', mktime( 0, 0, 0, 1, 1, $year ) )))*86400) + ($week-2)*7*86400 + 1 ;
?>
the idea is to add :
the timestamp of the first of January of the chosen year
the number of seconds to reach the end of the first week (which is 7 days minus the day of week of the 1st of January + 1 day) multiplied by the number of seconds per day
the number of seconds of the number of chosen weeks minus the first week and the current week
1 second to reach the fist second of the current week
My example returns : 1358722801
which is the timestamp of 2013/01/21 0:00:01
Here is very simple solution, passing a week no and returns the date.
The ISO8601 standard states that week 1 always fall on the week where Jan 4 falls.
For example, to get a day in the 4th week of the year:
$day_in_week = strtotime("2006-01-04 + 4 weeks"));
Then you can adjust this value to Sunday (as a starting place you can guarantee that you can find):
// Find that day's day of the week (value of 0-6)
$wday = date('w', $day_in_week);
$offset = 6 - $wday; // How far it is from Sunday.
$sunday_in_week = $day_in_week - ($offset * (60 * 60 * 24)); // $offset * seconds in a day
Then, you add the seconds in a day again to get Monday.
$monday_in_week = $sunday_in_week + (60 * 60 * 24);
Note: This method can occasionally have some problems with daylight savings time. A similar, and slightly safer between DST time changes, method would use the DateTime class. However, DateTime is only support in PHP 5.2.0 or later. The method above works in earlier version as well.
Try this function
function MondayOfWeek($WeekNumber, $Year=-1) {
if ($Year == -1) $Year = 0+date("Y");
$NewYearDate = mktime(0,0,0,1,1,$Year);
$FirstMondayDate = 7 + 1 - date("w", mktime(0,0,0,1,1,2009));
$Dates_fromFirstMonday = 7 * $WeekNumber;
$Second_fromFirstMonday = 60*60*24*($FirstMondayDate + $Dates_fromFirstMonday);
$MondayDay_ofWeek = $NewYearDate + $Second_fromFirstMonday;
$Date_ofMondayDay_ofWeek = 0+date("j", $MondayDay_ofWeek);
return $Date_ofMondayDay_ofWeek;
}
for($i = 0; $i
When run, I got:
-5-12-19-26-2-9-16-23-2-9-16-23-30-6-13-20-27-4-11-18-25-1-8-15-22-29-6-13-20-27-3-10-17-24-31-7-14-21-28-5-12-19-26-2-9-16-23-30-7-14-21-28
Hope this helps.
I required same in the java script..so i converted.
function(week,year){
var timestamp = new Date(year, 0, 1, 0, 0, 0, 0);
var dateObj=new Date();
var val = timestamp.getTime();
days=( week * 7 * 24 * 60 * 60*1000 );
val=val+days;
var timestamp_for_monday =val - 86400 *((timestamp.getDay()-1000));
var weekdate=new Date(timestamp_for_monday);
return weekdate;
}

Categories