Jump to content

Archived

This topic is now archived and is closed to further replies.

DJMurtz

substract two dates and convert remaining time

Recommended Posts

Hi,

Right now I have two dates. One date is (for example) [b]2007-04-15 00:00:00[/b] The other date is the current date. I want to substract the current date from the '2007-04-15 00:00:00' date. I did this by converting both dates to a UNIX timestamp and then substracting them from eachother.

Next thing I did was this:

[code]
<?php
        $iTimeLeft = strtotime($aMembersInfo['expiredate']) - time();
        $iYears = 0;
        $iDays = 0;
        $iHours = 0;
        $iMinutes = 0;
        $iSeconds = 0;
        
        while($iTimeLeft >= 31536000) {
            $iTimeLeft -= 31536000;
            $iYears += 1;
        }
        while($iTimeLeft >= 86400) {
            $iTimeLeft -= 86400;
            $iDays += 1;
        }
        while($iTimeLeft >= 3600) {
            $iTimeLeft -= 3600;
            $iHours += 1;
        }
        while($iTimeLeft >= 60) {
            $iTimeLeft -= 60;
            $iMinutes += 1;
        }
        if($iTimeLeft >= 0) {
            $iSeconds = $iTimeLeft;
        }
        if($iYears != 0) {
            $iTimeLeft = $iYears . 'y ' . $iDays . 'd';
        } elseif($iDays != 0 && $iDays != 1) {
            $iTimeLeft = $iDays . 'd';
        } elseif($iDays == 1) {
            $iTimeLeft = $iDays . 'd ' . $iHours . 'h';
        } elseif($iHours != 0) {
            $iTimeLeft = $iHours . 'h ' . $iMinutes . 'm';
        } elseif($iMinutes != 0) {
            $iTimeLeft = $iMinutes . 'm ' . $iSeconds . 's';
        } elseif($iSeconds != 0) {
            $iTimeLeft = $iSeconds . 's';
        } else {
            $iTimeLeft = 'Disabled';
        }
?>
[/code]

As you can see I started counting how many years, months, days, hours, minutes and finally seconds fit into the UNIX timestamp I got from substracting the two dates. After this I started putting the number of years, months, etc into their own variables and parse them in the way I want on the screen.

All of this works great, with one downside. It's inacurate. As you can see in my code I presume that a month has always 30 days, and a year 365 days. This isn't correct and thus the output is false.

I've been trying to think of a way to get the same output, but with correct numbers but have so far found nothing that will help me do this. Does anyone of you know a solution to my problem? I thank you in advance!

Share this post


Link to post
Share on other sites
Well, you can use strtotime() to convert "English" dates to UNIX timestamps; then subtract them

[a href=\"http://us3.php.net/manual/en/function.strtotime.php\" target=\"_blank\"]http://us3.php.net/manual/en/function.strtotime.php[/a]

Share this post


Link to post
Share on other sites
[!--quoteo(post=365736:date=Apr 18 2006, 01:08 AM:name=poirot)--][div class=\'quotetop\']QUOTE(poirot @ Apr 18 2006, 01:08 AM) [snapback]365736[/snapback][/div][div class=\'quotemain\'][!--quotec--]
Well, you can use strtotime() to convert "English" dates to UNIX timestamps; then subtract them

[a href=\"http://us3.php.net/manual/en/function.strtotime.php\" target=\"_blank\"]http://us3.php.net/manual/en/function.strtotime.php[/a]
[/quote]

Thanks for the suggestion, but you can see that I already did this in my example..

Just to make it more clear:


Here I convert everything to UNIX timestamps:
$iTimeLeft = strtotime($aMembersInfo['expiredate']) - time();

After that I start substracting 31536000 seconds (1 year):
while($iTimeLeft >= 31536000) {
$iTimeLeft -= 31536000;
$iYears += 1;
}

After that days, hours, minutes and seconds.
But as I stated above, this is inacurate, because a year isn't always 365 days and a month isnt always 30 days.

I'm on to something tho, I think I figured it out, just making some final tweaks right now

Share this post


Link to post
Share on other sites
After messing around with php I got what I needed:

[code]
<?php
        // Calculate time left till deactivation account and echo in cel.
        
        // Extract variables from expire date/time
        $aExpireDate = explode(' ', $aMembersInfo['expiredate']);
        $aExpireTime = $aExpireDate[1];
        $aExpireDate = $aExpireDate[0];
        
        $aExpireDate = explode('-', $aExpireDate);
        $aExpireTime = explode(':', $aExpireTime);
        // Extract variables from current date/time
        $aCurrentDate = explode(' ', $aMembersInfo['now']);
        $aCurrentTime = $aCurrentDate[1];
        $aCurrentDate = $aCurrentDate[0];
        
        $aCurrentDate = explode('-', $aCurrentDate);
        $aCurrentTime = explode(':', $aCurrentTime);
        
        // Calculate differences between now and expire date
        $iDiffYears  = $aExpireDate[0] - $aCurrentDate[0];
        $iDiffMonths = $aExpireDate[1] - $aCurrentDate[1];
        $iDiffDays   = $aExpireDate[2] - $aCurrentDate[2];
    
        $iDiffHours  = $aExpireTime[0] - $aCurrentTime[0];
        $iDiffMins   = $aExpireTime[1] - $aCurrentTime[1];
        $iDiffSecs   = $aExpireTime[2] - $aCurrentTime[2];
    
        // Make sure correct number of days, months and years are shown
        if($iDiffDays < 0) {
            $iDiffMonths--;
            $iDiffDays += date("t",mktime(0,0,0,date("m")-1));
        }
        if($iDiffMonths < 0) {
            $iDiffYears--;
            $iDiffMonths += 12;
        }
        // We don't use months, convert them to days
        while($iDiffMonths != 0) {
            $iDiffMonths--;
            $iDiffDays += date("t",mktime(0,0,0,date("m")));
        }
        // Calculate time differences
        if($iDiffSecs < 0) {
            $iDiffMins--;
            $iDiffSecs += 60;
        }
        if($iDiffMins < 0) {
            $iDiffHours--;
            $iDiffMins += 60;
        }

        
        
        if($iDiffYears != 0) {
            $iTimeLeft = $iDiffYears . 'y ' . $iDiffDays . 'd';
        } elseif($iDiffDays != 0 && $iDiffDays != 1) {
            $iTimeLeft = $iDiffDays . 'd';
        } elseif($iDiffDays == 1) {
            $iTimeLeft = $iDiffDays . 'd ' . $iDiffHours . 'h';
        } elseif($iDiffHours != 0) {
            $iTimeLeft = $iDiffHours . 'h ' . $iDiffMins . 'm';
        } elseif($iDiffMins != 0) {
            $iTimeLeft = $iDiffMins . 'm ' . $iDiffSecs . 's';
        } elseif($iDiffSecs != 0) {
            $iTimeLeft = $iDiffSecs . 's';
        }
        if ($iTimeLeft{0} == '-') {
            $iTimeLeft = 'Disabled';
        }
?>
[/code]

Only problem with this method is, it's kind of a processorhog. It took php to parse 10 rows dates with the difference between them via this method [b]0.8 seconds[/b]. Maybe I can find a better way to do what I did in the above script in the future. But for now it works :)

Share this post


Link to post
Share on other sites
When I get home I'll try to write something, but if I end up with something like this, I'd think it's really not worth the hassle...

Share this post


Link to post
Share on other sites
I just looked at your first post more carefully, and I really can't think of a good solution.

So, can I give you an advice instead? Calculating time left befire expiration is not like "oh my, it must be totally accurate"; if I were a user with more than 1 year of time I wouldn't worry about "hey, its lacking 1 day" or something as long as I know the expiration date itself.

So, you should measure the advantages and drawbacks, I would prefer something less accurate over a slow script.

Share this post


Link to post
Share on other sites
Based on a standard subtraction

[code]     Y   M   D   H   m   s
--------------------------
   2007  4  15   0   0   0
   2006  4  18   0  37  45  -
---------------------------
      0 11  26  23  22  15[/code]

this processed an array of 10 dates in 0.0016 secs on my server.

[code]
<?php
function getmicrotime(){
    list($usec, $sec) = explode(" ",microtime());
    return ((float)$usec + (float)$sec);
    }

$t1 = getmicrotime();

function datediff($exp) {

        if (strtotime($exp) < time()) {
            $t1 = getdate(strtotime($exp));
            $t2 = getdate();

        } else {
            $t2 = getdate(strtotime($exp));
            $t1 = getdate();
        }

        //seconds
        if ($t2['seconds'] > $t1['seconds']) {
            $d['seconds'] = $t2['seconds'] - $t1['seconds'];
        }
        else {
            $d['seconds'] = $t2['seconds'] + 60 -  $t1['seconds'];
            $t1['minutes'] += 1;
        }

        //minutes
        if ($t2['minutes'] > $t1['minutes']) {
            $d['minutes'] = $t2['minutes'] - $t1['minutes'];
        }
        else {
            $d['minutes'] = $t2['minutes'] + 60 -  $t1['minutes'];
            $t1['hours'] += 1;
        }

        //hours
        if ($t2['hours'] > $t1['hours']) {
            $d['hours'] = $t2['hours'] - $t1['hours'];
        }
        else {
            $d['hours'] = $t2['hours'] + 24 -  $t1['hours'];
            $t1['mday'] += 1;
        }

        //days
        if ($t2['mday'] > $t1['mday']) {
            $d['mday'] = $t2['mday'] - $t1['mday'];
        }
        else {
               // get days in current month
            $dim = date('t', mktime(0,0,0,$t1['mon'],1,$t1['year']));

            $d['mday'] = $t2['mday'] + $dim -  $t1['mday'];
            $t1['mon'] += 1;
        }

        //months
        if ($t2['mon'] > $t1['mon']) {
            $d['mon'] = $t2['mon'] - $t1['mon'];
        }
        else {
            $d['mon'] = $t2['mon'] + 12 -  $t1['mon'];
            $t1['year'] += 1;
        }

        //years
        $d['year'] = $t2['year'] - $t1['year'];

        return array_reverse($d);
}

$input = array (
          '2004-04-15 00:00:00',
          '2008-05-31 00:00:00',
          '2007-12-15 00:00:00',
          '2006-05-31 00:00:00',
          '2007-04-15 00:00:00',
          '2006-06-01 00:00:00',
          '2010-04-15 00:00:00',
          '2006-09-31 00:00:00',
          '2007-02-01 00:00:00',
          '2008-08-08 00:00:00'
);

foreach($input as $dt) {
    $d = datediff($dt);

    foreach ($d as $k=>$v) echo "<b>$v</b> $k  ";
    echo '<br>';
}

$t2 = getmicrotime();
echo $t2-$t1;
?>[/code]

Share this post


Link to post
Share on other sites
Thanks alot :)

That works great, stupid of me not to think of the 'simple math' stuff ;)

Share this post


Link to post
Share on other sites
[!--quoteo(post=366019:date=Apr 18 2006, 04:40 PM:name=Jean M)--][div class=\'quotetop\']QUOTE(Jean M @ Apr 18 2006, 04:40 PM) [snapback]366019[/snapback][/div][div class=\'quotemain\'][!--quotec--]
Thanks alot :)

That works great, stupid of me not to think of the 'simple math' stuff ;)
[/quote]

Looking deeper into it it seems your technique is basicly the same as mine.
After implementing it it gave me the same slow parse time.

After commenting out other lines in the while loop I found the problem (but didn't solve it yet):
[code]
$aPlanInfo = mysql_fetch_assoc(mysql_query("SELECT term, type FROM plans WHERE id = " . $aMembersInfo['plan']));
[/code]

I have no clue why a simple query could slow the script down by almost 1 second. I [b]am[/b] testing this localy but I never had this kind of problem before? Could it be that me running the script localy might be causing the delay? Or should I look elsewhere for the problem?

Share this post


Link to post
Share on other sites
DON'T nest Mysql functions like that.

Every time you fetch a row you repeat the query!

Share this post


Link to post
Share on other sites
[!--quoteo(post=366121:date=Apr 18 2006, 08:58 PM:name=Barand)--][div class=\'quotetop\']QUOTE(Barand @ Apr 18 2006, 08:58 PM) [snapback]366121[/snapback][/div][div class=\'quotemain\'][!--quotec--]
DON'T nest Mysql functions like that.

Every time you fetch a row you repeat the query!
[/quote]

I understand that, but I dont see how else to get the right data for each user, right now I have this:
[code]
    $qMembersInfo = mysql_query("SELECT NOW() AS now, plans.unixtime, plans.id, membership.*
                                FROM membership, plans " . $sWhere . $sWherePlans . "
                                ORDER BY " . $sSortDatabase . " " . $_GET['sort'] . "
                                LIMIT " . $sStart . "," . $sEnd;


    // Parse selected members in the table.
    while($aMembersInfo = mysql_fetch_assoc($qMembersInfo)) {
        // Get plan info for member
        $aPlanInfo = mysql_fetch_assoc(mysql_query("SELECT term, type FROM plans WHERE id = " . $aMembersInfo['plan']));
    }
[/code]

I don't see another way to get the information I need from the selected user in the while loop...

Share this post


Link to post
Share on other sites
I notice the solutions where a bit too complicated for this problem

time() function in php will return the number of seconds, so if you have two times and subtract them, you'll get the difference in seconds. All you have to do is convert that into minutes, hours, days, etc...

I wrote a small function that will do that

[code]function convert_time($seconds){
    $f_minutes = $seconds / 60;
    $i_minutes = floor($f_minutes);
    $r_seconds = intval(($f_minutes - $i_minutes) * 60);
    
    $f_hours = $i_minutes / 60;
    $i_hours = floor($f_hours);
    $r_minutes = intval(($f_hours  - $i_hours) * 60);
    
    $f_days = $i_hours / 24;
    $i_days = floor($f_days);
    $r_hours = intval(($f_days - $i_days) * 24);
    
    if ($i_days > 0) $r = "$i_days days ";
    if ($r_hours > 0) $r .= "$r_hours hours ";
    if ($r_minutes > 0) $r .= "$r_minutes min";
    else $r = "less than a minute";
    
    return $r;
}[/code]

the f_ is for float i_ is for int and r_ is the return value. I only need days, so you can keep going for months and years the same way.

Good luck,

Wesam Saif
[a href=\"http://www.nogray.com\" target=\"_blank\"]http://www.nogray.com[/a]

Share this post


Link to post
Share on other sites
Hi,

I was playing with the convert_seconds function and found that a value of 46800 to 46859 (13 hours to 13 hours 59 seconds) returns "less than a minute".

values above 46859 and values below 46800 return the correct time.

This is the only range that I have found and I havent found out why its doing this yet.

Does anyone else have this issue?
Does anyone see where the problem is?

I am using PHP ver. 4.4.2


Thanks

Ray...

Share this post


Link to post
Share on other sites
I just checked this using the following and there are quite a few values that return less than a minute.

[code=php:0]
function convert_seconds($seconds){
    $f_minutes = $seconds / 60;
    $i_minutes = floor($f_minutes);
    $r_seconds = intval(($f_minutes - $i_minutes) * 60);
   
    $f_hours = $i_minutes / 60;
    $i_hours = floor($f_hours);
    $r_minutes = intval(($f_hours  - $i_hours) * 60);
   
    $f_days = $i_hours / 24;
    $i_days = floor($f_days);
    $r_hours = intval(($f_days - $i_days) * 24);
   
    if ($i_days > 0) $r = $i_days."d ";
    if ($r_hours > 0) $r .= $r_hours."h ";
    if ($r_minutes > 0) $r .= $r_minutes."m";
    else $r = "< a min";
   
    return $r;
}
$count = 30;
while($count < 1000000){
if(convert_seconds($count) == "< a min"){
echo  $count;
echo "<br />";
}
$count = $count + 60;
}
[/code]

Ray...

Share this post


Link to post
Share on other sites
I found it.

The else is only an else for the last if statement I just changed it to if $r is empty.

[code=php:0]
function convert_seconds($seconds){
    $f_minutes = $seconds / 60;
    $i_minutes = floor($f_minutes);
    $r_seconds = intval(($f_minutes - $i_minutes) * 60);
   
    $f_hours = $i_minutes / 60;
    $i_hours = floor($f_hours);
    $r_minutes = intval(($f_hours  - $i_hours) * 60);
   
    $f_days = $i_hours / 24;
    $i_days = floor($f_days);
    $r_hours = intval(($f_days - $i_days) * 24);
   
    if ($i_days > 0) $r = "$i_days days ";
    if ($r_hours > 0) $r .= "$r_hours hours ";
    if ($r_minutes > 0) $r .= "$r_minutes min";
    if ($r == '') $r = "less than a minute";
   
    return $r;
}
[/code]


Ray...

Share this post


Link to post
Share on other sites

×

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.