Ответ 1
Используйте modulo.
$prev = 1330518155 - (1330518155 % 1800);
$next = $prev + 1800;
Оператор modulo дает остальную часть деления.
Хорошо, поэтому я работаю над приложением календаря в своей CRM-системе, и мне нужно найти верхнюю и нижнюю границы полутора часового времени, отбрасывая временную метку, в которую кто-то ввел событие в календаре, чтобы запустить некоторый SQL на БД, чтобы определить, есть ли у них что-то забронированное в пределах этого временного интервала.
Например, у меня есть отметка времени 1330518155 = 29 февраля 2012 г. 16:22:35 GMT + 4 поэтому мне нужно получить 1330516800 и 1330518600, которые равны 16:00 и 16:30.
Если у кого есть какие-то идеи или я думаю, что приближаюсь к разработке календаря глупым способом, дайте мне знать! Его первый раз на такой задаче, в которой так много работы со временем и датами, поэтому любые советы были оценены!
Используйте modulo.
$prev = 1330518155 - (1330518155 % 1800);
$next = $prev + 1800;
Оператор modulo дает остальную часть деления.
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 будет корректно отформатировать нас.]
Вы можете использовать оператор modulo.
$time -= $time % 3600; // nearest hour (always rounds down)
Надеюсь, этого достаточно, чтобы указать вам в правильном направлении, если не добавить комментарий, и я попытаюсь создать более конкретный пример.
Я не читал вопросы четко, но этот код будет округлен до ближайшего полчаса, для тех, кому не нужен диапазон между ними. Использует некоторые коды 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
}
Если вам нужно получить текущее время, а затем применить округление (вниз) времени, я бы сделал следующее:
$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
минуты), и вы получите желаемый результат.
Я бы использовал функции localtime
и mktime
.
$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
и сохраняющее информацию о часовом поясе и т.д. Также будет обрабатывать временные интервалы, которые не являются кратным 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)
. Вы также можете установить часовой пояс в конструкторе.