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);
}
Related
I want to get the difference in two times that are in hh:mm format. I am using this function
<?php
function timeDiff($firstTime,$lastTime) {
$firstTime=strtotime($firstTime);
$lastTime=strtotime($lastTime);
$timeDiff=$lastTime-$firstTime;
return $timeDiff;
}
echo (timeDiff("10:00","20:00")/60)/60;
?>
The issue is that it works perfectly if I have hours less than 24. But I need it to work for upto 60 hours. Like 60:00 - 02:25 should give me 57:35 and 60:00 - 00:00 should give me 60:00. Where are I doing wrong?
If you only work with hours + minutes, then you can just calculate the timestamp yourself, something like that:
function calculateSeconds($time) {
$timeParts = explode(':', $time);
return (int)$timeParts[0] * 3600 + (int)$timeParts[1] * 60;
}
and then use it in your function
function timeDiff($firstTime, $lastTime) {
return calculateSeconds($lastTime) - calculateSeconds($firstTime);
}
You can use gmdate() function as bellow.
function timeDiff($firstTime,$lastTime) {
$a_split = explode(":", $firstTime);
$b_split = explode(":", $lastTime);
$a_stamp = mktime($a_split[0], $a_split[1]);
$b_stamp = mktime($b_split[0], $b_split[1]);
if($a_stamp > $b_stamp)
{
$diff = $a_stamp - $b_stamp; //69600
}else{
$diff = $b_stamp - $a_stamp; //69600
}
$min = gmdate("i", $diff);
$d_hours = gmdate("d", $diff)==1 ? 0 : gmdate("d", $diff)*12 ;
$hours = $d_hours + gmdate("H", $diff) ;
echo $hours . ':' . $min; // 56:12:12
}
timeDiff("35:05", "01:45");
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
My output is in the format of 290.52262423327 seconds. How can i change this to 00:04:51?
The same output i want to show in seconds and in HH:MM:SS format, so if it is seconds, i want to show only 290.52 seconds.(only two integers after decimal point)? how can i do this?
I am working in php and the output is present in $time variable. want to change this $time into $newtime with HH:MM:SS and $newsec as 290.52.
Thanks :)
1)
function foo($seconds) {
$t = round($seconds);
return sprintf('%02d:%02d:%02d', ($t/3600),($t/60%60), $t%60);
}
echo foo('290.52262423327'), "\n";
echo foo('9290.52262423327'), "\n";
echo foo(86400+120+6), "\n";
prints
00:04:51
02:34:51
24:02:06
2)
echo round($time, 2);
Try this one
echo gmdate("H:i:s", 90);
For till 23:59:59 hours you can use PHP default function
echo gmdate("H:i:s", 86399);
Which will only return the result till 23:59:59
If your seconds is more then 86399 than
with the help of #VolkerK answer
$time = round($seconds);
echo sprintf('%02d:%02d:%02d', ($time/3600),($time/60%60), $time%60);
will be the best options to use ...
Edit: A comment pointed out that the previous answer fails if the number of seconds exceeds a day (86400 seconds). Here's an updated version. The OP did not specify this requirement so this may be implemented differently than the OP might expect, and there may be much better answers here already. I just couldn't stand having provided an answer with this bug.
$iSecondsIn = 290.52262423327;
// Account for days.
$iDaysOut = 0;
while ($iSecondsIn >= 86400) {
$iDaysOut += 1;
$iSecondsIn -= 86400;
}
// Display number of days if appropriate.
if ($iDaysOut > 0) {
print $iDaysOut.' days and ';
}
// Print the final product.
print date('H:i:s', mktime(0, 0, $iSecondsIn));
The old version, with the bug:
$iSeconds = 290.52262423327;
print date('H:i:s', mktime(0, 0, $iSeconds));
Try this:
$time = 290.52262423327;
echo date("h:i:s", mktime(0,0, round($time) % (24*3600)));
Based on https://stackoverflow.com/a/3534705/4342230, but adding days:
function durationToString($seconds) {
$time = round($seconds);
return sprintf(
'%02dD:%02dH:%02dM:%02dS',
$time / 86400,
($time / 3600) % 24,
($time / 60) % 60,
$time % 60
);
}
I dont know if this is the most efficient way, but if you also need to display days, this works:
function foo($seconds) {
$t = round($seconds);
return sprintf('%02d %02d:%02d:%02d', ($t/86400%24), ($t/3600) -(($t/86400%24)*24),($t/60%60), $t%60);
}
Try this :)
private function conversionTempsEnHms($tempsEnSecondes)
{
$h = floor($tempsEnSecondes / 3600);
$reste_secondes = $tempsEnSecondes - $h * 3600;
$m = floor($reste_secondes / 60);
$reste_secondes = $reste_secondes - $m * 60;
$s = round($reste_secondes, 3);
$s = number_format($s, 3, '.', '');
$h = str_pad($h, 2, '0', STR_PAD_LEFT);
$m = str_pad($m, 2, '0', STR_PAD_LEFT);
$s = str_pad($s, 6, '0', STR_PAD_LEFT);
$temps = $h . ":" . $m . ":" . $s;
return $temps;
}
Personally, going off other peoples answers I made my own parser.
Works with days, hours, minutes and seconds. And should be easy to expand to weeks/months etc.
It works with deserialisation to c# as well
function secondsToTimeInterval($seconds) {
$t = round($seconds);
$days = floor($t/86400);
$day_sec = $days*86400;
$hours = floor( ($t-$day_sec) / (60 * 60) );
$hour_sec = $hours*3600;
$minutes = floor((($t-$day_sec)-$hour_sec)/60);
$min_sec = $minutes*60;
$sec = (($t-$day_sec)-$hour_sec)-$min_sec;
return sprintf('%02d:%02d:%02d:%02d', $days, $hours, $minutes, $sec);
}
1)
$newtime = sprintf( "%02d:%02d:%02d", $time / 3600, $time / 60 % 60, $time % 60 );
2)
$newsec = sprintf( "%.2f", $time );
If you're using Carbon (such as in Laravel), you can do this:
$timeFormatted = \Carbon\Carbon::now()->startOfDay()->addSeconds($seconds)->toTimeString();
But $timeFormatted = date("H:i:s", $seconds); is probably good enough.
Just see caveats.
Here was my implementation with microseconds
/**
* #example 00 d 00 h 00 min 00 sec 005098 ms (0.005098 sec.ms)
*/
public function __toString()
{
// Add your code to get $seconds and $microseconds
$time = round(($seconds + $microseconds), 6, PHP_ROUND_HALF_UP);
return sprintf(
'%02d d %02d h %02d min %02d sec %06d ms (%s sec.ms)',
$time / 86400,
($time / 3600) % 24,
($time / 60) % 60,
$time % 60,
$time * 1000000 % 1000000,
$time
);
}
echo date('H:i:s', round($time)%86400);
Simple formatter with progressively added parts - sample:
formatTime(123) => 2m 3s
formatTime(7400) => 2h 3m 20s
formatTime(999999) => 11d 13h 46m 39s
function formatTime($secs)
{
$secs = max(0, intval($secs));
if($secs > 0){
$out = [];
$yrs = floor($secs / 31536e3);
if($yrs){
$out[] = $yrs."y";
}
$rem = $secs - $yrs * 31536e3;
$days = floor($rem / 86400);
if($days || $out){
$out[] = $days."d";
}
$rem -= $days * 86400;
$hrs = floor($rem / 3600);
if($hrs || $out){
$out[] = $hrs."h";
}
$rem -= $hrs * 3600;
$min = floor($rem / 60);
if($min || $out){
$out[] = $min."m";
}
$rem -= $min * 60;
$out[] = $rem."s";
return implode(" ", $out);
}
return 0;
}
echo date('H:i:s',$time);
echo number_format($time,2);
Numero uno... http://www.ckorp.net/sec2time.php (use this function)
Numero duo... echo round(290.52262423327,2);
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);
}
I have a total ammount of milliseconds (ie 70370) and I want to display it as minutes:seconds:milliseconds ie 00:00:0000.
How can I do this in PHP?
Don't fall into the trap of using date functions for this! What you have here is a time interval, not a date. The naive approach is to do something like this:
date("H:i:s.u", $milliseconds / 1000)
but because the date function is used for (gasp!) dates, it doesn't handle time the way you would want it to in this situation - it takes timezones and daylight savings, etc, into account when formatting a date/time.
Instead, you will probably just want to do some simple maths:
$input = 70135;
$uSec = $input % 1000;
$input = floor($input / 1000);
$seconds = $input % 60;
$input = floor($input / 60);
$minutes = $input % 60;
$input = floor($input / 60);
// and so on, for as long as you require.
If you are using PHP 5.3 you can make use of the DateInterval object:
list($seconds, $millis) = explode('.', $milliseconds / 1000);
$range = new DateInterval("PT{$seconds}S");
echo $range->format('%H:%I:%S') . ':' . str_pad($millis, 3, '0', STR_PAD_LEFT);
why bother with date() and formatting when you can just use math ?
if $ms is your number of milliseconds
echo floor($ms/60000).':'.floor(($ms%60000)/1000).':'.str_pad(floor($ms%1000),3,'0', STR_PAD_LEFT);
convert milliseconds to formatted time
<?php
/* Write your PHP code here */
$input = 7013512333;
$uSec = $input % 1000;
$input = floor($input / 1000);
$seconds = $input % 60;
$input = floor($input / 60);
$minutes = $input % 60;
$input = floor($input / 60);
$hour = $input ;
echo sprintf('%02d %02d %02d %03d', $hour, $minutes, $seconds, $uSec);
?>
check demo here :
https://www.phprun.org/qCbY2n
Try this function to display amount of milliseconds the way you like:
<?php
function udate($format, $utimestamp = null)
{
if (is_null($utimestamp)) {
$utimestamp = microtime(true);
}
$timestamp = floor($utimestamp);
$milliseconds = round(($utimestamp - $timestamp) * 1000000);
return date(preg_replace('`(?<!\\\\)u`', sprintf("%06u", $milliseconds), $format), $timestamp);
}
echo udate('H:i:s.u'); // 19:40:56.78128
echo udate('H:i:s.u', 654532123.04546); // 16:28:43.045460
?>
Source
As mentioned in the manual:
u Microseconds (added in PHP 5.2.2)
Example: 654321
We have a 'u' parameter for the date() function
Example:
if(($u/60) >= 60)
{
$u = mktime(0,($u / 360));
}
date('H:i:s',$u);
no, you can use CarbonInterval:
use Carbon\CarbonInterval;
...
$actualDrivingTimeString = CarbonInterval::seconds($milliseconds/1000)
->cascade()->format('%H:%I:%S');
...
voila, and you are done