Подтвердить что ты не робот

Как округлить временную отметку unix вверх и вниз до ближайшего полчаса?

Хорошо, поэтому я работаю над приложением календаря в своей CRM-системе, и мне нужно найти верхнюю и нижнюю границы полутора часового времени, отбрасывая временную метку, в которую кто-то ввел событие в календаре, чтобы запустить некоторый SQL на БД, чтобы определить, есть ли у них что-то забронированное в пределах этого временного интервала.

Например, у меня есть отметка времени 1330518155 = 29 февраля 2012 г. 16:22:35 GMT + 4 поэтому мне нужно получить 1330516800 и 1330518600, которые равны 16:00 и 16:30.

Если у кого есть какие-то идеи или я думаю, что приближаюсь к разработке календаря глупым способом, дайте мне знать! Его первый раз на такой задаче, в которой так много работы со временем и датами, поэтому любые советы были оценены!

4b9b3361

Ответ 1

Используйте modulo.

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

Оператор modulo дает остальную часть деления.

Ответ 2

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

Есть несколько улучшений, которые могут быть сделаны на этом, но что основное ядро.

[Изменить: исправлены мои имена переменных!]

[Edit: Я пересмотрел этот ответ, потому что, к моему смущению, я понял, что он не обрабатывал последние полчаса дня правильно. Я исправил эту проблему. Обратите внимание, что $day фиксируется добавлением дневной стоимости секунд в метку времени - это делается так, что нам не нужно беспокоиться о пересечении границ месяца, дней високосного перехода и т.д., Потому что PHP будет корректно отформатировать нас.]

Ответ 3

Вы можете использовать оператор modulo.

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

Надеюсь, этого достаточно, чтобы указать вам в правильном направлении, если не добавить комментарий, и я попытаюсь создать более конкретный пример.

Ответ 4

Я не читал вопросы четко, но этот код будет округлен до ближайшего полчаса, для тех, кому не нужен диапазон между ними. Использует некоторые коды 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 
}

Ответ 5

Если вам нужно получить текущее время, а затем применить округление (вниз) времени, я бы сделал следующее:

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

Или вы можете округлить, добавив смещение и сделать что-то большее, чем просто эхо-время. Затем цикл for отображает 12 часов приращений. Я использовал вышеупомянутое в недавнем проекте.

Ответ 6

Как вы, вероятно, знаете, временная метка UNIX занимает несколько секунд, поэтому substract/add 1800 (количество секунд в 30 минуты), и вы получите желаемый результат.

Ответ 7

Я бы использовал функции localtime и mktime.

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

Ответ 8

Вдали от моей лучшей работы... но здесь есть некоторые функции для работы со строкой или 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;
}

Ответ 9

Это решение, использующее DateTimeInterface и сохраняющее информацию о часовом поясе и т.д. Также будет обрабатывать временные интервалы, которые не являются кратным 30-минутному смещению от GMT (например, 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). Вы также можете установить часовой пояс в конструкторе.