2012-03-09 16 views
18

Ok, estoy trabajando en una aplicación de calendario dentro de mi sistema CRM y necesito encontrar los límites superior e inferior de la media hora que sobrepasa la marca de tiempo en la que alguien ingresó a un evento en el calendario para ejecutar SQL en el DB para determinar si ya tienen algo reservado dentro de ese intervalo de tiempo.¿Cómo redondear la marca de tiempo de Unix hacia arriba y hacia abajo a la media hora más cercana?

Por ejemplo, tengo la marca de tiempo 1330518155 = 29 de febrero de 2012 16:22:35 GMT + 4 por lo que necesita para obtener 1330516800 y 1330518600, que es igual a las 16:00 y las 16:30.

Si alguien tiene alguna idea o piensa que me estoy acercando a desarrollar el calendario de una manera estúpida, ¡hágamelo saber! ¡Es mi primera vez en una tarea que implica tanto trabajo con los tiempos y las fechas, por lo que cualquier consejo se agradece!

+0

intente utilizar la función en manual - http://php.net/manual/en/function.strtotime.php - debe ser útil, puede agregar o eliminar cualquier cantidad de tiempo de la marca de tiempo muy fácil. – Kamil

+0

¿qué tiene esto que ver con las horas y las fechas? es simple matemática – miki

Respuesta

58

Use modulo.

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

El operador de módulo da el resto de la división.

+0

Eso encontrará segundos desde la hora, pero eso es solo parte del problema, porque si los minutos son> = 30, el intervalo de tiempo es H: 30 a H + 1: 00 –

+1

Dado que estamos dividiendo por 1800, lo hará dar segundos desde el último incremento de media hora (1:00, 1:30, 2:00, 2:30, etc ...). Si es 1:30:01, la operación de módulo devolverá 1 y $ prev será 1:30. Agregar 1800 segundos hará $ siguiente igual a 2:00. Del mismo modo, si es 1:29:59, el módulo será 1799 y $ prev será 1:00. Nuevamente, agregar 1800 hará $ siguiente a la 1:30. – SenorAmor

+2

¡Tan simple que a veces intentas sobre pensar cosas y buscar una función para hacer aritmética básica! – Ash

0

Como probablemente sepa, una marca de tiempo UNIX es una cantidad de segundos, por lo que resta/agrega 1800 (número de segundos en 30 minutos) y obtendrá el resultado deseado.

+2

que no está realmente redondeando, ¿o sí? – thescientist

+0

Eso encontrará 30 minutos antes y 30 minutos después, no el "en la hora" y "en la media hora" que limitan el tiempo. Por favor mira su ejemplo nuevamente. –

2

Puede usar el operador de módulo.

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

Esperemos que esto es suficiente para señalarle en la dirección correcta, si no por favor añadir un comentario y voy a tratar de elaborar un ejemplo más específico.

0

Utilizaría las funciones localtime y mktime.

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

PHP tiene una clase DateTime y una gran cantidad de métodos que proporciona. Puede usarlos si lo desea, pero me resulta más fácil usar las funciones integradas date() y strtotime().

aquí está mi solución:

// 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 

Hay algunas mejoras que se pueden hacer en esto, pero eso es el núcleo básico.

[Editar: corregido mis nombres de variables]

[Editar: He a visitar esta respuesta porque, para mi vergüenza, me di cuenta que no manejó la última media hora de un día correctamente. He solucionado ese problema. Tenga en cuenta que $day se soluciona agregando un valor de segundos de un día a la marca de tiempo; hacerlo de esta manera significa que no tenemos que preocuparnos de cruzar los límites de un mes, los días bisiestos, etc. porque PHP lo formateará correctamente independientemente de nosotros].

2

No leí las preguntas con claridad, pero este código redondeará a la media hora más cercana, para aquellos que no necesitan el rango entre los dos. Utiliza algo del código de SenorAmor. Props y su loca y elegante solución a la pregunta correcta.

$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 
} 
1

Si usted necesita para obtener la hora actual y luego aplicar el redondeo (hacia abajo) de las veces, me gustaría hacer lo siguiente:

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

o usted podría redondear sumando el desplazamiento, y hacer algo más que solo repetir el tiempo. El ciclo for muestra las 12 horas de incrementos. Usé lo anterior en un proyecto reciente.

0

Lejos de mi mejor trabajo ... pero aquí hay algunas funciones para trabajar con cadenas o marcas de tiempo de 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

Esta es una solución usando DateTimeInterface y mantener la información zona horaria etc. También se va a manejar las zonas horarias que no son un múltiplo de 30 minutos desplazamiento desde GMT (por ejemplo 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'); 
} 

Tendrá que haber creado el objeto DateTime primero sin embargo - tal vez con algo así como $dateTime = new DateTimeImmutable('@' . $timestamp). También puede establecer la zona horaria en el constructor.

Cuestiones relacionadas