get the difference in time between two given time - php

I'm trying to get the difference in time between two given times e.g. first time '17:00:01' and then second time '17:47:25' and here's what I tried so far,
$start_time = "17:00:01";
$end_time = "17:47:25";
echo $start_time->diff($end_time);
But seem's unfortunately not working, any help, ideas please?
My expected output must be like, if no difference in hours but there's difference in minutes and seconds then, "22 mins and 15 secs", If no difference in minutes but have difference in hours then, "2 hrs and 10 secs" but if only seconds in difference then, "22 secs".

Get difference between two times
public function convTimeToMinutes($intime, $outtime)
{
$start = Carbon::parse($intime);
$end = Carbon::parse($outtime);
$minutes = $end->diffInMinutes($start); // 226
return $this->convertMinuteToHours($minutes);
}
public function convertMinuteToHours($minutes)
{
return $minutes / 60;
}
$totalHour = $this->convTimeToMinutes('09:25:35', '13:12:27');
//$totalHour = 3.76

String in php is not object, so can't call diff method on it.
Use diff method, you must change the string to DateTime object.
If you want to compare time difference in same day, you could try:
$start_time = "17:00:01";
$end_time = "17:47:25";
$start_datetime = new DateTime(date('Y-m-d').' '.$start_time);
$end_datetime = new DateTime(date('Y-m-d').' '.$end_time);
var_dump($start_datetime->diff($end_datetime));

Here is it.
PHP
$start_time = "17:00:01";
$end_time = "17:47:25";
$time1 = new DateTime($start_time);
$time2 = new DateTime($end_time);
$interval = $time1->diff($time2);
echo $hour = $interval->format('%h hour');
echo $min = $interval->format('%i min');
echo $sec = $interval->format('%s second');
Output:
0 hour 47 min 24 sec
Now you can add some condition and make the real format.

Just another way of doing it using string functions:
/*
* Get difference in seconds between time formats
*/
function getDiff($start_time, $end_time)
{
$start_time = timeFormatToSeconds($start_time);
$end_time = timeFormatToSeconds($end_time);
if ($end_time > $start_time) {
return $end_time - $start_time;
}
return false;
}
/*
* Convert time format (HH:MM:SS) to seconds
*/
function timeFormatToSeconds($time_format)
{
sscanf($time_format, "%d:%d:%d", $hours, $minutes, $seconds);
return $hours * 3600 + $minutes * 60 + $seconds;
}
$start_time = "17:00:01";
$end_time = "17:47:25";
$diff = getDiff($start_time, $end_time);
if ($diff) {
$hours = floor($time / (60 * 60));
$time -= $hours * (60 * 60);
$minutes = floor($time / 60);
$time -= $minutes * 60;
$seconds = floor($time);
$time -= $seconds;
var_dump(array($hours, $minutes, $seconds));
}

Convert string time to timestamp and subtract. Convert timestamp to desired time format.
$start_time = strtotime('17:00:01');
$end_time = strtotime('17:47:25');
$diff = $end_time - $start_time;
echo date('H:i:s', $diff);

You can do something like this as a generic function
private function calculateDiffInMinutes($from, $to)
{
$from = Carbon::createFromFormat('Y-m-d H:s:i', $from);
$to = Carbon::createFromFormat('Y-m-d H:s:i', $to);
return $to->diffInMinutes($from);
}
and you can call the function anywhere and pass the parameters you need
here the difference between now and created at time
$this->calculateDiffInMinutes($item->created_at, now())
Hope this helped

Related

round minute to closest 15 minute [duplicate]

I need to round times down to the nearest quarter hour in PHP. The times are being pulled from a MySQL database from a datetime column and formatted like 2010-03-18 10:50:00.
Example:
10:50 needs to be 10:45
1:12 needs to be 1:00
3:28 needs to be 3:15
etc.
I'm assuming floor() is involved but not sure how to go about it.
Thanks
$seconds = time();
$rounded_seconds = round($seconds / (15 * 60)) * (15 * 60);
echo "Original: " . date('H:i', $seconds) . "\n";
echo "Rounded: " . date('H:i', $rounded_seconds) . "\n";
This example gets the current time and rounds it to the nearest quarter and prints both the original and the rounded time.
PS: If you want to round it down replace round() with floor().
Your full function would be something like this...
function roundToQuarterHour($timestring) {
$minutes = date('i', strtotime($timestring));
return $minutes - ($minutes % 15);
}
$now = getdate();
$minutes = $now['minutes'] - $now['minutes']%15;
//Can add this to go to the nearest 15min interval (up or down)
$rmin = $now['minutes']%15;
if ($rmin > 7){
$minutes = $now['minutes'] + (15-$rmin);
}else{
$minutes = $now['minutes'] - $rmin;
}
$rounded = $now['hours'].":".$minutes;
echo $rounded;
To round nearest quarter hour use below code
<?php
$time = strtotime("01:08");
echo $time.'<br />';
$round = 15*60;
$rounded = round($time / $round) * $round;
echo date("H:i", $rounded);
?>
01:08 become 01:15
$minutes = ($minutes - ($minutes % 15));
Lately I like tackling a problem the TDD/unit testing way. I am not programming much PHP anymore lately, but this is what I came up with. To be honest I actually looked at the code examples here, and picked the one I thought was already correct. Next I wanted to verify this by unit testing using the tests you provided above.
class TimeTest
require_once 'PHPUnit/Framework.php';
require_once 'Time.php';
class TimeTest extends PHPUnit_Framework_TestCase
{
protected $time;
protected function setUp() {
$this->time = new Time(10, 50);
}
public function testConstructingTime() {
$this->assertEquals("10:50", $this->time->getTime());
$this->assertEquals("10", $this->time->getHours());
$this->assertEquals("50", $this->time->getMinutes());
}
public function testCreatingTimeFromString() {
$myTime = Time::create("10:50");
$this->assertEquals("10", $myTime->getHours());
$this->assertEquals("50", $myTime->getMinutes());
}
public function testComparingTimes() {
$timeEquals = new Time(10, 50);
$this->assertTrue($this->time->equals($timeEquals));
$timeNotEquals = new Time(10, 44);
$this->assertFalse($this->time->equals($timeNotEquals));
}
public function testRoundingTimes()
{
// Round test time.
$roundedTime = $this->time->round();
$this->assertEquals("10", $roundedTime->getHours());
$this->assertEquals("45", $roundedTime->getMinutes());
// Test some more times.
$timesToTest = array(
array(new Time(1,00), new Time(1,12)),
array(new Time(3,15), new Time(3,28)),
array(new Time(1,00), new Time(1,12)),
);
foreach($timesToTest as $timeToTest) {
$this->assertTrue($timeToTest[0]->equals($timeToTest[0]->round()));
}
}
}
class Time
<?php
class Time
{
private $hours;
private $minutes;
public static function create($timestr) {
$hours = date('g', strtotime($timestr));
$minutes = date('i', strtotime($timestr));
return new Time($hours, $minutes);
}
public function __construct($hours, $minutes) {
$this->hours = $hours;
$this->minutes = $minutes;
}
public function equals(Time $time) {
return $this->hours == $time->getHours() &&
$this->minutes == $time->getMinutes();
}
public function round() {
$roundedMinutes = $this->minutes - ($this->minutes % 15);
return new Time($this->hours, $roundedMinutes);
}
public function getTime() {
return $this->hours . ":" . $this->minutes;
}
public function getHours() {
return $this->hours;
}
public function getMinutes() {
return $this->minutes;
}
}
Running Test
alfred#alfred-laptop:~/htdocs/time$ phpunit TimeTest.php
PHPUnit 3.3.17 by Sebastian Bergmann.
....
Time: 0 seconds
OK (4 tests, 12 assertions)
I was surprised that nobody has mentioned the amazing Carbon library (often used in Laravel).
/**
*
* #param \Carbon\Carbon $now
* #param int $minutesChunk
* #return \Carbon\Carbon
*/
public static function getNearestTimeRoundedDown($now, $minutesChunk = 30) {
$newMinute = $now->minute - ($now->minute % $minutesChunk);
return $now->minute($newMinute)->startOfMinute(); //https://carbon.nesbot.com/docs/
}
Test cases:
public function testGetNearestTimeRoundedDown() {
$this->assertEquals('2018-07-06 14:00:00', TT::getNearestTimeRoundedDown(Carbon::parse('2018-07-06 14:12:59'))->format(TT::MYSQL_DATETIME_FORMAT));
$this->assertEquals('14:00:00', TT::getNearestTimeRoundedDown(Carbon::parse('2018-07-06 14:29:25'))->format(TT::HOUR_MIN_SEC_FORMAT));
$this->assertEquals('14:30:00', TT::getNearestTimeRoundedDown(Carbon::parse('2018-07-06 14:30:01'))->format(TT::HOUR_MIN_SEC_FORMAT));
$this->assertEquals('18:00:00', TT::getNearestTimeRoundedDown(Carbon::parse('2019-07-06 18:05:00'))->format(TT::HOUR_MIN_SEC_FORMAT));
$this->assertEquals('18:45:00', TT::getNearestTimeRoundedDown(Carbon::parse('2019-07-06 18:50:59'), 15)->format(TT::HOUR_MIN_SEC_FORMAT));
$this->assertEquals('18:45:00', TT::getNearestTimeRoundedDown(Carbon::parse('2019-07-06 18:49:59'), 15)->format(TT::HOUR_MIN_SEC_FORMAT));
$this->assertEquals('10:15:00', TT::getNearestTimeRoundedDown(Carbon::parse('1999-12-30 10:16:58'), 15)->format(TT::HOUR_MIN_SEC_FORMAT));
$this->assertEquals('10:10:00', TT::getNearestTimeRoundedDown(Carbon::parse('1999-12-30 10:16:58'), 10)->format(TT::HOUR_MIN_SEC_FORMAT));
}
It's an old question but having recently implemented myself I'll share my solution:-
public function roundToQuarterHour($datetime) {
$datetime = ($datetime instanceof DateTime) ? $datetime : new DateTime($datetime);
return $datetime->setTime($datetime->format('H'), ($i = $datetime->format('i')) - ($i % 15));
}
public function someQuarterHourEvent() {
print_r($this->roundToQuarterHour(new DateTime()));
print_r($this->roundToQuarterHour('2016-10-19 10:50:00'));
print_r($this->roundToQuarterHour('2016-10-19 13:12:00'));
print_r($this->roundToQuarterHour('2016-10-19 15:28:00'));
}
For my system I wanted to add jobs which are scheduled to run every 5th minute on my server, and I want the same job to run in the next 5th minute block, then 15, 30, 60, 120, 240 minutes, 1 day and 2 days after, so that's what this function calculates
function calculateJobTimes() {
$now = time();
IF($now %300) {
$lastTime = $now - ($now % 300);
}
ELSE {
$lastTime = $now;
}
$next[] = $lastTime + 300;
$next[] = $lastTime + 900;
$next[] = $lastTime + 1800;
$next[] = $lastTime + 3600;
$next[] = $lastTime + 7200;
$next[] = $lastTime + 14400;
$next[] = $lastTime + 86400;
$next[] = $lastTime + 172800;
return $next;
}
echo "The time now is ".date("Y-m-d H:i:s")."<br />
Jobs will be scheduled to run at the following times:<br /><br />
<ul>";
foreach(calculateJobTimes() as $jTime) {
echo "<li>".date("Y-m-d H:i:s", $jTime).'</li>';
}
echo '</ul>';
It's important you use a built-in PHP function for rounding times to take into account the date as well as the time. For example 2020-10-09 23:37:35 needs to become 2020-10-10 00:00:00 when rounding up to nearest hour.
Round time to nearest hour:
$time = '2020-10-09 23:37:35';
$time = date("Y-m-d H:i:s", round(strtotime($time) / 3600) * 3600); // 2020-10-10 00:00:00
$time = '2020-10-09 23:15:35';
$time = date("Y-m-d H:i:s", round(strtotime($time) / 3600) * 3600); // 2020-10-09 23:00:00
Round time down to nearest 15 minute increment:
$time = '2020-10-09 23:15:35';
$time = date("Y-m-d H:i:s", floor(strtotime($time) / (60*15))*(60*15)); // 2020-10-09 23:15:00
$time = '2020-10-09 23:41:35';
$time = date("Y-m-d H:i:s", floor(strtotime($time) / (60*15))*(60*15)); // 2020-10-09 23:30:00
If you need to round up to nearest 15 minute increment, change floor to ceil e.g
$time = date("Y-m-d H:i:s", ceil(strtotime($time) / (60*15))*(60*15)); // 2020-10-09 23:45:00
If you need to round time to another minute increment you can simply do:
$time = date("Y-m-d H:i:s", ceil(strtotime($time) / (60*20))*(60*20)); // 2020-10-10 00:00:00
I needed a way to round down to the day, and cut off everything beyond that:
$explodedDate = explode("T", gmdate("c",strtotime("now")));
$expireNowDate = date_create($explodedDate[0]);
The strtotime gives me a timestamp for "now", which gmdate converts to ISO format (something like "2012-06-05T04:00:00+00:00"), then I use explode at the "T", giving me "2012-06-05" in the zeroth index of $explodedDate, which is then passed into date_create to get a date object.
Not sure if all of that is necessary, but it seems like a lot less work than going through and subtracting the seconds, minutes, hours etc.
// time = '16:58'
// type = auto, up, down
function round_time( $time, $round_to_minutes = 5, $type = 'auto' ) {
$round = array( 'auto' => 'round', 'up' => 'ceil', 'down' => 'floor' );
$round = #$round[ $type ] ? $round[ $type ] : 'round';
$seconds = $round_to_minutes * 60;
return date( 'H:i', $round( strtotime( $time ) / $seconds ) * $seconds );
}
Simple solution:
$oldDate = "2010-03-18 10:50:00";
$date = date("Y-m-d H:i:s", floor(strtotime($oldDate) / 15 / 60) * 15 * 60);
You can change floor to ceil if you want to round up.
I wrote a function that does the trick to round time stamps to seconds or minutes.
I might not be the most performant way, but I think PHP doens't care about a few simple loops.
In your case, you just pass your MySQL datetime like this:
<?php echo date('d/m/Y - H:i:s', roundTime(strtotime($MysqlDateTime), 'i', 15)); ?>
Returns: the closests rounded value (looks both up and down!)
The function:
<?php
function roundTime($time, $entity = 'i', $value = 15){
// prevent big loops
if(strpos('is', $entity) === false){
return $time;
}
// up down counters
$loopsUp = $loopsDown = 0;
// loop up
$loop = $time;
while(date($entity, $loop) % $value != 0){
$loopsUp++;
$loop++;
}
$return = $loop;
// loop down
$loop = $time;
while(date($entity, $loop) % $value != 0){
$loopsDown++;
$loop--;
if($loopsDown > $loopsUp){
$loop = $return;
break;
}
}
$return = $loop;
// round seconds down
if($entity == 'i' && date('s', $return) != 0){
while(intval(date('s', $return)) != 0){
$return--;
}
}
return $return;
}
?>
You simple replace $entity by 's' if you want to round up or down to seconds and replace 15 by the amount of seconds or minutes you want to roud up or down to.
Here's a function I'm currently using:
/**
* Rounds a timestamp
*
* #param int $input current timestamp
* #param int $round_to_minutes rounds to this minute
* #param string $type auto, ceil, floor
* #return int rounded timestamp
*/
static function roundToClosestMinute($input = 0, $round_to_minutes = 5, $type = 'auto')
{
$now = !$input ? time() : (int)$input;
$seconds = $round_to_minutes * 60;
$floored = $seconds * floor($now / $seconds);
$ceiled = $seconds * ceil($now / $seconds);
switch ($type) {
default:
$rounded = ($now - $floored < $ceiled - $now) ? $floored : $ceiled;
break;
case 'ceil':
$rounded = $ceiled;
break;
case 'floor':
$rounded = $floored;
break;
}
return $rounded ? $rounded : $input;
}
Hope it helps someone :)
Might help others. For any language.
roundedMinutes = yourRoundFun(Minutes / interval) * interval.
E.g. The interval could be 5 minutes , 10 minutes, 15 minutes, 30 minutes.
Then rounded minutes can be reset to the respective date.
yourDateObj.setMinutes(0)
yourDateObj.setMinutes(roundedMinutes)
While it is typically most appropriate to use datetime-based functions to manipulate a datetime, the requirement of this task does not involve any special time-related treatment -- it is a simple task of executing a calculation on a specific substring and using the mathematical outcome to replace the substring.
Not everyone is a fan of regex, but it does provide a single-function technique to mutate the input string.
Code: (Demo)
$timeString = "2010-03-18 10:50:57";
// PHP7.4+ arrow syntax
echo preg_replace_callback(
'~:\K(\d{2}).*~',
fn($m) => $m[1] - $m[1] % 15 . ':00',
$timeString
);
echo "\n---\n";
// below PHP7.3
echo preg_replace_callback(
'~:\K(\d{2}).*~',
function($m) {return $m[1] - $m[1] % 15 . ':00';},
$timeString
);
Output:
2010-03-18 10:45:00
---
2010-03-18 10:45:00
Note, this regex pattern will work just as well if dealing with a time-only (colon-delimited) string. (Demo)
Or you could MySQL let do the work (for dates from 1970):
SELECT FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(date_col)/900)*900) FROM mytable;
Solved by one line code.
protected function roundToQuarterHour($timestring)
{
return Carbon::parse($timestring)->roundMinute(15);
}

PHP calculate between two time with H:i:s format

i'm trying to find and calculate between startime, finish time as: starttime + 1 hour and current time. if current time is between start and finish i must be print message such as please try after 1 hour:
$current_date_time = new DateTime("now", new DateTimeZone("Asia/Tehran"));
$user_current_time = $current_date_time->format("H:i:s");
$start_limit_time = date("H:i:s",strtotime('2015-09-15 14:57:31'));
$finish_limit_time = date('H:i:s', strtotime($start_limit_time) + (60 * 60 * 1));
$date1 = DateTime::createFromFormat('H:i:s', $user_current_time);
$date2 = DateTime::createFromFormat('H:i:s', $start_limit_time);
$date3 = DateTime::createFromFormat('H:i:s', $finish_limit_time);
if ($date1 > $date2 && $date1 < $date3)
{
echo 'here';
}
this code is not correct and i can not fix that,
You can try this, it shows the difference in minutes:
$current_date_time = new DateTime("now", new DateTimeZone("Asia/Tehran"));
$user_current_time = $current_date_time->format("H:i:s");
$start_limit_time = date("H:i:s",strtotime('2015-09-15 14:57:31'));
$finish_limit_time = date('H:i:s', strtotime($start_limit_time) + (60 * 60 * 1));
$date1 = DateTime::createFromFormat('H:i:s', $user_current_time);
$date2 = DateTime::createFromFormat('H:i:s', $start_limit_time);
$date3 = DateTime::createFromFormat('H:i:s', $finish_limit_time);
if ($date1 > $date2 && $date1 < $date3)
{
$tryAgainIn = $date3->diff( $date1 );
// just minutes
echo "try again in ".$tryAgainIn->format( "%i minutes" );
// or hours and minutes
$hours = $tryAgainIn->format('%h');
$minutes = $tryAgainIn->format('%i');
echo "try again in $hours hours and $minutes minutes";
}
For more information take a look at: DateTime::diff
At first you should avoid operating with strings format, as they should only be used IMHO to printing and retrieving data from outside. Use only timestamp or OOP methods.
I believe, that this is something you are looking for:
$startTime = new DateTime('2015-09-15 14:57:31');
$endTime = clone $startTime;
$endTime->modify('+1 hour');
if ($startTime->getTimestamp() <= time() && time() < $endTime->getTimestamp()) {
echo 'here';
}
I wonder why you need to use H:i:s format. Can you give some bigger picture?
Edit: Try this, as prior to now I did not fully understand what you want to do ;)
$origin = new DateTime('2015-09-15 14:57:31');
$startTime = new DateTime('today '.$origin->format('H:i:s'));
$endTime = clone $startTime;
$endTime->modify('+1 hour');
if ($startTime->getTimestamp() <= time() && time() < $endTime->getTimestamp()) {
echo 'here';
}

PHP - Find the difference between two times

I'm trying to calculate the time difference (in hours) between two times inputted via a timepicker. I have working JavaScript code, but would rather use server side code to make this calculation as it's quite important. If you want me to post the working JS code let me know in comments.
Calculating the difference between the times is easy enough, but I require the output in a particular format. For example inputs of '07:30' and '14:00' would return 6.5 rather than 6.3. The reason for this is to make it easier for me to use this time difference in calculations.
PHP Code i've tried:
Attempt #1:
<?php
$start_time = new DateTime('07:30');
$end_time = new DateTime('14:00');
$time_diff = date_diff($start_time,$end_time);
echo $time_diff->format('%h.%i');
?>
Returns 6.3 as expected.
Attempt #2:
<?php
$start_time = "07:30";
$end_time = "14:00";
$start_time = str_replace(":", "", $start_time);
$end_time = str_replace(":", "", $end_time);
$res = $end_time - $start_time;
$result = $res / 100;
echo $result;
?>
Returns 6.7.
Tool used to test output: http://codepad.viper-7.com/
Just extract the minutes:
<?php
$start_time = new DateTime('07:30');
$end_time = new DateTime('14:00');
$time_diff = date_diff($start_time,$end_time);
$hours = (int)$time_diff->format('%h');
$hour_part = ((int)$time_diff->format('%i')) / 60;
echo $hours + $hour_part;
?>
Make sure to change the type to (int) before any calculations.
If you divide the minutes by 60 you will get what part of a hour they represent.
<?php
$start_time = new DateTime('07:30');
$end_time = new DateTime('14:00');
$time_diff = date_diff($start_time,$end_time);
echo $time_diff->format('%h') + $time_diff->format('%i')/60;
?>
Returns 6.5 as expected.
You can try this:
<?php
$start_time = strtotime("07:30");
$end_time = strtotime("14:00");
$diff = $end_time - $start_time;
echo $diff;
1 hour = 60 min.
Demo.
$start_time = "07:30";
$end_time = "14:00";
list($h1, $m1) = explode(':', $start_time);
list($h2, $m2) = explode(':', $end_time);
// 1 hr = 60 min
$res = ($h2*60 - $m2) - ($h1*60 + $m1);
$result = floor($res/60) .'.'. $res % 60;
echo $result;
Try this
function time_difference($time1, $time2) {
$time1 = strtotime("1980-01-01 $time1");
$time2 = strtotime("1980-01-01 $time2");
if ($time2 < $time1) {
$time2 += 86400;
}
return date("H:i:s", strtotime("1980-01-01 00:00:00") + ($time2 - $time1));
}
echo time_difference("11:30:30", "22:40:59");
You can use this function to get the time difference between two times:
function timeBetween($start_date,$end_date)
{
$diff = $end_date-$start_date;
$seconds = 0;
$hours = 0;
$minutes = 0;
if($diff % 86400 <= 0){$days = $diff / 86400;} // 86,400 seconds in a day
if($diff % 86400 > 0)
{
$rest = ($diff % 86400);
$days = ($diff - $rest) / 86400;
if($rest % 3600 > 0)
{
$rest1 = ($rest % 3600);
$hours = ($rest - $rest1) / 3600;
if($rest1 % 60 > 0)
{
$rest2 = ($rest1 % 60);
$minutes = ($rest1 - $rest2) / 60;
$seconds = $rest2;
}
else{$minutes = $rest1 / 60;}
}
else{$hours = $rest / 3600;}
}
if($days > 0){$days = $days.' days, ';}
else{$days = false;}
if($hours > 0){$hours = $hours.' hours, ';}
else{$hours = false;}
if($minutes > 0){$minutes = $minutes.' minutes, ';}
else{$minutes = false;}
$seconds = $seconds.' seconds';
return $days.''.$hours.''.$minutes.''.$seconds;
}

calculate time duration considering the dates in PHP

How can I calculate time duration considering the datestamp in PHP? the date format I used in between dates is "Y-m-d H:i:s",
My working code can only compute the duration between time without considering the date.
below is my code:
$assigned_time = "2012-05-21 22:02:00";
$completed_time= "2012-05-22 05:02:00";
function hmsDiff ($assigned_time, $completed_time) {
$assigned_seconds = hmsToSeconds($assigned_time);
$completed_seconds = hmsToSeconds($completed_time);
$remaining_seconds = $assigned_seconds - $completed_seconds;
return secondsToHMS($remaining_seconds);
}
function hmsToSeconds ($hms) {
$total_seconds = 0;
list($hours, $minutes, $seconds) = explode(":", $hms);
$total_seconds += $hours * 60 * 60;
$total_seconds += $minutes * 60;
$total_seconds += $seconds;
return $total_seconds;
}
function secondsToHMS ($seconds) {
$minutes = (int)($seconds / 60);
$seconds = $seconds % 60;
$hours = (int)($minutes / 60);
$minutes = $minutes % 60;
return sprintf("%02d", abs($hours)) . ":" .
sprintf("%02d", abs($minutes)) . ":" .
sprintf("%02d", abs($seconds));
}
The DateTime has a "diff" method which returns an Interval object. The interval object has a method "format" which allows you to customize the output.
#!/usr/bin/env php
<?php
$assigned_time = "2012-05-21 22:02:00";
$completed_time= "2012-05-22 05:02:00";
$d1 = new DateTime($assigned_time);
$d2 = new DateTime($completed_time);
$interval = $d2->diff($d1);
echo $interval->format('%d days, %H hours, %I minutes, %S seconds');
NOTE: If you are not using 5.3.0+, there is a good answer here: https://stackoverflow.com/a/676828/128346.
Not completely knowing what you want, what about something like:
// prevents php error
date_default_timezone_set ( 'US/Eastern' );
// convert to time in seconds
$assigned_seconds = strtotime ( $assigned_time );
$completed_seconds = strtotime ( $completed_time );
$duration = $completed_seconds - $assigned_seconds;
// j gives days
$time = date ( 'j g:i:s', $duration );

Round minute down to nearest quarter hour

I need to round times down to the nearest quarter hour in PHP. The times are being pulled from a MySQL database from a datetime column and formatted like 2010-03-18 10:50:00.
Example:
10:50 needs to be 10:45
1:12 needs to be 1:00
3:28 needs to be 3:15
etc.
I'm assuming floor() is involved but not sure how to go about it.
Thanks
$seconds = time();
$rounded_seconds = round($seconds / (15 * 60)) * (15 * 60);
echo "Original: " . date('H:i', $seconds) . "\n";
echo "Rounded: " . date('H:i', $rounded_seconds) . "\n";
This example gets the current time and rounds it to the nearest quarter and prints both the original and the rounded time.
PS: If you want to round it down replace round() with floor().
Your full function would be something like this...
function roundToQuarterHour($timestring) {
$minutes = date('i', strtotime($timestring));
return $minutes - ($minutes % 15);
}
$now = getdate();
$minutes = $now['minutes'] - $now['minutes']%15;
//Can add this to go to the nearest 15min interval (up or down)
$rmin = $now['minutes']%15;
if ($rmin > 7){
$minutes = $now['minutes'] + (15-$rmin);
}else{
$minutes = $now['minutes'] - $rmin;
}
$rounded = $now['hours'].":".$minutes;
echo $rounded;
To round nearest quarter hour use below code
<?php
$time = strtotime("01:08");
echo $time.'<br />';
$round = 15*60;
$rounded = round($time / $round) * $round;
echo date("H:i", $rounded);
?>
01:08 become 01:15
$minutes = ($minutes - ($minutes % 15));
Lately I like tackling a problem the TDD/unit testing way. I am not programming much PHP anymore lately, but this is what I came up with. To be honest I actually looked at the code examples here, and picked the one I thought was already correct. Next I wanted to verify this by unit testing using the tests you provided above.
class TimeTest
require_once 'PHPUnit/Framework.php';
require_once 'Time.php';
class TimeTest extends PHPUnit_Framework_TestCase
{
protected $time;
protected function setUp() {
$this->time = new Time(10, 50);
}
public function testConstructingTime() {
$this->assertEquals("10:50", $this->time->getTime());
$this->assertEquals("10", $this->time->getHours());
$this->assertEquals("50", $this->time->getMinutes());
}
public function testCreatingTimeFromString() {
$myTime = Time::create("10:50");
$this->assertEquals("10", $myTime->getHours());
$this->assertEquals("50", $myTime->getMinutes());
}
public function testComparingTimes() {
$timeEquals = new Time(10, 50);
$this->assertTrue($this->time->equals($timeEquals));
$timeNotEquals = new Time(10, 44);
$this->assertFalse($this->time->equals($timeNotEquals));
}
public function testRoundingTimes()
{
// Round test time.
$roundedTime = $this->time->round();
$this->assertEquals("10", $roundedTime->getHours());
$this->assertEquals("45", $roundedTime->getMinutes());
// Test some more times.
$timesToTest = array(
array(new Time(1,00), new Time(1,12)),
array(new Time(3,15), new Time(3,28)),
array(new Time(1,00), new Time(1,12)),
);
foreach($timesToTest as $timeToTest) {
$this->assertTrue($timeToTest[0]->equals($timeToTest[0]->round()));
}
}
}
class Time
<?php
class Time
{
private $hours;
private $minutes;
public static function create($timestr) {
$hours = date('g', strtotime($timestr));
$minutes = date('i', strtotime($timestr));
return new Time($hours, $minutes);
}
public function __construct($hours, $minutes) {
$this->hours = $hours;
$this->minutes = $minutes;
}
public function equals(Time $time) {
return $this->hours == $time->getHours() &&
$this->minutes == $time->getMinutes();
}
public function round() {
$roundedMinutes = $this->minutes - ($this->minutes % 15);
return new Time($this->hours, $roundedMinutes);
}
public function getTime() {
return $this->hours . ":" . $this->minutes;
}
public function getHours() {
return $this->hours;
}
public function getMinutes() {
return $this->minutes;
}
}
Running Test
alfred#alfred-laptop:~/htdocs/time$ phpunit TimeTest.php
PHPUnit 3.3.17 by Sebastian Bergmann.
....
Time: 0 seconds
OK (4 tests, 12 assertions)
I was surprised that nobody has mentioned the amazing Carbon library (often used in Laravel).
/**
*
* #param \Carbon\Carbon $now
* #param int $minutesChunk
* #return \Carbon\Carbon
*/
public static function getNearestTimeRoundedDown($now, $minutesChunk = 30) {
$newMinute = $now->minute - ($now->minute % $minutesChunk);
return $now->minute($newMinute)->startOfMinute(); //https://carbon.nesbot.com/docs/
}
Test cases:
public function testGetNearestTimeRoundedDown() {
$this->assertEquals('2018-07-06 14:00:00', TT::getNearestTimeRoundedDown(Carbon::parse('2018-07-06 14:12:59'))->format(TT::MYSQL_DATETIME_FORMAT));
$this->assertEquals('14:00:00', TT::getNearestTimeRoundedDown(Carbon::parse('2018-07-06 14:29:25'))->format(TT::HOUR_MIN_SEC_FORMAT));
$this->assertEquals('14:30:00', TT::getNearestTimeRoundedDown(Carbon::parse('2018-07-06 14:30:01'))->format(TT::HOUR_MIN_SEC_FORMAT));
$this->assertEquals('18:00:00', TT::getNearestTimeRoundedDown(Carbon::parse('2019-07-06 18:05:00'))->format(TT::HOUR_MIN_SEC_FORMAT));
$this->assertEquals('18:45:00', TT::getNearestTimeRoundedDown(Carbon::parse('2019-07-06 18:50:59'), 15)->format(TT::HOUR_MIN_SEC_FORMAT));
$this->assertEquals('18:45:00', TT::getNearestTimeRoundedDown(Carbon::parse('2019-07-06 18:49:59'), 15)->format(TT::HOUR_MIN_SEC_FORMAT));
$this->assertEquals('10:15:00', TT::getNearestTimeRoundedDown(Carbon::parse('1999-12-30 10:16:58'), 15)->format(TT::HOUR_MIN_SEC_FORMAT));
$this->assertEquals('10:10:00', TT::getNearestTimeRoundedDown(Carbon::parse('1999-12-30 10:16:58'), 10)->format(TT::HOUR_MIN_SEC_FORMAT));
}
It's an old question but having recently implemented myself I'll share my solution:-
public function roundToQuarterHour($datetime) {
$datetime = ($datetime instanceof DateTime) ? $datetime : new DateTime($datetime);
return $datetime->setTime($datetime->format('H'), ($i = $datetime->format('i')) - ($i % 15));
}
public function someQuarterHourEvent() {
print_r($this->roundToQuarterHour(new DateTime()));
print_r($this->roundToQuarterHour('2016-10-19 10:50:00'));
print_r($this->roundToQuarterHour('2016-10-19 13:12:00'));
print_r($this->roundToQuarterHour('2016-10-19 15:28:00'));
}
For my system I wanted to add jobs which are scheduled to run every 5th minute on my server, and I want the same job to run in the next 5th minute block, then 15, 30, 60, 120, 240 minutes, 1 day and 2 days after, so that's what this function calculates
function calculateJobTimes() {
$now = time();
IF($now %300) {
$lastTime = $now - ($now % 300);
}
ELSE {
$lastTime = $now;
}
$next[] = $lastTime + 300;
$next[] = $lastTime + 900;
$next[] = $lastTime + 1800;
$next[] = $lastTime + 3600;
$next[] = $lastTime + 7200;
$next[] = $lastTime + 14400;
$next[] = $lastTime + 86400;
$next[] = $lastTime + 172800;
return $next;
}
echo "The time now is ".date("Y-m-d H:i:s")."<br />
Jobs will be scheduled to run at the following times:<br /><br />
<ul>";
foreach(calculateJobTimes() as $jTime) {
echo "<li>".date("Y-m-d H:i:s", $jTime).'</li>';
}
echo '</ul>';
It's important you use a built-in PHP function for rounding times to take into account the date as well as the time. For example 2020-10-09 23:37:35 needs to become 2020-10-10 00:00:00 when rounding up to nearest hour.
Round time to nearest hour:
$time = '2020-10-09 23:37:35';
$time = date("Y-m-d H:i:s", round(strtotime($time) / 3600) * 3600); // 2020-10-10 00:00:00
$time = '2020-10-09 23:15:35';
$time = date("Y-m-d H:i:s", round(strtotime($time) / 3600) * 3600); // 2020-10-09 23:00:00
Round time down to nearest 15 minute increment:
$time = '2020-10-09 23:15:35';
$time = date("Y-m-d H:i:s", floor(strtotime($time) / (60*15))*(60*15)); // 2020-10-09 23:15:00
$time = '2020-10-09 23:41:35';
$time = date("Y-m-d H:i:s", floor(strtotime($time) / (60*15))*(60*15)); // 2020-10-09 23:30:00
If you need to round up to nearest 15 minute increment, change floor to ceil e.g
$time = date("Y-m-d H:i:s", ceil(strtotime($time) / (60*15))*(60*15)); // 2020-10-09 23:45:00
If you need to round time to another minute increment you can simply do:
$time = date("Y-m-d H:i:s", ceil(strtotime($time) / (60*20))*(60*20)); // 2020-10-10 00:00:00
I needed a way to round down to the day, and cut off everything beyond that:
$explodedDate = explode("T", gmdate("c",strtotime("now")));
$expireNowDate = date_create($explodedDate[0]);
The strtotime gives me a timestamp for "now", which gmdate converts to ISO format (something like "2012-06-05T04:00:00+00:00"), then I use explode at the "T", giving me "2012-06-05" in the zeroth index of $explodedDate, which is then passed into date_create to get a date object.
Not sure if all of that is necessary, but it seems like a lot less work than going through and subtracting the seconds, minutes, hours etc.
// time = '16:58'
// type = auto, up, down
function round_time( $time, $round_to_minutes = 5, $type = 'auto' ) {
$round = array( 'auto' => 'round', 'up' => 'ceil', 'down' => 'floor' );
$round = #$round[ $type ] ? $round[ $type ] : 'round';
$seconds = $round_to_minutes * 60;
return date( 'H:i', $round( strtotime( $time ) / $seconds ) * $seconds );
}
Simple solution:
$oldDate = "2010-03-18 10:50:00";
$date = date("Y-m-d H:i:s", floor(strtotime($oldDate) / 15 / 60) * 15 * 60);
You can change floor to ceil if you want to round up.
I wrote a function that does the trick to round time stamps to seconds or minutes.
I might not be the most performant way, but I think PHP doens't care about a few simple loops.
In your case, you just pass your MySQL datetime like this:
<?php echo date('d/m/Y - H:i:s', roundTime(strtotime($MysqlDateTime), 'i', 15)); ?>
Returns: the closests rounded value (looks both up and down!)
The function:
<?php
function roundTime($time, $entity = 'i', $value = 15){
// prevent big loops
if(strpos('is', $entity) === false){
return $time;
}
// up down counters
$loopsUp = $loopsDown = 0;
// loop up
$loop = $time;
while(date($entity, $loop) % $value != 0){
$loopsUp++;
$loop++;
}
$return = $loop;
// loop down
$loop = $time;
while(date($entity, $loop) % $value != 0){
$loopsDown++;
$loop--;
if($loopsDown > $loopsUp){
$loop = $return;
break;
}
}
$return = $loop;
// round seconds down
if($entity == 'i' && date('s', $return) != 0){
while(intval(date('s', $return)) != 0){
$return--;
}
}
return $return;
}
?>
You simple replace $entity by 's' if you want to round up or down to seconds and replace 15 by the amount of seconds or minutes you want to roud up or down to.
Here's a function I'm currently using:
/**
* Rounds a timestamp
*
* #param int $input current timestamp
* #param int $round_to_minutes rounds to this minute
* #param string $type auto, ceil, floor
* #return int rounded timestamp
*/
static function roundToClosestMinute($input = 0, $round_to_minutes = 5, $type = 'auto')
{
$now = !$input ? time() : (int)$input;
$seconds = $round_to_minutes * 60;
$floored = $seconds * floor($now / $seconds);
$ceiled = $seconds * ceil($now / $seconds);
switch ($type) {
default:
$rounded = ($now - $floored < $ceiled - $now) ? $floored : $ceiled;
break;
case 'ceil':
$rounded = $ceiled;
break;
case 'floor':
$rounded = $floored;
break;
}
return $rounded ? $rounded : $input;
}
Hope it helps someone :)
Might help others. For any language.
roundedMinutes = yourRoundFun(Minutes / interval) * interval.
E.g. The interval could be 5 minutes , 10 minutes, 15 minutes, 30 minutes.
Then rounded minutes can be reset to the respective date.
yourDateObj.setMinutes(0)
yourDateObj.setMinutes(roundedMinutes)
While it is typically most appropriate to use datetime-based functions to manipulate a datetime, the requirement of this task does not involve any special time-related treatment -- it is a simple task of executing a calculation on a specific substring and using the mathematical outcome to replace the substring.
Not everyone is a fan of regex, but it does provide a single-function technique to mutate the input string.
Code: (Demo)
$timeString = "2010-03-18 10:50:57";
// PHP7.4+ arrow syntax
echo preg_replace_callback(
'~:\K(\d{2}).*~',
fn($m) => $m[1] - $m[1] % 15 . ':00',
$timeString
);
echo "\n---\n";
// below PHP7.3
echo preg_replace_callback(
'~:\K(\d{2}).*~',
function($m) {return $m[1] - $m[1] % 15 . ':00';},
$timeString
);
Output:
2010-03-18 10:45:00
---
2010-03-18 10:45:00
Note, this regex pattern will work just as well if dealing with a time-only (colon-delimited) string. (Demo)
Or you could MySQL let do the work (for dates from 1970):
SELECT FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(date_col)/900)*900) FROM mytable;
Solved by one line code.
protected function roundToQuarterHour($timestring)
{
return Carbon::parse($timestring)->roundMinute(15);
}

Categories