Calculate Text Diffs in PHP

Calculate text diffs in PHP

What sort of diffs? File diffs? There is array_diff() which acts on arrays. Then there is also xdiff, which "enables you to create and apply patch files containing differences between different revisions of files.". The latter acts on files or strings.

Edit: I should add xdiff doesn't appear to be out in a release yet. You have to build from source to use it.

PHP/JS Text Diff

Ok so it has been a while.

I actually decided to look around at what other people use and stumbled upon what Yii ( http://www.yiiframework.com ) uses.

They actually use the PEAR module for their text_diff and they use it in its new form on the horde channel. It seems that text_diff is now a horde project but you can just as easily integrate a version of it into your application and that is what Yii does by default (it comes pre-bundled with a version of it).

So I searched around a bit to find out how they used it and how to get into it and I came across:

public function actionDiff()
{
Yii::import('gii.components.TextDiff');

$model=$this->prepare();
if(isset($_GET['id']) && isset($model->files[$_GET['id']]))
{
$file=$model->files[$_GET['id']];
if(!in_array($file->type,array('php', 'txt','js','css')))
$diff=false;
elseif($file->operation===CCodeFile::OP_OVERWRITE)
$diff=TextDiff::compare(file_get_contents($file->path), $file->content);
else
$diff='';

$this->renderPartial('/common/diff',array(
'file'=>$file,
'diff'=>$diff,
));
}
else
throw new CHttpException(404,'Unable to find the code you requested.');
}

In CCodeGenerator for their Gii module ( http://www.yiiframework.com/doc/api/1.1/CCodeGenerator/ ). The important part is where they actually hook into the PEAR module:

$diff=TextDiff::compare(file_get_contents($file->path), $file->content);

By reading in the contents of two files which produces a diffed output.

Originally I did not want to use PEAR because of the bloat but this module is quite slim for a fully featured text_diff so I have decided to go with this. Not only that but, at the moment, it is the only text_diff module that has truly worked for me so I am keeping with the best, even if the best is quite memory hungry.

PHP text diff script

You might try using the PEAR Text_Diff it provides a text-based diff engine and renders for multiple diff output formats.

How to calculate the difference between two dates using PHP?

Use this for legacy code (PHP < 5.3). For up to date solution see jurka's answer below

You can use strtotime() to convert two dates to unix time and then calculate the number of seconds between them. From this it's rather easy to calculate different time periods.

$date1 = "2007-03-24";
$date2 = "2009-06-26";

$diff = abs(strtotime($date2) - strtotime($date1));

$years = floor($diff / (365*60*60*24));
$months = floor(($diff - $years * 365*60*60*24) / (30*60*60*24));
$days = floor(($diff - $years * 365*60*60*24 - $months*30*60*60*24)/ (60*60*24));

printf("%d years, %d months, %d days\n", $years, $months, $days);

Edit: Obviously the preferred way of doing this is like described by jurka below. My code is generally only recommended if you don't have PHP 5.3 or better.

Several people in the comments have pointed out that the code above is only an approximation. I still believe that for most purposes that's fine, since the usage of a range is more to provide a sense of how much time has passed or remains rather than to provide precision - if you want to do that, just output the date.

Despite all that, I've decided to address the complaints. If you truly need an exact range but haven't got access to PHP 5.3, use the code below (it should work in PHP 4 as well). This is a direct port of the code that PHP uses internally to calculate ranges, with the exception that it doesn't take daylight savings time into account. That means that it's off by an hour at most, but except for that it should be correct.

<?php

/**
* Calculate differences between two dates with precise semantics. Based on PHPs DateTime::diff()
* implementation by Derick Rethans. Ported to PHP by Emil H, 2011-05-02. No rights reserved.
*
* See here for original code:
* http://svn.php.net/viewvc/php/php-src/trunk/ext/date/lib/tm2unixtime.c?revision=302890&view=markup
* http://svn.php.net/viewvc/php/php-src/trunk/ext/date/lib/interval.c?revision=298973&view=markup
*/

function _date_range_limit($start, $end, $adj, $a, $b, $result)
{
if ($result[$a] < $start) {
$result[$b] -= intval(($start - $result[$a] - 1) / $adj) + 1;
$result[$a] += $adj * intval(($start - $result[$a] - 1) / $adj + 1);
}

if ($result[$a] >= $end) {
$result[$b] += intval($result[$a] / $adj);
$result[$a] -= $adj * intval($result[$a] / $adj);
}

return $result;
}

function _date_range_limit_days($base, $result)
{
$days_in_month_leap = array(31, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
$days_in_month = array(31, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);

_date_range_limit(1, 13, 12, "m", "y", &$base);

$year = $base["y"];
$month = $base["m"];

if (!$result["invert"]) {
while ($result["d"] < 0) {
$month--;
if ($month < 1) {
$month += 12;
$year--;
}

$leapyear = $year % 400 == 0 || ($year % 100 != 0 && $year % 4 == 0);
$days = $leapyear ? $days_in_month_leap[$month] : $days_in_month[$month];

$result["d"] += $days;
$result["m"]--;
}
} else {
while ($result["d"] < 0) {
$leapyear = $year % 400 == 0 || ($year % 100 != 0 && $year % 4 == 0);
$days = $leapyear ? $days_in_month_leap[$month] : $days_in_month[$month];

$result["d"] += $days;
$result["m"]--;

$month++;
if ($month > 12) {
$month -= 12;
$year++;
}
}
}

return $result;
}

function _date_normalize($base, $result)
{
$result = _date_range_limit(0, 60, 60, "s", "i", $result);
$result = _date_range_limit(0, 60, 60, "i", "h", $result);
$result = _date_range_limit(0, 24, 24, "h", "d", $result);
$result = _date_range_limit(0, 12, 12, "m", "y", $result);

$result = _date_range_limit_days(&$base, &$result);

$result = _date_range_limit(0, 12, 12, "m", "y", $result);

return $result;
}

/**
* Accepts two unix timestamps.
*/
function _date_diff($one, $two)
{
$invert = false;
if ($one > $two) {
list($one, $two) = array($two, $one);
$invert = true;
}

$key = array("y", "m", "d", "h", "i", "s");
$a = array_combine($key, array_map("intval", explode(" ", date("Y m d H i s", $one))));
$b = array_combine($key, array_map("intval", explode(" ", date("Y m d H i s", $two))));

$result = array();
$result["y"] = $b["y"] - $a["y"];
$result["m"] = $b["m"] - $a["m"];
$result["d"] = $b["d"] - $a["d"];
$result["h"] = $b["h"] - $a["h"];
$result["i"] = $b["i"] - $a["i"];
$result["s"] = $b["s"] - $a["s"];
$result["invert"] = $invert ? 1 : 0;
$result["days"] = intval(abs(($one - $two)/86400));

if ($invert) {
_date_normalize(&$a, &$result);
} else {
_date_normalize(&$b, &$result);
}

return $result;
}

$date = "1986-11-10 19:37:22";

print_r(_date_diff(strtotime($date), time()));
print_r(_date_diff(time(), strtotime($date)));

Highlight the difference between two strings in PHP

You were able to use the PHP Horde_Text_Diff package.

However this package is no longer available.

Compare 2 strings and display difference (php or javascript)

This answer to a related question seems promising for javascript. google-diff-match-patch

It provides an API which will take care of all the complex and well known algorithms. However you'll have to do some work with the presentation.

PHP is more versatile there is a lot of diff tools out there.
Look this other related question Calculate text diffs in PHP.

Count the number of differences between two string in php?

Maybe this helps. I forked the comment from Anant.

$first_str = "abcdez";
$second_str= "abhdx";

$first_str_array = str_split($first_str);

$second_str_array = str_split($second_str);

$first_count = count($first_str_array);
$second_count = count($second_str_array);

if (($first_count - $second_count) > 0) {
$count = $first_count - $second_count;
unset($first_str_array[$first_count-$count]);
} else if (($second_count - $first_count) > 0){
$count = $second_count - $first_count;
unset($second_str_array[$second_count-$count]);
}

$final_difference = array_diff($first_str_array,$second_str_array);

Calculate Absolute Differences between Dates in PHP

Here's a function that does 99% of what you want (it doesn't implement rounding when length != 'l', and it also doesn't remove the s from e.g. 1 years). 0 values are not output, although you could add a parameter to control that.

function friendlyDtmDiff($date1, $date2, $length = '', $format = '') {
// Create DateTime for diff()
$dt1 = new \DateTime($date1);
$dt2 = new \DateTime($date2);

// Create intervals
if ($dt1 < $dt2) {
$sign = '';
$interval = $dt1->diff($dt2);
}
else {
$sign = '-';
$interval = $dt2->diff($dt1);
}
// Output format (minimum 2 digits for upper case formats)
$of = ($format < 'a') ? '%02d' : '%d';

// generate output using an array of terms to be imploded
$output = array();
// create time components
switch ($format) {
case 'Y':
case 'y':
$years = $interval->y;
if ($years) $output[] = sprintf("$of years", $years);
if ($length != 'l') break;
$interval->y = 0;
case 'M':
case 'm':
$months = $interval->y * 12 + $interval->m;
if ($months) $output[] = sprintf("$of months", $months);
if ($length != 'l') break;
$interval->m = $interval->y = 0;
case 'D':
case 'd':
$days = ($interval->y * 12 + $interval->m) * 30 + $interval->d;
if ($days) $output[] = sprintf("$of days", $days);
if ($length != 'l') break;
$interval->d = $interval->m = $interval->y = 0;
case 'H':
case 'h':
$hours = (($interval->y * 12 + $interval->m) * 30 + $interval->d) * 24 + $interval->h;
if ($hours) $output[] = sprintf("$of hours", $hours);
if ($length != 'l') break;
$interval->h = $interval->d = $interval->m = $interval->y = 0;
case 'I':
case 'i':
$minutes = ((($interval->y * 12 + $interval->m) * 30 + $interval->d) * 24 + $interval->h) * 60 + $interval->i;
if ($minutes) $output[] = sprintf("$of minutes", $minutes);
if ($length != 'l') break;
$interval->i = $interval->h = $interval->d = $interval->m = $interval->y = 0;
case 'S':
case 's':
$seconds = (((($interval->y * 12 + $interval->m) * 30 + $interval->d) * 24 + $interval->h) * 60 + $interval->i) * 60 + $interval->s;
if ($seconds) $output[] = sprintf("$of seconds", $seconds);
break;
default:
return 'Invalid format';
break;
}
// put the output string together
$last = array_pop($output);
return $sign . (count($output) ? implode(', ', $output) . ' and ' : '') . $last;
}

Example usage:

echo friendlyDtmDiff('2020-02-28 00:00:00', '2020-03-01 12:00:56', '', 'h') . PHP_EOL;
echo friendlyDtmDiff('2020-02-28 00:00:00', '2020-03-01 12:00:56', 'l', 'h') . PHP_EOL;
echo friendlyDtmDiff('2020-02-28 00:00:00', '2020-03-01 12:08:56', 'l', 'h') . PHP_EOL;
echo friendlyDtmDiff('2018-12-28 00:00:00', '2020-04-11 04:08:56', 'l', 'y') . PHP_EOL;
echo friendlyDtmDiff('2018-12-28 00:00:00', '2020-04-11 04:08:56', 'l', 'm') . PHP_EOL;
echo friendlyDtmDiff('2018-12-28 00:00:00', '2020-04-11 04:08:56', 'l', 'd') . PHP_EOL;
echo friendlyDtmDiff('2018-12-28 00:00:00', '2020-04-11 04:08:56', 'l', 'h') . PHP_EOL;
echo friendlyDtmDiff('2018-12-28 00:00:00', '2020-04-11 04:08:56', 'l', 'i') . PHP_EOL;
echo friendlyDtmDiff('2018-12-28 00:00:00', '2020-04-11 04:08:56', 'l', 's') . PHP_EOL;

Output:

60 hours
60 hours and 56 seconds
60 hours, 8 minutes and 56 seconds
1 years, 3 months, 14 days, 4 hours, 8 minutes and 56 seconds
15 months, 14 days, 4 hours, 8 minutes and 56 seconds
464 days, 4 hours, 8 minutes and 56 seconds
11140 hours, 8 minutes and 56 seconds
668408 minutes and 56 seconds
40104536 seconds

Demo on 3v4l.org

How to calculate difference of two string dates in days using PHP?

Try this, use date_create

$dnow = "2016-12-1";
$dafter = "2016-12-11";
$date1=date_create($dnow);
$date2=date_create($dafter);
$diff=date_diff($date1,$date2);
print_r($diff);

DEMO



Related Topics



Leave a reply



Submit