Хорошо, поэтому я работаю над календарным приложением в своей 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, ie 2012-03-09 16:23:41 $day = date( 'Ym-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( 'Ym-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 time stamp.
/** * 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 Ymd H:i * @return bool|string */ function roundTimeString( $timestampString, $mins = 30, $format="Ymd 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 (например, 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)
. Вы также можете установить часовой пояс в конструкторе.