Home > Software design >  Show next "DateInterval" value depending on actual time
Show next "DateInterval" value depending on actual time

Time:12-20

I use a "DateInterval" with an interval of 3 hours to get all the dates between a start and end time. The result looks like that:

15:00 | 18:00 | 21:00 | 00:00 | 03:00 (and so on...)

Now I'm searching a solution that only the next "DateInterval" value gets shown (depending on the actual time), and not all of them.

Example: if the actual time is 19:29 the shown result should be 21:00.

My code so far:

$start = new DateTime('2022-12-18 15:00:00');
$interval = DateInterval::createFromDateString('3 hours');
$end = new DateTime('2022-12-31 15:00:00');

$occurrences = new DatePeriod($start, $interval, $end);

foreach ($occurrences as $occurrence) {

    echo $occurrence->format('H:i') . PHP_EOL;
}

CodePudding user response:

The following will properly take into account the start time and return an object with the same timezone and other properties as its input.

function intervalToSeconds(DateInterval $interval) {
    $d1 = new DateTimeImmutable('', new DateTimezone('UTC'));
    $d2 = $d1->add($interval);
    return $d2->getTimestamp() - $d1->getTimestamp();
}

function getNextDateTime(DateTime $target, DateTime $start, DateInterval $interval) {
    $t_start    = $start->getTimestamp();
    $t_target   = $target->getTimestamp();
    $t_since    = $t_target - $t_start;
    $t_interval = intervalToSeconds($interval);
    
    $t_next = ( intdiv($t_since, $t_interval)   1 ) * $t_interval   $t_start;
    
    return (clone $target)->setTimestamp($t_next);
}

$start = new DateTime('2022-12-18 16:00:00', new DateTimezone('UTC'));
$interval = DateInterval::createFromDateString('3 hours');
$now = new DateTime('2022-12-20 23:45:01', new DateTimezone('America/Vancouver'));

var_dump(
    $start, $interval,
    getNextDateTime($now, $start, $interval)
);

Output:

object(DateTime)#1 (3) {
  ["date"]=>
  string(26) "2022-12-18 16:00:00.000000"
  ["timezone_type"]=>
  int(3)
  ["timezone"]=>
  string(3) "UTC"
}
object(DateInterval)#2 (2) {
  ["from_string"]=>
  bool(true)
  ["date_string"]=>
  string(7) "3 hours"
}
object(DateTime)#5 (3) {
  ["date"]=>
  string(26) "2022-12-21 02:00:00.000000"
  ["timezone_type"]=>
  int(3)
  ["timezone"]=>
  string(17) "America/Vancouver"
}

CodePudding user response:

No need to iterate through the period. Just manipulate current hour number. This probably might be reworked with plain unix timestamps for even simplier code:

<?php

// This is just for test, in the code below
// should be replaced with plain `(new DateTime)`
$now = new DateTime('2022-12-18 19:29:00');

// Set the next fraction-3 hour
$result = ( new DateTime )
    ->setTime(
        // Divide current hour by 3, take integer part,
        // add one, multiply by 3, take 24 modulo 
        // (to get '0' instead of '24' and '3' instead of '27')
        (((int)($now->format('H') / 3)   1 ) * 3) % 24,
        0
    );

// The result
// Note, the date is current here
print $result->format('H:i');
  • Related