web-dev-qa-db-ja.com

UNIXタイムスタンプを最も近い30分に切り上げる方法は?

それでは、CRMシステム内のカレンダーアプリケーションに取り組んでいます。DBでSQLを実行するために、誰かがカレンダーにイベントを入力したタイムスタンプを超える30分の上下限を見つける必要があります。そのタイムスロット内ですでに何かが予約されているかどうかを確認します。

たとえば、タイムスタンプが1330518155 = 2012年2月29日16:22:35 GMT + 4であるため、16:00と16:30に等しい1330516800と1330518600を取得する必要があります。

誰かが何かアイデアを持っている、または私が愚かな方法でカレンダーを開発していると思っているなら、私に知らせてください!時間と日付を使用する多くの作業を含むそのようなタスクに初めて参加するので、アドバイスはありがたいです!

20
Ash

モジュロを使用します。

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

剰余演算子は、除算の残りの部分を与えます。

66
SenorAmor

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

これにはいくつかの改善点がありますが、それが基本的なコアです。

[編集:変数名を修正しました!]

[編集:私がこの答えを再訪したのは、恥ずかしいことに、1日の最後の30分を正しく処理できないことに気づいたからです。その問題を修正しました。ご了承ください $dayは、タイムスタンプに1日分の秒数を追加することで修正されます。このようにすることで、PHPは、関係なく、正しくフォーマットしてください。]

3
Jazz

モジュロ演算子を使用できます。

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

うまくいけば、これで正しい方向を示すのに十分です。そうでない場合は、コメントを追加してください。具体的な例を作成します。

2
Chris Browne

私は質問を明確に読みませんでしたが、このコードは2つの間の範囲を必要としない人のために、最も近い30分に丸めます。 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 
}
2
Eric G

現在の時刻を取得してから、時刻の丸め(切り捨て)を適用する必要がある場合は、次のようにします。

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

または、オフセットを追加して端数を切り上げ、時間をエコーするだけではありません。 forループは、12時間の増分を表示します。私は最近のプロジェクトで上記を使用しました。

1
royjm

localtime関数とmktime関数を使用します。

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

私の最高の仕事とはほど遠い...しかし、ここに文字列または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;
}
0
blak3r

これは、おそらく1日の特定の時間に、これらのいくつかを作成する必要がある人のためのよりセマンティックな方法です。

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

そのHを0〜23の任意の数値に変更できるため、その日のその時間に丸めることができます。

0
Vael Victus

これは、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)のようなものを使用します。コンストラクタでタイムゾーンを設定することもできます。

0
Dezza

おそらくご存じのとおり、UNIXタイムスタンプは秒数なので、180030分の秒数)を減算/加算すると、目的の結果が得られます。

0
Pateman