Calculate months diff between dates without days - php

is there a good way to calculate months diff between dates without days? I mean I have two not full dates for example:
2017-09 and 2018-11. I need to calculate how many months is between this two dates. I read something about this and I know I can for example use:
$firstDate = "2017-09";
$secondDate = "2018-11";
$firstDate = new DateTime($firstDate . "-01");
$secondDate = new DateTime($secondDate . "-01");
$interval = date_diff($firstDate, $secondDate);
var_dump($interval->format('%m months'));exit();
This show me 2 months.
How can I reach this? And is there a way to calculate this without adding days "-01" to end of my dates?
I want to calculate difference of months for dates without write "-01" in this dates. Only year and month.

You need the years also.
Also you had a parse error on the date 2017-0901 is not valid either 2017-09 or 2017-09-01.
$firstDate = "2017-09";
$secondDate = "2018-11";
$firstDate = new DateTime($firstDate);
$secondDate = new DateTime($secondDate);
$interval = date_diff($firstDate, $secondDate);
echo $interval->format('%y')*12+$interval->format('%m') . " months";
// 14 months
https://3v4l.org/XGdXg

Just use plain arithmetic. We're clearly not concerned about timezones, daylight saving, calendar changes, etc. so we're also not concerned about parsing the date "in some timezone, based on some calendar". What we're left with is just plain arithemtics, using months. A year is 12 months. And now we're almost done already.
function ym_as_months($v) {
$v = array_map("intval", explode("-", $v));
return $v[0]*12 + $v[1];
}
$firstDate = "2017-09";
$firstMonths = ym_as_months($firstDate);
$secondDate = "2018-11";
$secondMonths = ym_as_months($secondDate);
$diff = $secondMonths - $firstMonths;
echo "There are $diff months between $firstDate and $secondDate.";
And we get:
There are 14 months between 2017-09 and 2018-11.
Perfect.
Of course, depending on how you get those date stamps in your application, it might be far easier to not even pass them in as string, but simply as two numbers from the get go, in which case this becomes even less work.
Alternatively, do your conversion as the very last step, as per another answer here.

I will suggest using Carbon for dates related calculations in PHP as it really makes everything easy.
To calculate months between two dates with Carbon, you simply need to do this
//year & month
$startDate = Carbon::create('2017', '9');
$endDate = Carbon::create('2018','11');
$diff = $startDate->diffInMonths($endDate);

https://secure.php.net/manual/en/datetime.createfromformat.php
$a = DateTime::createFromFormat('Y-m', '2017-09');
$b = DateTime::createFromFormat('Y-m', '2018-11');
$diff = $a->diff($b);
var_dump(
$a, $b,
$diff->format("%y years, %m months"),
sprintf("%d months", $diff->y * 12 + $diff->m)
);
Output:
object(DateTime)#1 (3) {
["date"]=>
string(26) "2017-09-06 18:33:58.000000"
["timezone_type"]=>
int(3)
["timezone"]=>
string(16) "Europe/Amsterdam"
}
object(DateTime)#2 (3) {
["date"]=>
string(26) "2018-11-06 18:33:58.000000"
["timezone_type"]=>
int(3)
["timezone"]=>
string(16) "Europe/Amsterdam"
}
string(17) "1 years, 2 months"
string(9) "14 months"

Related

How to get time difference of a datetime value and a time value in PHP

I have one DATETIME value 'D1' and one TIME value 'T1'. I need to find difference of D1 and T1 after comparing these two values.
D1:2020-12-07 18:21:47 and T1:19:30:00
My code to find time difference:
if(strtotime(T1) > strtotime(D1)){
$diff = date("H:i:s",(strtotime(T1) - strtotime(D1)));
}`
I am getting incorrect result.
use this method to add date to your t1 value
date('Y-m-d',strtotime('2020-12-07 18:21:47'));
and then use this method to get difference
$starttimestamp = strtotime($startdatetime);
$endtimestamp = strtotime($enddatetime);
$difference = abs($endtimestamp - $starttimestamp)/3600; in hours difference
2020-12-07 18:21:47 is not a full date time value. It is missing the time zone which can lead to unexpected or wrong results.
strtotime() is a very old function. The better approach is the DateTimeImmutable class. You can set the time with DateTimeImmutable::setTime() and get the difference with DateTimeImmutable::diff().
$dates = [
new DateTimeImmutable('2020-12-07T00:21:47Z'),
new DateTimeImmutable('2020-12-07T00:21:47-0800'),
new DateTimeImmutable('2020-12-07 00:21:47', new DateTimeZone('+02:00')),
new DateTimeImmutable('2020-03-29 00:21:47', new DateTimeZone('Europe/Berlin')),
];
$timeParts = explode(':', '19:30:00');
foreach ($dates as $date) {
// get a modified copy of the immutable date time
$other = $date->setTime(...$timeParts);
var_dump($other->format(DateTimeInterface::ATOM));
// differences as a DateInterval
$difference = $date->diff($other);
var_dump($difference->format('%h hour(s), %i minute(s)'));
}
Output:
string(25) "2020-12-07T19:30:00+00:00"
string(23) "19 hour(s), 8 minute(s)"
string(25) "2020-12-07T19:30:00-08:00"
string(23) "19 hour(s), 8 minute(s)"
string(25) "2020-12-07T19:30:00+02:00"
string(23) "19 hour(s), 8 minute(s)"
string(25) "2020-03-29T19:30:00+02:00"
string(23) "18 hour(s), 8 minute(s)"
Notice that the last result is 18 hours. This is because on March 29th is the clock change to daylight saving time in this time zone.
The difference between two times on the same day is being sought. With this solution with DateTime, the date from $d1 is set to the current day, the difference is calculated and formatted.
$d1 = '2020-12-07 18:21:47';
$t1 = '19:30:00';
$diffHis = date_create($d1)
->modify(date('Y-m-d'))
->diff(date_create($t1))
->format('%r%H:%I:%s')
;
echo $diffHis; //01:08:13
Another variant uses DateTime::createFromFormat with a format that hides the date from $d1. So the time from $d1 gets the current date.
$diffHis = DateTime::createFromFormat('????-??-?? H:i:s',$d1)
->diff(date_create($t1))
->format('%r%H:%I:%s')
;
$d1 = '2020-12-07 18:21:47';
$t1 = date('Y-m-d',strtotime('2020-12-07 18:21:47')).' 19:30:00'; // or $t1 = '2020-12-07 19:30:00';
if( strtotime($t1) > strtotime($d1)){
$diff = date("H:i:s",(strtotime($t1) - strtotime($d1)));
}
print_r( $diff );
//should return you correct result
01:08:13
Check that you are passing vars in correct way.

PHP Dates are frustrating me

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.

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.

Laravel Carbon error with year in difference between dates

Good afternoon...
I try to make the difference in years between the current date and a date in the database like this:
$final = '2016-05-10'; //date database
$hoy = \Carbon\Carbon::now(); //today
$fecha_ingreso = \Carbon\Carbon::createFromFormat('Y-m-d', $final);
$diff = $hoy->diffInYears($fecha_ingreso); //diff
But when doing a var_dump() of $fecha_ingreso it shows me the following:
object(Carbon\Carbon)#259 (3) { ["date"]=> string(26) "2155-05-10 22:27:09.000000" ["timezone_type"]=> int(3) ["timezone"]=> string(3) "UTC" }
The day and the month are ok but the year is not, why can this error be ??
Thank you very much for the help.
I assume you want the difference in number of years, try this.
$dbDate = \Carbon\Carbon::parse('2016-05-10');
$diffYears = \Carbon\Carbon::now()->diffInYears($dbDate);
// $diffYears is 1

Difference in dates between servers

I am wondering why I have been getting totally invalid computation by PHP all the time.
I have code like this:
echo floor((strtotime("2017-03-27") - strtotime("2017-03-24"))/86400);
which on the one of the server returns: 3 (like 3 days)
and on the another server returns: 2! (2.9583333333333 day?) Why is there a variance?
Or, just use better methods:
EDIT I updated the code to use the same dates as OP. It returns 3, as it should, and I'm fairly confident it will do that on whatever server you put it on to test.
<?php
$date1 = date_create('2017-03-27');
$date2 = date_create('2017-03-24');
$interval = date_diff($date1,$date2);
echo $interval->format('%a');
?>
Ref: http://php.net/manual/en/function.date-diff.php
Your servers maybe sitting in two different time zones. Convert the days to hours and you will get a difference of one hour.
3 days * 24 hours/1 day = 72 hours
2.958333 days * 24 hours/1 day = 71 hours
Since some people are having difficulty accepting that this is due to a TZ-specific DST change, have some proof:
function poc($tz_str) {
$tz = new DateTimeZone($tz_str);
$start = (new DateTime('2017-03-24', $tz))->format('U');
$end = (new DateTime('2017-03-27', $tz))->format('U');
return [$tz_str, $end - $start, ( $end - $start ) / 86400];
}
var_dump(
poc('UTC'),
poc('Europe/London'),
poc('America/New_York')
);
Output:
array(3) {
[0]=> string(3) "UTC"
[1]=> int(259200)
[2]=> int(3)
}
array(3) {
[0]=> string(13) "Europe/London"
[1]=> int(255600)
[2]=> float(2.9583333333333)
}
array(3) {
[0]=> string(16) "America/New_York"
[1]=> int(259200)
[2]=> int(3)
}
UTC has no DST, not affected.
Most of the eastern hemisphere has their DST change on March 26, affected.
Most of the western hemisphere has their DST change on March 12, not affected.
That said, don't do manual date math on a Unix timestamp.

Categories