web-dev-qa-db-fra.com

Comment arrondir l'horodatage Unix à la demi-heure près?

Ok, je suis donc en train de travailler sur une application de calendrier dans mon système CRM et je dois trouver les limites supérieure et inférieure de la demi-heure au-dessus de l'horodatage auquel une personne a saisi un événement dans le calendrier afin d'exécuter du code SQL sur la base de données pour déterminer s’ils ont déjà réservé quelque chose dans cet intervalle de temps.

Par exemple, j'ai l'horodatage 1330518155 = 29 février 2012 16:22:35 GMT + 4, donc je dois obtenir 1330516800 et 1330518600, ce qui correspond à 16h00 et à 16h30.

Si quelqu'un a des idées ou pense que je suis en train d'élaborer le calendrier de manière stupide, faites-le moi savoir! C’est la première fois que je participe à une tâche de ce type, qui demande tant de temps et de dates, alors tout conseil est apprécié!

19
Ash

Utilisez modulo.

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

L'opérateur modulo donne le reste de la division.

63
SenorAmor

PHP a une classe DateTime et tout un tas de méthodes qu’elle fournit. Vous pouvez les utiliser si vous le souhaitez, mais je trouve plus facile d'utiliser les fonctions intégrées date() et strtotime().

Voici ma solution:

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

Quelques améliorations peuvent être apportées à ce sujet, mais c'est le noyau de base.

[Edit: corrigé mes noms de variables!]

[Edit: J'ai revu cette réponse parce que, à mon grand embarras, j'ai réalisé qu'il ne gérait pas correctement la dernière demi-heure de la journée. J'ai résolu ce problème. Notez que $day est corrigé en ajoutant une journée de secondes à l'horodatage. Cela signifie que nous n'avons pas à nous soucier du franchissement des limites des mois, des jours bissextiles, etc., car PHP le formatera. correctement pour nous malgré tout.]

3
Jazz

Vous pouvez utiliser l'opérateur modulo.

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

Espérons que cela suffira à vous orienter dans la bonne direction. Sinon, veuillez ajouter un commentaire et je vais essayer de vous donner un exemple plus spécifique.

2
Chris Browne

Je n'ai pas lu les questions clairement, mais ce code sera arrondi à la demi-heure la plus proche, pour ceux qui n'ont pas besoin de l'intervalle entre les deux. Utilise une partie du code de SenorAmor. Les accessoires et sa solution élégante folle à la bonne question.

$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

Si vous avez besoin d’obtenir l’heure actuelle et d’appliquer ensuite l’arrondi (en bas) du temps, je procéderais comme suit:

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

Vous pouvez également arrondir en ajoutant le décalage et faire quelque chose de plus que l'écho du temps. La boucle for affiche ensuite les 12 heures d’incréments. J'ai utilisé ce qui précède dans un projet récent.

1
royjm

J'utiliserais les fonctions localtime et mktime.

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

Loin de mon travail le plus abouti ... mais voici quelques fonctions permettant de travailler avec des horodatages string ou 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

Voici une méthode plus sémantique pour ceux qui doivent en faire quelques-uns, peut-être à certaines heures de la journée.

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

Vous pouvez changer cette H en n'importe quel nombre compris entre 0 et 23, de sorte que vous puissiez arrondir à cette heure de la journée.

0
Vael Victus

C'est une solution qui utilise DateTimeInterface et conserve les informations de fuseau horaire, etc. Gère également les fuseaux horaires qui ne sont pas un décalage de 30 minutes par rapport à GMT (par exemple, 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');
}

Cependant, vous devrez d'abord avoir créé l'objet DateTime - peut-être avec quelque chose comme $dateTime = new DateTimeImmutable('@' . $timestamp). Vous pouvez également définir le fuseau horaire dans le constructeur.

0
Dezza

Comme vous le savez probablement, un horodatage UNIX est un nombre de secondes, donc soustrayez/ajoutez 1800 (nombre de secondes dans 30 minutes) et vous obtiendrez le résultat souhaité.

0
Pateman