Как округлить временную метку unix вверх и вниз до ближайшего получаса?
хорошо, поэтому я работаю над календарным приложением в моей CRM-системе, и мне нужно найти верхнюю и нижнюю границы получаса, окружающего метку времени, в которой кто-то ввел событие в календаре, чтобы запустить некоторый SQL на БД, чтобы определить, есть ли у них уже что-то забронировано в пределах этого временного интервала.
например, у меня есть отметка времени 1330518155 = 29 февраля 2012 16: 22: 35 GMT+4 поэтому мне нужно получить 1330516800 и 1330518600, которые равны 16: 00 и 16:30.
Если у кого-нибудь есть какие-либо идеи или думаю, что я приближаюсь к разработке календаря глупым способом, дайте мне знать! Это мой первый раз на такой задаче, связанной с такой большой работой со временем и датами, поэтому любой совет ценится!
9 ответов
использовать по модулю.
$prev = 1330518155 - (1330518155 % 1800);
$next = $prev + 1800;
оператор по модулю дает оставшуюся часть деления.
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:исправлены имена переменных!]
[Edit: я вернулся к этому ответу, потому что, к моему смущению, я понял, что это последние полчаса дня я вел себя неправильно. Я исправил эту проблему. Обратите внимание, что $day
фиксируется путем добавления секунд на день к метке времени - это означает, что нам не нужно беспокоиться о пересечении границ месяца, високосных дней и т. д. потому что PHP будет форматировать его правильно для нас независимо.]
вы можете использовать оператор по модулю.
$time -= $time % 3600; // nearest hour (always rounds down)
надеюсь, этого достаточно, чтобы указать вам в правильном направлении, если нет, добавьте комментарий, и я попытаюсь создать более конкретный пример.
Я не читал вопросы четко, но этот код будет округляться до ближайших получаса, для тех, кому не нужен диапазон между ними. Использует код Сеньорамора. Реквизит и его безумное элегантное решение правильного вопроса.
$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
}
Если вам нужно получить текущее время, а затем применить округлением (вниз) времени, я бы сделал следующее:
$now = date('U');
$offset = ($now % 1800);
$now = $now-$offset;
for ($i = 0;$i < 24; $i++)
{
echo date('g:i',$now);
$now += 1800;
}
или вы можете округлить, добавив смещение, и сделать что-то большее, чем просто эхо времени. Затем цикл for отображает 12 часов инкрементов. Я использовал вышеизложенное в недавнем проекте.
Как вы, вероятно, знаете, метка времени UNIX-это несколько секунд, поэтому substract/add 1800
(количество секунд в 30
минут), и вы получите желаемый результат.
далеко от моей лучшей работы... но вот некоторые функции для работы со строкой или меткой времени 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
и держать информацию о часовом поясе etc. Будет также обрабатывать часовые пояса, которые не кратны 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)
. Вы также можете установить часовой пояс в конструкторе.