HiveBrain v1.2.0
Get Started
← Back to all entries
gotchaphpModerate

Display the relative time difference between two dates

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
thedatestimedifferencetwobetweendisplayrelative

Problem

Goal: To create a function that returns the relative time difference between two given timestamps, using the DateTime class.

Current approach:

function time_elapsed($date1, $date2) {
    $dt1 = new DateTime($date1);
    $dt2 = new DateTime($date2);

    $diff = $dt1->diff($dt2);

    $ret = $diff->format('%y years, %m months, %a days, %h hours, %i minutes, %S seconds');

    $ret = str_replace(
        array('0 years,',' 0 months,',' 0 days,',' 0 hours,', ' 0 minutes,'), 
        '', 
        $ret
    );

    $ret = str_replace(
        array('1 years, ',' 1 months, ',' 1 days, ',' 1 hours, ',' 1 minutes'), 
        array('1 year, ','1 month, ',' 1 day, ',' 1 hour, ',' 1 minute'), 
        $ret
    );

    return $ret;
}


As you can see, the function works fine. I'm currently using a couple of str_replace() calls to remove the unnecessary parts from the formatted string, but I don't think that's a very good approach. I'm sure what I have written can be cleaned up and improved, using a different approach, perhaps.

Solution

-
I guess you have a bug here:

$ret = $diff->format('%y years, %m months, %a days, %h hours, %i minutes, %S seconds');


%a should be %d. With %a

time_elapsed("2012-07-08 11:14:15.889342", "2014-09-10 13:15:17.889342");


prints total number of days:

2 years, 2 months, 794 days, 2 hours, 1 minute, 02 seconds


Using %d changes 794 days to 2 days.

-
Another approach is iterating through of an array of units:

function time_elapsed2($start, $end) {
    $start = new DateTime($start);
    $end = new DateTime($end);

    $interval = $end->diff($start);

    $units = array(
        "%y" => sp("year", "years"),
        "%m" => sp("month", "months"),
        "%d" => sp("day", "days"),
        "%h" => sp("hour", "hours"),
        "%i" => sp("minute", "minutes"),
        "%s" => sp("second", "seconds")
    );

    $result = array();
    foreach ($units as $format_char => $names) {
        $formatted_value = $interval->format($format_char);
        if ($formatted_value == "0") {
            continue;
        }
        $result[] = get_formatted_string($formatted_value, $names);
    }  

    return implode(", ", $result);
} 

function sp($singular, $plural) {
    return array("singular" => $singular, "plural" => $plural);
}

function get_formatted_string($formatted_value, $names) {
    $result = $formatted_value . " ";
    if ($formatted_value == "1") {
        $result .= $names["singular"];
    } else {
        $result .= $names["plural"];
    }
    return $result;
}


(In production code I'd use constants instead of singular and plural.) The array also helps if you want to translate your page to other languages.

Code Snippets

$ret = $diff->format('%y years, %m months, %a days, %h hours, %i minutes, %S seconds');
time_elapsed("2012-07-08 11:14:15.889342", "2014-09-10 13:15:17.889342");
2 years, 2 months, 794 days, 2 hours, 1 minute, 02 seconds
function time_elapsed2($start, $end) {
    $start = new DateTime($start);
    $end = new DateTime($end);

    $interval = $end->diff($start);

    $units = array(
        "%y" => sp("year", "years"),
        "%m" => sp("month", "months"),
        "%d" => sp("day", "days"),
        "%h" => sp("hour", "hours"),
        "%i" => sp("minute", "minutes"),
        "%s" => sp("second", "seconds")
    );

    $result = array();
    foreach ($units as $format_char => $names) {
        $formatted_value = $interval->format($format_char);
        if ($formatted_value == "0") {
            continue;
        }
        $result[] = get_formatted_string($formatted_value, $names);
    }  

    return implode(", ", $result);
} 

function sp($singular, $plural) {
    return array("singular" => $singular, "plural" => $plural);
}

function get_formatted_string($formatted_value, $names) {
    $result = $formatted_value . " ";
    if ($formatted_value == "1") {
        $result .= $names["singular"];
    } else {
        $result .= $names["plural"];
    }
    return $result;
}

Context

StackExchange Code Review Q#38154, answer score: 10

Revisions (0)

No revisions yet.