如何将unix时间戳上下四舍五入到最接近的半小时


How to round unix timestamp up and down to nearest half hour?

好的,所以我正在CRM系统中开发一个日历应用程序,我需要找到某人在日历中输入事件的时间戳周围半小时的上限和下限,以便在DB上运行一些SQL,以确定他们是否已经在该时间段内预订了一些东西。

例如,我的时间戳为1330518155=2012年2月29日16:22:35 GMT+4所以我需要得到1330516800和1330518600,它们等于16:00和16:30。

如果有人有任何想法,或者认为我正在以一种愚蠢的方式开发日历,请告诉我!这是我第一次做这样一项任务,涉及到这么多时间和日期的工作,所以任何建议都很感激!

使用模。

$prev = 1330518155 - (1330518155 % 1800);
$next = $prev + 1800;

模运算符给出除法的余数部分。

我没有读清楚这些问题,但对于那些不需要两者之间的范围的人来说,这段代码将精确到半小时。使用SenorAmor的一些代码。道具和他对正确问题的疯狂优雅的解决方案。

$time = 1330518155; //Or whatever your time is in unix timestamp
//Store how many seconds long our rounding interval is
//1800 equals one half hour
//Change this to whatever interval to round by
$INTERVAL_SECONDS = 1800;  //30*60
//Find how far off the prior interval we are
$offset = ($time % $INTERVAL_SECONDS); 
//Removing this offset takes us to the "round down" half hour
$rounded = $time - $offset; 
//Now add the full interval if we should have rounded up
if($offset > ($INTERVAL_SECONDS/2)){
  $nearestInterval = $rounded + $INTERVAL_SECONDS;
}
else{
  $nearestInterval = $rounded 
}

您可以使用模运算符。

$time -= $time % 3600; // nearest hour (always rounds down)

希望这足以为你指明正确的方向,如果不是,请添加评论,我将尝试制作一个更具体的例子。

PHP确实有一个DateTime类和它提供的一大堆方法。如果您愿意,可以使用这些函数,但我发现使用内置的date()strtotime()函数更容易。

这是我的解决方案:

// Assume $timestamp has the original timestamp, i.e. 2012-03-09 16:23:41
$day = date( 'Y-m-d', $timestamp ); // $day is now "2012-03-09"
$hour = (int)date( 'H', $timestamp ); // $hour is now (int)16
$minute = (int)date( 'i', $timestamp ); // $minute is now (int)23
if( $minute < 30 ){
  $windowStart = strtotime( "$day $hour:00:00" );
  $windowEnd   = strtotime( "$day $hour:30:00" );
} else {
  $windowStart = strtotime( "$day $hour:30:00" );
  if( ++$hour > 23 ){
    // if we crossed midnight, fix the date and set the hour to 00
    $day = date( 'Y-m-d', $timestamp + (24*60*60) );
    $hour = '00';
  }
  $windowEnd   = strtotime( "$day $hour:00:00" );
}
// Now $windowStart and $windowEnd are the unix timestamps of your endpoints

在这方面可以做一些改进,但这是基本的核心。

[编辑:更正了我的变量名!]

[编辑:我重新审视了这个答案,因为令我尴尬的是,我意识到它没有正确处理一天中的最后半小时。我已经解决了这个问题。请注意,$day是通过在时间戳中添加一天的秒数来解决的——这样做意味着我们不必担心跨越月份界限、闰日等,因为PHP无论如何都会为我们正确格式化它。]

如果您需要获得当前时间,然后应用时间的四舍五入(向下),我会执行以下操作:

$now = date('U');
$offset = ($now % 1800);
$now = $now-$offset;
for ($i = 0;$i < 24; $i++)
{
    echo date('g:i',$now);
    $now += 1800;
}

或者,你可以通过添加偏移量来取整,并做一些不仅仅是回声时间的事情。for循环随后显示12小时的增量。我在最近的一个项目中使用了以上内容。

我会使用localtimemktime函数。

$localtime = localtime($time, true);
$localtime['tm_sec'] = 0;
$localtime['tm_min'] = 30;
$time = mktime($localtime);

远非我最好的作品。。。但这里有一些用于处理字符串或unix时间戳的函数。

/**
 * Takes a timestamp like "2016-10-01 17:59:01" and returns "2016-10-01 18:00"
 * Note: assumes timestamp is in UTC
 * 
 * @param $timestampString - a valid string which will be converted to unix with time()
 * @param int $mins - interval to round to (ex: 15, 30, 60);
 * @param string $format - the format to return the timestamp default is Y-m-d H:i
 * @return bool|string
 */
function roundTimeString( $timestampString, $mins = 30, $format="Y-m-d H:i") {
    return gmdate( $format, roundTimeUnix( time($timestampString), $mins ));
}
/**
 * Rounds the time to the nearest minute interval, example: 15 would round times to 0, 15, 30,45
 * if $mins = 60, 1:00, 2:00
 * @param $unixTimestamp
 * @param int $mins
 * @return mixed
 */
function roundTimeUnix( $unixTimestamp, $mins = 30 ) {
    $roundSecs = $mins*60;
    $offset = $unixTimestamp % $roundSecs;
    $prev = $unixTimestamp - $offset;
    if( $offset > $roundSecs/2 ) {
        return $prev + $roundSecs;
    }
    return $prev;
}

这是一个使用DateTimeInterface并保留时区信息等的解决方案。它还将处理与GMT偏移量不是30分钟倍数的时区(例如Asia/Kathmandu)。

/**
 * Return a DateTimeInterface object that is rounded down to the nearest half hour.
 * @param 'DateTimeInterface $dateTime
 * @return 'DateTimeInterface
 * @throws 'UnexpectedValueException if the $dateTime object is an unknown type
 */
function roundToHalfHour('DateTimeInterface $dateTime)
{
    $hours = (int)$dateTime->format('H');
    $minutes = $dateTime->format('i');
    # Round down to the last half hour period
    $minutes = $minutes >= 30 ? 30 : 0;
    if ($dateTime instanceof 'DateTimeImmutable) {
        return $dateTime->setTime($hours, $minutes);
    } elseif ($dateTime instanceof 'DateTime) {
        // Don't change the object that was passed in, but return a new object
        $dateTime = clone $dateTime;
        $dateTime->setTime($hours, $minutes);
        return $dateTime;
    }
    throw new UnexpectedValueException('Unexpected DateTimeInterface object');
}

不过,您需要先创建DateTime对象——也许使用$dateTime = new DateTimeImmutable('@' . $timestamp)之类的东西。您也可以在构造函数中设置时区。

Math.round(timestamp/1800)*1800

正如您可能知道的,UNIX时间戳是秒数,因此减去/添加1800(以30分钟为单位的秒数),您将获得所需的结果。

对于那些可能在一天中的某些时间必须制作其中一些的人来说,这里有一个更具语义的方法。

$time = strtotime(date('Y-m-d H:00:00'));

您可以将H更改为任何0-23数字,这样您就可以四舍五入到当天的那个小时。