将分钟向下舍入到最接近的一刻钟
Posted
技术标签:
【中文标题】将分钟向下舍入到最接近的一刻钟【英文标题】:Round minute down to nearest quarter hour 【发布时间】:2011-01-29 15:40:57 【问题描述】:我需要在 php 中将时间四舍五入到最接近的一刻钟。时间从 mysql 数据库中的 datetime 列中提取,并格式化为2010-03-18 10:50:00
。
例子:
10:50 必须是 10:45 1:12 必须是 1:00 3:28 必须是 3:15 等我假设 floor()
参与其中,但不知道该怎么做。
谢谢
【问题讨论】:
如果您四舍五入到最近的刻钟,1:12 会不会变成 1:15,3:28 会变成 3:30?相反,您不是将向下四舍五入到一刻钟吗?前者比后者更具挑战性…… 抱歉,这就是目标。向下舍入到最近的一刻钟。 任意舍入 PHP 日期时间的函数:***.com/a/57399274/339440 【参考方案1】:$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";
此示例获取当前时间并将其四舍五入到最近的四分之一,并打印原始时间和四舍五入的时间。
PS:如果你想将它向下舍入,请将round()
替换为floor()
。
【讨论】:
如果你想分别强制你的时间向上/向下,你可以为round()补充ceil()/floor()。 简单、聪明且易于定制。太棒了!【参考方案2】:你的完整功能应该是这样的......
function roundToQuarterHour($timestring)
$minutes = date('i', strtotime($timestring));
return $minutes - ($minutes % 15);
【讨论】:
删除了这个函数,走这条路:$start_minutes = date('i', strtotime($row['start'])); $minutes_floor = $start_minutes - ($start_minutes % 15); 如果 $minutes = 29 它将返回 15 - 必须返回 30 如何向上舍入。像 9.10 舍入到 9.15 和 9.20 到 9.30 一样明智 @FDisk 没错。我们正在四舍五入,而不是最接近的。所以,15
对 29
是正确的【参考方案3】:
$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;
【讨论】:
我发现如果时间是 10:59,它会四舍五入到 10:60。为了解决这个问题,我添加了: if ($minutes == "60") $rounded = $date_split['hour']+1; $rounded .= ":00"; else $minutes = str_pad($minutes, 2, '0', STR_PAD_LEFT); $rounded = $date_split['hour'].":".$minutes; 还有 str_pad 以确保到处都是前导零。此解决方案可能是最佳的,但效果很好。【参考方案4】:要舍入最近的一刻钟,请使用以下代码
<?php
$time = strtotime("01:08");
echo $time.'<br />';
$round = 15*60;
$rounded = round($time / $round) * $round;
echo date("H:i", $rounded);
?>
01:08 变成 01:15
【讨论】:
你的例子比接受答案中的例子更精确,谢谢!【参考方案5】:最近我喜欢用TDD/unit testing 的方式解决问题。最近我不再编写太多 PHP 了,但这就是我想出的。老实说,我实际上查看了这里的代码示例,并选择了一个我认为已经正确的示例。接下来,我想使用您上面提供的测试通过单元测试来验证这一点。
类时间测试
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()));
上课时间
<?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;
运行测试
alfred@alfred-laptop:~/htdocs/time$ phpunit TimeTest.php
PHPUnit 3.3.17 by Sebastian Bergmann.
....
Time: 0 seconds
OK (4 tests, 12 assertions)
【讨论】:
【参考方案6】:$minutes = ($minutes - ($minutes % 15));
【讨论】:
所以 1:19 变成 (19%15)*15 = 4*15 = 60!? 谢谢理查德。我的头在别的地方。【参考方案7】:这是一个老问题,但最近我自己实现了,我将分享我的解决方案:-
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'));
【讨论】:
它确实是地板 - 但不是向上/向下舍入。【参考方案8】:我很惊讶没有人提到惊人的Carbon library(在 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/
测试用例:
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));
【讨论】:
其实在使用 Carbon 的时候,你可以做$now->floorMinute(15)
或者类似的操作
在 Laravel 中使用 now()->floorMinutes(15)
。为了像@Wesley-Synio 那样总结使用now()->roundMinutes(15)
,这存在于其他时间间隔,例如小时和天。
因为您不需要 Carbon 库。查看@TrentRenshaw 的另一个答案【参考方案9】:
对于我的系统,我想添加计划在我的服务器上每 5 分钟运行一次的作业,并且我希望相同的作业在接下来的 5 分钟块内运行,然后是 15、30、60、120、240 分钟, 1天2天后,这就是这个函数计算的结果
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>';
【讨论】:
【参考方案10】:使用内置 PHP 函数进行舍入时间以考虑日期和时间是很重要的。例如,2020-10-09 23:37:35
需要在四舍五入时变为 2020-10-10 00:00:00
。
圆形时间到最近的小时:
$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
四舍五入到最近的 15 分钟增量:
$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
如果您需要四舍五入到最近的 15 分钟增量,请将 floor
更改为 ceil
,例如
$time = date("Y-m-d H:i:s", ceil(strtotime($time) / (60*15))*(60*15)); // 2020-10-09 23:45:00
如果您需要将时间四舍五入到另一个分钟增量,您可以简单地这样做:
$time = date("Y-m-d H:i:s", ceil(strtotime($time) / (60*20))*(60*20)); // 2020-10-10 00:00:00
【讨论】:
【参考方案11】:我需要一种方法来结束这一天,并切断除此之外的一切:
$explodedDate = explode("T", gmdate("c",strtotime("now")));
$expireNowDate = date_create($explodedDate[0]);
strtotime 给了我“现在”的时间戳,gmdate 将其转换为 ISO 格式(类似于“2012-06-05T04:00:00+00:00”),然后我在“T”处使用爆炸,在 $explodedDate 的第零个索引中给我“2012-06-05”,然后将其传递给 date_create 以获取日期对象。
不确定是否所有这些都是必要的,但这似乎比通过并减去秒、分钟、小时等的工作要少得多。
【讨论】:
或者这可能更容易。$expireNowDate = date_create(date("Y-m-d"));
【参考方案12】:
// 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 以满足我的特殊需要。【参考方案13】:简单的解决方案:
$oldDate = "2010-03-18 10:50:00";
$date = date("Y-m-d H:i:s", floor(strtotime($oldDate) / 15 / 60) * 15 * 60);
如果要四舍五入,可以将floor
更改为ceil
。
【讨论】:
【参考方案14】:我编写了一个函数,可以将时间戳四舍五入到秒或分钟。
我可能不是最高效的方式,但我认为 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 替换为您想要向上或向下舍入的秒数或分钟数。
【讨论】:
【参考方案15】:这是我目前正在使用的一个函数:
/**
* 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;
希望它可以帮助某人:)
【讨论】:
【参考方案16】:可能会帮助别人。适用于任何语言。
roundedMinutes = yourRoundFun(Minutes / interval) * interval.
例如间隔可以是 5 分钟、10 分钟、15 分钟、30 分钟。 然后可以将四舍五入的分钟重置为相应的日期。
yourDateObj.setMinutes(0)
yourDateObj.setMinutes(roundedMinutes)
【讨论】:
【参考方案17】:虽然通常最适合使用基于日期时间的函数来操作日期时间,但此任务的要求不涉及任何与时间相关的特殊处理——它是对特定子字符串执行计算的简单任务,并且使用数学结果替换子字符串。
不是每个人都喜欢正则表达式,但它确实提供了一种单一功能的技术来改变输入字符串。
代码:(Demo)
$timeString = "2010-03-18 10:50:57";
// PHP7.4+ arrow syntax
echo preg_replace_callback(
'~:\K(\d2).*~',
fn($m) => $m[1] - $m[1] % 15 . ':00',
$timeString
);
echo "\n---\n";
// below PHP7.3
echo preg_replace_callback(
'~:\K(\d2).*~',
function($m) return $m[1] - $m[1] % 15 . ':00';,
$timeString
);
输出:
2010-03-18 10:45:00
---
2010-03-18 10:45:00
注意,这种正则表达式模式在处理仅时间(以冒号分隔)的字符串时同样有效。 (Demo)
【讨论】:
以上是关于将分钟向下舍入到最接近的一刻钟的主要内容,如果未能解决你的问题,请参考以下文章