Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP diff() gives incorrect values where $date1 = '2016-03-01'

Tags:

php

I am using the code below to determine employee service in a year:

$datePay1 = new DateTime($date1);
$datePay2 = new DateTime($date2);
$interval = $datePay1->diff($datePay2);
$vYears = $interval->y;
$vMonths = $interval->m;
$vDays = $interval->d;
$service = $vYears." years, ".$vMonths." months, ".$vDays." days"; 

Case 1:

$date1 = '2016-03-01';
$date2 = '2017-03-01';

Service = 0 years, 11 months, 30 days

Case 2:

$date1 = '2017-03-01';
$date2 = '2018-03-01';

Service = 1 years, 0 months, 0 days

Case 1 seems to be incorrect. Why is this? Is it because 2016 was a leap year? The server runs PHP v5.6.

like image 276
PeterC Avatar asked Aug 23 '18 09:08

PeterC


1 Answers

This is related to your timezone settings and leap year - in 2016 February had 29 days. Intervals are calculated using UTC timezone, and depending on your timezone DateTime may evaluate to different time that you may expecting. For example if you're using Europe/Warsaw timezone, DateTime('2016-03-01') (which is the same as DateTime('2016-03-01 00:00:00')) will evaluate to to 2016-02-29 23:00:00.

Sample:

date_default_timezone_set('Europe/Warsaw');
$date1 = '2016-03-01';
$date2 = '2017-03-01';
$datePay1 = new DateTime($date1);
$datePay2 = new DateTime($date2);

echo 'datePay1: ' . $datePay1->setTimezone(new DateTimeZone('UTC'))->format('Y-m-d H:i:s')
    . "\ndatePay2: " . $datePay2->setTimezone(new DateTimeZone('UTC'))->format('Y-m-d H:i:s');

Result:

datePay1: 2016-02-29 23:00:00
datePay2: 2017-02-28 23:00:00

https://3v4l.org/mKNhX

As you can see you're actually comparing 2016-02-29 23:00:00 to 2017-02-28 23:00:00. And since there is one day difference between February 29 and February 28, it is not considered as full year difference.


To make it more consistent and timezone independent, specify UTC as timezone explicitly:

date_default_timezone_set('Europe/Warsaw');
$date1 = '2016-03-01';
$date2 = '2017-03-01';
$datePay1 = new DateTime($date1, new DateTimeZone('UTC'));
$datePay2 = new DateTime($date2, new DateTimeZone('UTC'));
$interval = $datePay1->diff($datePay2);
$vYears = $interval->y;
$vMonths = $interval->m;
$vDays = $interval->d;
echo  "$vYears years, $vMonths months, $vDays days";

Result:

1 years, 0 months, 0 days

https://3v4l.org/lFnkL

like image 112
rob006 Avatar answered Nov 03 '22 22:11

rob006