将分钟数向下取到最接近的15分钟

62
我需要在PHP中将时间向下舍入到最近的15分钟。这些时间是从MySQL数据库中的日期时间列中提取并格式化的,例如2010-03-18 10:50:00
例如:
  • 10:50 需要变成 10:45
  • 1:12 需要变成 1:00
  • 3:28 需要变成 3:15
  • 等等。
我假设需要使用floor()函数,但不确定如何实现。
谢谢。

7
如果你要将时间取到最接近的一刻钟,那么1:12会变成1:15,3:28会变成3:30,而不是向下取整到一刻钟。但实际上,你是要向下取整到一刻钟,这比前者稍微有些难度。 - Richard JP Le Guen
抱歉,是的,那就是目标。向下舍入到最近的15分钟。 - Rob
PHP日期时间任意舍入函数:https://dev59.com/-mIj5IYBdhLWcg3w24kF#57399274 - Stephen R
在PHP开始之前,关于处理这个任务的相关建议:如何将时间四舍五入到最近的15分钟段Java、MySQL或PHP - 将分钟向下舍入到下一个10分钟 - undefined
20个回答

1
简单的解决方案:
$oldDate = "2010-03-18 10:50:00";
$date = date("Y-m-d H:i:s", floor(strtotime($oldDate) / 15 / 60) * 15 * 60);

你可以将floor替换为ceil,如果你想要向上取整。

1
// 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 );
}

这个按要求工作了。11:29 变成了 11:30,11:22 变成了 11:15。这比 Wickethewok 的解决方案更好。我将默认的舍入到分钟改为了 15 分钟,因为请求者要求四舍五入到每个刻钟。我还将输出格式改为了 g:i:s,以适应我的特定需求。 - Johnish

1
我需要一种方法将日期向下舍入,并截断超出该日期的所有内容:
$explodedDate = explode("T", gmdate("c",strtotime("now")));
$expireNowDate =  date_create($explodedDate[0]);

strtotime函数返回当前时间的时间戳,gmdate将其转换为ISO格式(类似于“2012-06-05T04:00:00+00:00”),然后使用“T”进行分割,得到“2012-06-05”在$explodedDate数组中的第0个索引位置,然后将其传递给date_create函数以获取日期对象。

不确定是否所有这些步骤都是必要的,但它似乎比逐个减去秒、分钟、小时等要简单得多。


这可能更容易。 $expireNowDate = date_create(date("Y-m-d")); - Andy Gee

0
我写了一个函数,可以将时间戳舍入到秒或分钟。
虽然可能不是最高效的方法,但我认为PHP并不在乎一些简单的循环。
在你的情况下,你只需要像这样传递你的MySQL日期时间:
<?php echo date('d/m/Y - H:i:s', roundTime(strtotime($MysqlDateTime), 'i', 15)); ?>

返回:最接近的四舍五入值(同时向上和向下查找!)
函数:
<?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;
}
?>

如果你想四舍五入到秒,只需将$entity替换为's',并将15替换为你想要四舍五入到的秒数或分钟数。


0

可能会对其他人有帮助。适用于任何语言。

roundedMinutes = yourRoundFun(Minutes / interval) * interval.

例如,时间间隔可以是5分钟、10分钟、15分钟或30分钟。 然后,四舍五入的分钟数可以重置为相应的日期。
yourDateObj.setMinutes(0) 
yourDateObj.setMinutes(roundedMinutes)

0

这是我目前正在使用的一个函数:

/**
 * 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;
}

希望能对某些人有所帮助 :)

0
大多数答案都把问题复杂化了。
PHP 7+内置了一个名为intdiv的函数,用于整数除法(向下取整)。由于楼主想要将结果舍入到最接近的15分钟,你可以简单地使用以下代码:
$t = time();
// Or from string:
$t = strtotime('2010-03-18 10:50:00');
$t = intdiv($t, 900) * 900;
$output = date('Y-m-d H:i:s', $t);

在这里在线运行

900 是15分钟的秒数(60 * 15)。

如果性能非常关键,这段代码应该也会更快,因为它会有更少的底层指令,因为你不再使用浮点除法。


是的,这比被接受的答案要简单一些,但是你的输入值是一个Unix时间戳。然而,原始问题提供的是一个格式化的日期字符串。为了完全满足问题并展示性能优势,你需要将字符串解析为Unix时间戳,进行计算,然后将整数返回到原始的日期时间格式。 - undefined
@mickmackusa OP没有提供任何代码,问题也很模糊。不过,我还是更新了我的答案。问题的核心是如何将日期向下取整。如果用户是从数据库中选择的,那么取决于他们在选择中是否使用了UNIX_TIMESTAMP,或者他们如何将数据传递给PHP。 - undefined
此外,得票最高的答案也使用了time(),这表明该答案仍然有用。 - undefined
在Stack Overflow上,旧页面因为新的回答受到早期回答的影响,往往会出现“任务蔓延”或需求偏离的情况,这是相对常见的。我只是希望回答能够专注于解答最初提出的问题。 - undefined

0

一行代码解决。

protected function roundToQuarterHour($timestring)
    {
        return Carbon::parse($timestring)->roundMinute(15);
    }

0

尽管通常最适合使用基于日期时间的函数来操作日期时间,但此任务的要求不涉及任何特殊的时间相关处理--它是在特定子字符串上执行计算并使用数学结果替换子字符串的简单任务。

并非每个人都喜欢正则表达式,但它确实提供了一种单函数技术来改变输入字符串。

代码:(演示)

$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
     );

输出:

2010-03-18 10:45:00
---
2010-03-18 10:45:00

请注意,如果要处理仅包含时间的字符串(以冒号分隔),此正则表达式模式同样有效。(演示

0

或者你可以让 MySQL 来处理(1970 年以后的日期):

SELECT FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(date_col)/900)*900) FROM mytable;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接