Technically Feasible

A basic date_diff for PHP 5.2

Likeness of Michael Oldroyd
Michael Oldroyd
⚠️ This content was imported from a previous incarnation of this blog, and may contain formatting errors

I came across a problem having developed a site with a PHP 5.3 environment, when moving the site to the live environment the server was running PHP 5.2. Whilst the server gets upgraded I looked into getting the code to work in some form in the meantime. The main issues are the functions lcfirst() and date_diff(). The former is a simple fix, a function which lower-cases the first letter of a string — I was surprised this was only introduced in 5.3!

if(function_exists('lcfirst') === false) {
function lcfirst($str) {
$str[0] = strtolower($str[0]);
return $str;
}
}

The issue with date_diff is it's reliance on the DateInterval class, which as the name suggests is a native object introduced in 5.3 to represent the interval between two dates. The function ought to be functionally equivalent between both PHP 5.2 and 5.3, otherwise it would be useless. I found something that I am fairly happy with, in that it accepts the same inputs and outputs as the native 5.3 version. The calculations aren't correct though, unfortunately, and it's an incomplete implementation. I corrected the "invert" data type values returned, and also added support for "days" as these are the main things I am using.

/**
* Workaround for PHP < 5.3.0
*/
if(!function_exists('date_diff')) {
class DateInterval {
public $y;
public $m;
public $d;
public $h;
public $i;
public $s;
public $invert;
public $days;

public function format($format) {
  $format = str\_replace('%R%y', 
    ($this->invert ? '-' : '+') . $this->y, $format);
  $format = str\_replace('%R%m', 
     ($this->invert ? '-' : '+') . $this->m, $format);
  $format = str\_replace('%R%d', 
     ($this->invert ? '-' : '+') . $this->d, $format);
  $format = str\_replace('%R%h', 
     ($this->invert ? '-' : '+') . $this->h, $format);
  $format = str\_replace('%R%i', 
     ($this->invert ? '-' : '+') . $this->i, $format);
  $format = str\_replace('%R%s', 
     ($this->invert ? '-' : '+') . $this->s, $format);

  $format = str\_replace('%y', $this->y, $format);
  $format = str\_replace('%m', $this->m, $format);
  $format = str\_replace('%d', $this->d, $format);
  $format = str\_replace('%h', $this->h, $format);
  $format = str\_replace('%i', $this->i, $format);
  $format = str\_replace('%s', $this->s, $format);
  
  return $format;
}

}

function date_diff(DateTime $date1, DateTime $date2) {

$diff = new DateInterval();

if($date1 > $date2) {
  $tmp = $date1;
  $date1 = $date2;
  $date2 = $tmp;
  $diff->invert = 1;
} else {
  $diff->invert = 0;
}

$diff->y = ((int) $date2->format('Y')) - ((int) $date1->format('Y'));
$diff->m = ((int) $date2->format('n')) - ((int) $date1->format('n'));
if($diff->m < 0) {
  $diff->y -= 1;
  $diff->m = $diff->m + 12;
}
$diff->d = ((int) $date2->format('j')) - ((int) $date1->format('j'));
if($diff->d < 0) {
  $diff->m -= 1;
  $diff->d = $diff->d + ((int) $date1->format('t'));
}
$diff->h = ((int) $date2->format('G')) - ((int) $date1->format('G'));
if($diff->h < 0) {
  $diff->d -= 1;
  $diff->h = $diff->h + 24;
}
$diff->i = ((int) $date2->format('i')) - ((int) $date1->format('i'));
if($diff->i < 0) {
  $diff->h -= 1;
  $diff->i = $diff->i + 60;
}
$diff->s = ((int) $date2->format('s')) - ((int) $date1->format('s'));
if($diff->s < 0) {
  $diff->i -= 1;
  $diff->s = $diff->s + 60;
}

$start\_ts   = $date1->format('U');
$end\_ts   = $date2->format('U');
$days     = $end\_ts - $start\_ts;
$diff->days  = round($days / 86400);

if (($diff->h > 0 || $diff->i > 0 || $diff->s > 0))
  $diff->days += ((bool) $diff->invert)
    ? 1
    : -1;

return $diff;

}

}

It works pretty well (bar the inaccuracies), and hopefully I won't have a use for it again anyway.

Image of me

Michael Oldroyd

Michael is a Software Engineer working in the North West of England. Michael spends his days building hand-crafted PHP applications. Rumours of his super-hero status are currently unconfirmed. He savours his victories when solving difficult programming challenges; occasionally writing about them here, on his personal blog.