Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP DateTime round up to nearest 10 minutes

Tags:

php

datetime

I'm retrieving a datetime from a mysql field but I need to round it up to the nearest 10 minutes.

For example, If the datetime is 2013-11-06 14:00:01, I'd like to return the time as 6/11/2013 14:10.

What's the easiest way to do this?

$datetime = new DateTime($mysqldata);

echo $datetime->format('d/m/Y G:i');

Any advice appreciated.

Thanks.

like image 782
Dan Avatar asked Nov 06 '13 14:11

Dan


5 Answers

1) Set number of seconds to 0 if necessary (by rounding up to the nearest minute)

$second = $datetime->format("s");
if($second > 0)
    $datetime->add(new DateInterval("PT".(60-$second)."S"));

2) Get minute

$minute = $datetime->format("i");

3) Convert modulo 10

$minute = $minute % 10;

4) Count minutes to next 10-multiple minutes if necessary

if($minute != 0)
{
    // Count difference
    $diff = 10 - $minute;
    // Add difference
    $datetime->add(new DateInterval("PT".$diff."M"));
}

Edited, thanks @Ondrej Henek and @berturion

like image 54
rand Avatar answered Nov 13 '22 22:11

rand


I stumbled upon this question and wondered why all the solutions are so complicated. It's simply this:

function roundToNext10Min(\DateTime $dt, $precision = 10) {
    $s = $precision * 60;
    $dt->setTimestamp($s * (int) ceil($dt->getTimestamp() / $s));
    return $dt;
}

$dt = roundToNext10Min(new DateTime($str));
echo $dt->format('d/m/Y G:i');
like image 17
esqilin Avatar answered Nov 13 '22 21:11

esqilin


Edit: I wrote this answer a long time ago, some folks discovered that milliseconds are not considered. It is worth try other answers than mine to find the perfect time rounding method.

The answer of @rand have a bug when the DateTime we want to round is already a 10-minutes multiple. It will jump to 10 minutes later while it is not wanted.

Also, always jumping to the next minute with ($datetime->add(new \DateInterval("PT".(60-$second)."S")); is not wanted when seconds is at zero already.

This enhanced function fixes these bugs and takes a $precision parameter to cover more use cases.

function roundTime(\DateTime &$datetime, $precision = 30, $round_lower = false) {
    // 1) Set number of seconds to 0 (by rounding up to the nearest minute if necessary)
    $second = (int) $datetime->format("s");
    if ($second > 30 && $round_lower == false) {
        // Jumps to the next minute
        $datetime->add(new \DateInterval("PT".(60-$second)."S"));
    } elseif ($second > 0) {
        // Back to 0 seconds on current minute
        $datetime->sub(new \DateInterval("PT".$second."S"));
    }
    // 2) Get minute
    $minute = (int) $datetime->format("i");
    // 3) Convert modulo $precision
    $minute = $minute % $precision;
    if ($minute > 0) {
        if($round_lower) {
            $datetime->sub(new \DateInterval("PT".$minute."M"));
        } else {
            // 4) Count minutes to next $precision-multiple minutes
            $diff = $precision - $minute;
            // 5) Add the difference to the original date time
            $datetime->add(new \DateInterval("PT".$diff."M"));
        }
    }
}

This function is now perfect for my use and probably for other folks.

Edit: Now it allows to set round upper or lower

like image 16
berturion Avatar answered Nov 13 '22 20:11

berturion


You can use the ceil, floor and round functions to round a DateTime either up, down or to the nearest minute interval as follows:

/**
 * @param \DateTime $dateTime
 * @param int $minuteInterval
 * @return \DateTime
 */
public function roundUpToMinuteInterval(\DateTime $dateTime, $minuteInterval = 10)
{
    return $dateTime->setTime(
        $dateTime->format('H'),
        ceil($dateTime->format('i') / $minuteInterval) * $minuteInterval,
        0
    );
}

/**
 * @param \DateTime $dateTime
 * @param int $minuteInterval
 * @return \DateTime
 */
public function roundDownToMinuteInterval(\DateTime $dateTime, $minuteInterval = 10)
{
    return $dateTime->setTime(
        $dateTime->format('H'),
        floor($dateTime->format('i') / $minuteInterval) * $minuteInterval,
        0
    );
}

/**
 * @param \DateTime $dateTime
 * @param int $minuteInterval
 * @return \DateTime
 */
public function roundToNearestMinuteInterval(\DateTime $dateTime, $minuteInterval = 10)
{
    return $dateTime->setTime(
        $dateTime->format('H'),
        round($dateTime->format('i') / $minuteInterval) * $minuteInterval,
        0
    );
}
like image 8
markpietrus Avatar answered Nov 13 '22 21:11

markpietrus


I would use timestamps:

<?php

function roundTime(\DateTime $datetime, $precision = 10) {

    $ts = $datetime->getTimestamp();
    $s = ($precision * 60);
    $remainder = $ts % $s;

    if ($remainder > 0) {
        $datetime->setTimestamp($ts + $s - $remainder);
    }

    return $datetime;
}

echo roundTime(\DateTime::createFromFormat('Y-m-d H:i:s', '2016-03-04 09:00:00'))
    ->format('Y-m-d H:i:s');
// prints: 2016-03-04 09:00:00


echo roundTime(\DateTime::createFromFormat('Y-m-d H:i:s', '2016-03-04 09:00:01'))
    ->format('Y-m-d H:i:s');
// prints: 2016-03-04 09:10:00
like image 4
Martin Vseticka Avatar answered Nov 13 '22 20:11

Martin Vseticka