Accurate dif between two times.

PHP programming forum. Ask questions or help people concerning PHP code. Don't understand a function? Need help implementing a class? Don't understand a class? Here is where to ask. Remember to do your homework!

Moderator: General Moderators

Post Reply
Gen-ik
DevNet Resident
Posts: 1059
Joined: Mon Aug 12, 2002 7:08 pm
Location: London. UK.

Accurate dif between two times.

Post by Gen-ik »

I've been trying to work out an accurate number of months, weeks, days, etc between two unix timestamps. I've got it working up until I hit the months then it goes pear-shaped because of the variable number of days in a month/leap year etc.

Does anyone know of an easy way to do this?

Basically what I'm after is something that will give me the number of years, months, weeks, days, hours, and seconds that have past since $dateX.

Any help would be great.

Thanks.
Last edited by Gen-ik on Fri Dec 12, 2003 1:38 pm, edited 1 time in total.
User avatar
JayBird
Admin
Posts: 4524
Joined: Wed Aug 13, 2003 7:02 am
Location: York, UK
Contact:

Post by JayBird »

not sure if this might help ya

http://www.faqts.com/knowledge_base/vie ... /aid/12241

Mark
Gen-ik
DevNet Resident
Posts: 1059
Joined: Mon Aug 12, 2002 7:08 pm
Location: London. UK.

Post by Gen-ik »

Yeah that's pretty much what I have got at the mo... trouble is (even with the info at the other end of that link) people seem to hit problems when they want an accurate number of months.

The usual way is to just say that there are four weeks in a month, the trouble is not every month has 28 days in it.

Hmmm. Time for a bit more brain work me thinks.
User avatar
JayBird
Admin
Posts: 4524
Joined: Wed Aug 13, 2003 7:02 am
Location: York, UK
Contact:

Post by JayBird »

okay buddy, found a script. Haven't got time to check it myself, but i am going to need something like this soon for the project i am working on, so let me know how you get on.

Code: Select all

<?php
/*
    License:  do whatever you want with this code
    
    Disclaimer:  This code works well on my system, but may not on yours.  Use
    with circumspection and trepidation.  If this code blows up your system, 
    I recommend vituperation.
*/



/*
    function smoothdate simply takes a year, month, and a day, and
    concatenates them in the form YYYYMMDD
    
    the function date_difference uses this function
*/

function smoothdate ($year, $month, $day)
{
    return sprintf ('%04d', $year) . sprintf ('%02d', $month) . sprintf ('%02d', $day);
}


/*
    function date_difference calculates the difference between two dates in
    years, months, and days.  There is a ColdFusion funtion called, I
    believe, date_diff() which performs a similar function.
    
    It does not make use of 32-bit unix timestamps, so it will work for dates
    outside the range 1970-01-01 through 2038-01-19.  This function works by
    taking the earlier date finding the maximum number of times it can
    increment the years, months, and days (in that order) before reaching
    the second date.  The function does take yeap years into account, but does
    not take into account the 10 days removed from the calendar (specifically
    October 5 through October 14, 1582) by Pope Gregory to fix calendar drift.
    
    As input, it requires two associative arrays of the form:
    array (    'year' => year_value,
            'month' => month_value.
            'day' => day_value)
    
    The first input array is the earlier date, the second the later date.  It
    will check to see that the two dates are well-formed, and that the first
    date is earlier than the second.
    
    If the function can successfully calculate the difference, it will return
    an array of the form:
    array (    'years' => number_of_years_different,
            'months' => number_of_months_different,
            'days' => number_of_days_different)
            
    If the function cannot calculate the difference, it will return FALSE.
    
*/

function date_difference ($first, $second)
{
    $month_lengths = array (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);

    $retval = FALSE;

    if (    checkdate($first['month'], $first['day'], $first['year']) &&
            checkdate($second['month'], $second['day'], $second['year'])
        )
    {
        $start = smoothdate ($first['year'], $first['month'], $first['day']);
        $target = smoothdate ($second['year'], $second['month'], $second['day']);
                            
        if ($start <= $target)
        {
            $add_year = 0;
            while (smoothdate ($first['year']+ 1, $first['month'], $first['day']) <= $target)
            {
                $add_year++;
                $first['year']++;
            }
                                                                                                            
            $add_month = 0;
            while (smoothdate ($first['year'], $first['month'] + 1, $first['day']) <= $target)
            {
                $add_month++;
                $first['month']++;
                
                if ($first['month'] > 12)
                {
                    $first['year']++;
                    $first['month'] = 1;
                }
            }
                                                                                                                                                                            
            $add_day = 0;
            while (smoothdate ($first['year'], $first['month'], $first['day'] + 1) <= $target)
            {
                if (($first['year'] % 100 == 0) && ($first['year'] % 400 == 0))
                {
                    $month_lengths[1] = 29;
                }
                else
                {
                    if ($first['year'] % 4 == 0)
                    {
                        $month_lengths[1] = 29;
                    }
                }
                
                $add_day++;
                $first['day']++;
                if ($first['day'] > $month_lengths[$first['month'] - 1])
                {
                    $first['month']++;
                    $first['day'] = 1;
                    
                    if ($first['month'] > 12)
                    {
                        $first['month'] = 1;
                    }
                }
                
            }
                                                                                                                                                                                                                                                        
            $retval = array ('years' => $add_year, 'months' => $add_month, 'days' => $add_day);
        }
    }
                                                                                                                                                                                                                                                                                
    return $retval;
}


/*
    This code is merely an example of use of the function
*/

print '<pre>';
$begin = array ('year' => 2001, 'month' => 3, 'day' => 14);
$end = array ('year' => 2004, 'month' => 3, 'day' => 14);

$foo = date_difference ($begin, $end);
if ($foo !== FALSE)
{
    print_r ($foo);
}
else
{
    print 'FALSE';
}

?>

Mark
Gen-ik
DevNet Resident
Posts: 1059
Joined: Mon Aug 12, 2002 7:08 pm
Location: London. UK.

Post by Gen-ik »

Yep seems to do the trick. I might change it a bit though so that you can just chuck in two unix_timestamps. I'll post it here when it's sorted.
User avatar
m3mn0n
PHP Evangelist
Posts: 3548
Joined: Tue Aug 13, 2002 3:35 pm
Location: Calgary, Canada

Post by m3mn0n »

Cool. I was in need of this same thing also.
Gen-ik
DevNet Resident
Posts: 1059
Joined: Mon Aug 12, 2002 7:08 pm
Location: London. UK.

Post by Gen-ik »

I've just been reading through this post again and a thought popped into my head.

The main problem when working out the amount of time between two dates is basically the number days in each month that has past. So, I'm thinking that if we work with 28 days per month (4 weeks) which is pretty easy to do, then all that's needed is the number of extra days in each month.. which again shouldn't be too hard to work out.

Hmm. I'm going to have a play around with a few ideas and I'll let you know how it goes. If this works then I should be able to come up with a function() that can work out years, months, days, hours, minutes, and seconds, and also make adjustments for Daylight Savings (if needed) and also leap-years.

If I can get anything working I'll post it here so you guys can do the copy 'n' paste thing.
Post Reply