I've seen various posts asking how to subtract a specific number of hours, days, etc from a DateTime - but my question is a bit different.
Say I have a user log in, and the system records the date/time. Every second, a timer increases based on the difference between the current date/time and the recorded date/time - effectively creating a log-in timer. Then, the user decides to pause the timer, so the system records pause start and pause end (for when they resume). What I would like to do is make the displayed time subtracted by the pause time - such that the timer doesn't 'increase' while paused. Because I'm not using an actual counter adding up every second, in which case I could just not count up during lunch, I am unaware how to calculate the proper value on the timer.
Here is the code on displaying the timer (part of incriment.php):
date_default_timezone_set('America/Chicago');
$date = new DateTime(date('m/d/Y H:i'));
$date2 = new DateTime(date($_SESSION['date_in'] . ' ' .
$_SESSION['time_in']));
$interval = $date->diff($date2);
$interval = $interval->format('%H:%I');
$_SESSION['current_timer'] = $interval;
echo $_SESSION['current_timer'];
And here is the code on being paused
if(isset($_SESSION['paused']) && $_SESSION['paused'] === true) {
echo '<div class="info">';
echo '<img src="images/information-button" style="max-width:3em">';
if(isset($_SESSION['pause_start'])) {
date_default_timezone_set('America/Chicago');
if(isset($_SESSION['pause_end'])) {
$time = $_SESSION['pause_end']->diff($_SESSION['pause_start']);
echo '<br>Current pause time: ' . $time->format('%H:%I');
} else {
$time = new DateTime(date('H:i'));
$time = $time->diff(new DateTime($_SESSION['date_pause_start'] . ' ' . $_SESSION['pause_start']));
$_SESSION['pause_timer'] = $time->format('%h hours, %i minutes');
echo '<br>Pause timer: ' . $time->format('%h hours, %i minutes');
}
echo '</div>';
}
}
TLDR; How can I subtract a DateTime by an object returned by diff when I don't know if that diff will return minutes (say 30 minutes) or hours (say 1 hour, 30 minutes). I can't do this as a result of not knowing that, nor can I do something like $date->modify("+30 minutes") because I don't know if it's minutes or hours or what. I feel like it should be easy because in my lunch calculations, $time is displaying the time paused (ex: 30 minutes) and by using that into a string I could use the$date->modify strategy - but that's not working (See below what I tried in my incriment.php I showed earlier)
$interval = $interval->format('H:i');
if(isset($_SESSION['pause_timer'])) {
$interval = new DateTime(date($interval));
$interval = $interval->modify("-". $_SESSION['pause_timer']);
echo '-' . $_SESSION['pause_timer'];
}
But that echo's out -0 hours, 40 minutes if the user was paused for 40 minutes - and changes the time from 01:48 to 14:18 which is really confusing as it should be 1:08 obviously. That means to me that I'm improperly using the DateTime for my situation, is there a better solution
Thank you!
Edit: The user can only pause once per session for simplicities sake
I appreciate the replies in comments [even those they deleted ;) ], I managed to get it working by changing the paused code at the $_SESSION['pause_timer'] = $time->format('%h hours, %i minutes') into $_SESSION['pause_timer'] = $time->format('-%h hours, -%i minutes'). My problem was that I was subtracting only the hours, so when my time was only in minutes it added the minutes and subtracted the 0 hours!
Related
So I have a php session timer that works but somehow gets bugged out after awhile... this is the code and the console log I got. I'm looking for a fix to this problem, or possibly a different set of code to achieve the same timer effect (as I'm not sure if using session is the best method for a timer)
session_start();
function timer($time) {
//Set the countdown to 120 seconds.
$_SESSION['countdown'] = $time*60;
//Store the timestamp of when the countdown began.
$_SESSION['time_started'] = time();
$now = time();
$timeSince = $now - $_SESSION['time_started'];
$remainingSeconds = abs($_SESSION['countdown'] - $timeSince);
$counter = 0;
$minutes = $remainingSeconds/60;
echo "$minutes minutes countdown starts.".PHP_EOL;
while($remainingSeconds >= 1) {
$now = time();
$timeSince = $now - $_SESSION['time_started'];
if (($timeSince-$counter) >= 60) {
$remainingSeconds = abs($_SESSION['countdown'] - $timeSince);
$counter = $timeSince;
$minutes = $remainingSeconds/60;
echo "$minutes minutes has passed.".PHP_EOL;
}
}
if($remainingSeconds < 1){
session_abort();
return true;
}
}
if($this->timer(30)) {
// do whatever
echo "$time has passed";
}
Here's what happens in the console:
30 minutes countdown starts.
29 minutes has passed.
.... (continue as per pattern)
16 minutes has passed.
15 minutes has passed. (problem occurs here)
8.7166666666667 minutes has passed.
7.7166666666667 minutes has passed.
6.7166666666667 minutes has passed.
.... (continue as per pattern)
0.71666666666667 minutes has passed.
0.28333333333333 minutes has passed.
1.2833333333333 minutes has passed.
2.2833333333333 minutes has passed.
.... (continue as per pattern all the way)
Extra notes: The session timer doesn't always recur this same pattern, there have been times when it ran through the entire 30minutes and managed to echo "$time has passed"; while the bug only occured later on
I haven't run your, but just from reading it I think there are a few things very wrong with it.
Sessions. You're not using them right.
Session values should only be set once, meaning before you do $_SESSION['countdown'] = $time*60; and $_SESSION['time_started'] = time();, you should check if they already exist or not, and only assign if nonexistent. Your current code resets the clock every time the page is refreshed, which defeats the purpose of sessions.
abs. I think you're not using them right either.
You shouldn't abs the remaining seconds all the time. $remainingSeconds = abs($_SESSION['countdown'] - $timeSince); should be allowed to go into negative. Negative remaining seconds mean your timeout has expired / you've missed it! Calling abs means you're effectively letting it go forever if you by any chance miss the exact time of your event. This is the answer to your main problem. Fix this and your counter will stop going to zero and back up again.
You're relying on your code correctly checking every single second. But it doesn't.
The nasty decimals you're getting happen when for some reason your code gets delayed and doesn't correctly check the 60th second, which means your division by 60 is not perfectly round and you get 8.7166666 minutes.
If you start by removing the abs calls and generally try to simplify your code a bit, I believe you'll quickly get it to work as intended.
// Edit 1
This is a very naive, but simplified approach to your problem. I left two different outputs in there for you to pick one.
function timer($time) {
echo "$time minutes countdown starts." . PHP_EOL;
// Save the date in future when the timer should stop
$endTime = time() + $time * 60;
// Keeps track of last full minute to simplify logs
$lastFullMinute = $time;
while(true) {
$timeRemaining = $endTime - time();
if ($timeRemaining <= 0) {
// Time remaining is less than zero, which means we've gone beyond the end date.
// End the loop
return;
}
// Round up!
$minutesRemaining = ceil($timeRemaining / 60);
if ($minutesRemaining != $lastFullMinute) {
// Current "minute" is different than the previous one, so display a nice message
// If you want to show how many minutes are remainig, use this:
echo "$minutesRemaining minutes remaining." . PHP_EOL;
// If you want to show how many minutes have passed, you have to take mintutesRemaining away from the original time
$minutesPassed = $time - $minutesRemaining;
echo "$minutesPassed minutes passed." . PHP_EOL;
$lastFullMinute = $minutesRemaining;
}
}
}
The main way for you to improve it further would be to use the sleep function http://php.net/manual/en/function.sleep.php. Currently the while loop will hog all the CPU by constantly checking if the timer happened, so you should sleep for a few seconds inside.
What do you think of this solution? referenced from above
function timer($time) {
echo "$time minutes countdown starts." . PHP_EOL;
// Save the date in future when the timer should stop
$endTime = time() + $time*60;
while(true) {
sleep(20);
$secondsRemaining = $endTime - time();
if ($secondsRemaining <= 0) {
echo 'Finished';
return true;
}
}
}
Is it possible to check current DateTime and future DateTime in every 30 seconds until difference becomes 0 ( current DateTime to be equal to the future DateTime ) with precision of a minute using PHP ?
My code is not continuously in every 30 seconds:
<?php
$dt_format = 'Y-m-d H:i';
$new_row = "<br>";
$dt_now = new DateTime();
$date1 = DateTime::createFromFormat($dt_format, '2016-09-01 14:00');
$date2 = DateTime::createFromFormat($dt_format, '2016-09-01 14:15');
print("Today is " . $dt_now->format($dt_format) . $new_row);
$diff1 = $dt_now->diff($date1);
print ($diff1->format('%y years %m months %d days %h hours %i minutes') . $new_row);
$diff2 = $dt_now->diff($date2);
print ($diff2->format('%y years %m months %d days %h hours %i minutes') . $new_row);
?>
Do you want to block the page load into the time matches? That will lead to resource exhaustion on your server if the target time is too long.
PHP is single threaded so you can't do this check in the background.
Better to write out a holding page for the user, which tries to reload every 30 seconds.
If the time is reached, show the content, otherwise show a page with this content:
<p>Please wait until (put target time)</p>
<script>
setTimeout(function() {
window.location.reload();
}, 30000);
</script>
I'm getting a list of items from my database, each has a CURRENT_TIMESTAMP which i have changed into 'x minutes ago' with the help of timeago. So that's working fine. But the problem is i also want a "NEW" banner on items which are less than 30 minutes old. How can i take the generated timestamp (for example: 2012-07-18 21:11:12) and say if it's less than 30 minutes from the current time, then echo the "NEW" banner on that item.
Use strtotime("-30 minutes") and then see if your row's timestamp is greater than that.
Example:
<?php
if(strtotime($mysql_timestamp) > strtotime("-30 minutes")) {
$this_is_new = true;
}
?>
I'm using strtotime() twice here to get unix timestamps for your mysql date, and then again to get what the timestamp was 30 minutes ago. If the timestamp from 30 mins ago is greater than the timestamp of the mysql record, then it must have been created more than 30 minutes go.
Try something like this, using PHP's DateTime object:
$now = new DateTime();
$then = DateTime($timestamp); // "2012-07-18 21:11:12" for example
$diff = $now->diff($then);
$minutes = ($diff->format('%a') * 1440) + // total days converted to minutes
($diff->format('%h') * 60) + // hours converted to minutes
$diff->format('%i'); // minutes
if ($minutes <= 30) {
echo "NEW";
}
Edit: Mike is right, I forgot that for whatever reason, only %a actually returns the total of its type (in this case days). All the others are for displaying time formatting. I've extended the above to actually work.
You can do like this also -
$currentTime=time();
to check the last updated time is 30 minute old or not
last_updated_at < $currentTime - (60*30)
I wrote the following code to determine the amount of time that employees spend on a task:
$time1 = $row_TicketRS['OpenTime'];
$time2= $row_TicketRS['CloseTime'];
$t1=strtotime($time1);
$t2=strtotime($time2);
$end=strtotime(143000); //143000 is reference to 14:30
//$Hours =floor((($t2 - $t1)/60)/60);
$Hours = floor((($end- $t1)/60)/60);
echo $Hours.' Hours ';
The above code is not giving me the correct time.
For example, with a start time of 09:19:00 and end time of 11:01:00 it give me duration time of only 1 hour which is wrong. What is the correct way?
Your use of floor is why you are getting only 1 hour for those inputs. Those inputs result in 1.7 hours if you keep the answer as a float. floor automatically rounds down to the lower integer value. Check out http://php.net/manual/en/function.floor.php for more info.
$t1 = strtotime('09:19:00');
$t2 = strtotime('11:01:00');
$hours = ($t2 - $t1)/3600; //$hours = 1.7
If you want a more fine-grained time difference, you can flesh it out...
echo floor($hours) . ':' . ( ($hours-floor($hours)) * 60 ); // Outputs "1:42"
UPDATE:
I just noted your comments on Long Ears' answer. Please check my comments above again, they are correct. Inputting values of '09:11:00' and '09:33:00' results in 0 hours (22 minutes).
If you input those values and got 4 hours, you likely have a decimal error in your math. Using '09:11' to '09:33', the result is .367 hours. If you divided the strtotime results by 360 instead of by 3600, you would get result 3.67 hours (or 4 hours, depending on your rounding method).
strtotime converts your time to an int value representing number of seconds since Unix epoch. Since you convert both values to seconds, and then subtract the values from each other, the resulting value is a quantity of seconds. There are 3600 seconds in 1 hour.
After changing strtotime('14:30:00') everything working fine.. see below
$time1 = '09:19:00';
$time2= '11:01:00';
echo "Time1:".$t1=strtotime($time1);
echo "<br/>Time2:".$t2=strtotime($time2);
echo "<br/>End:".$end=strtotime('14:30:00');
echo "<br/>Floor value:";
var_dump(floor((($end- $t1)/60)/60));
//$Hours =floor((($t2 - $t1)/60)/60);
$Hours = floor((($end- $t1)/60)/60);
echo $Hours.' Hours ';
function getTimeDiff($dtime,$atime)
{
$nextDay=$dtime>$atime?1:0;
$dep=explode(':',$dtime);
$arr=explode(':',$atime);
$diff=abs(mktime($dep[0],$dep[1],0,date('n'),date('j'),date('y'))-mktime($arr[0],$arr[1],0,date('n'),date('j')+$nextDay,date('y')));
//Hour
$hours=floor($diff/(60*60));
//Minute
$mins=floor(($diff-($hours*60*60))/(60));
//Second
$secs=floor(($diff-(($hours*60*60)+($mins*60))));
if(strlen($hours)<2)
{
$hours="0".$hours;
}
if(strlen($mins)<2)
{
$mins="0".$mins;
}
if(strlen($secs)<2)
{
$secs="0".$secs;
}
return $hours.':'.$mins.':'.$secs;
}
echo getTimeDiff("23:30","01:30");
A better way is to use http://php.net/manual/en/datetime.diff.php
$start_t = new DateTime($start_time);
$current_t = new DateTime($current_time);
$difference = $start_t ->diff($current_t );
$return_time = $difference ->format('%H:%I:%S');
for example the start time is 09:19:00 and end time is 11:01:00 but it give me duration time only 1 hour which is wrong
You are calculating the difference in hours. what is the correct result for "start time is 09:19:00 and end time is 11:01:00"
You need strtotime('14:30') rather than strtotime(143000)
Edit: Actually to my surprise, strtotime(143000) does seem to have the desired effect but only for double-digit hours so I still wouldn't rely on it. Anyway it's not the cause of your problem ;)
You can use $hour = ($end - $t1)/(60*60)
In this the time format is (seconds*minutes*days*months*years) => (60*60*2)
Suppose the target time is 4.30 pm and the current time is 3.25 pm , how will i calculate the minutes remaining to reach the target time ? I need the result in minutes.
session_start();
$m=30;
//unset($_SESSION['starttime']);
if(!$_SESSION['starttime']){
$_SESSION['starttime']=date('Y-m-d h:i:s');
}
$stime=strtotime($_SESSION['starttime']);
$ttime=strtotime((date('Y-m-d h:i:s',strtotime("+$m minutes"))));-->Here I want to calcuate the target time; the time is session + 30 minutes. How will i do that
echo round(abs($ttime-$stime)/60);
Krishnik
A quick calculation of the difference between two times can be done like this:
$start = strtotime("4:30");
$stop = strtotime("6:30");
$diff = ($stop - $start); //Diff in seconds
echo $diff/3600; //Return 2 hours. Divide by something else to get in mins etc.
Edit*
Might as well add the answer to your problem too:
$start = strtotime("3:25");
$stop = strtotime("4:30");
$diff = ($stop - $start);
echo $diff/60; //Echoes 65 min
Oh and one more edit:) If the times are diffent dates, like start is 23:45 one day and end is 0:30 the next you need to add a date too to the strtotime.