Is it possible to round up date() or strtotime() to nearest hour?

Lets say I am pulling a datetime from the database that’s like 2010-10-20 18:30:00 or 2010-10-20 18:45:00 and I want to round those to the nearest hour which would of course be 2010-10-20 19:00:00.

For example, I have two datetimes: 2010-10-20 18:00:00 and 2010-10-20 18:30:00 that I want to round up, throw into the date() and strtotime() functions, and have it say “Scheduled between 6 PM to 7 PM”.

This didn’t work for me:


$date = '2010-10-20 18:30:00';
$eround = round(strtotime($date), 2);
$etime = date("g A", $eround);

I don’t know of a built in function, but it might be easier to break down your existing date, check the minutes and if it’s not at 0, then add an hour and set the minutes to 0.

And don’t forget that when the hour is 24 it should be 0 the next day. And when the day is 32 (or 29, or 31, depending on what month it is, and whether it’s a leap year, etc) it should be day 1 in the next month, and when the month is 13 it should be month 1 in the next year :slight_smile:

I would parse the string out to variables, increase the hour if needed, and then pass all variables to mktime() and let that function figure out all the stuff I said above :slight_smile:

$time = strtotime($date);

$minutes = $time % 3600; # pulls the remainder of the hour.

$time -= $minutes; # just start off rounded down.

if ($minutes >= 1800) $time += 3600; # add one hour if 30 mins or higher.

$etime = date(“g A”, $time);

Fingers crossed that you have PHP 5.3 available to play with because the changes to the DateTime part of PHP eat this sort of task for breakfast!

Off Topic:

The DateTime::createFromFormat is not actually necessary in this example given that all you care about are the hour and meridian. But note that the $datetime when created from that special formatting string will represent the date/time 2010-10-20 18:00:00 which we later add an hour to, to get the end hour.


$date = '2010-10-20 18:30:00';
$datetime = DateTime::createFromFormat('Y-m-d H:??:??', $date);

$start = $datetime->format('g A');
$end   = $datetime->modify('next hour')->format('g A');

echo "Scheduled between $start and $end.";

If you’re not yet blessed with PHP 5.3 (i.e., stuck with 5.2 or lower!) then we’ll have to resort to more old-school approaches like:


$date = '2010-10-20 18:30:00';

$start = date('g A', strtotime($date));
$end   = date('g A', strtotime('+1 hour', strtotime($date)));

echo "Scheduled between $start and $end.";

Edit: As Michael rightly points out, you could still likely make use of the DateTime class with PHP 5.2. Just without our fancy bespoke parsing of the date/time string.


$date = '2010-10-20 18:30:00';
$datetime = new DateTime($date);

$start = $datetime->format('g A');

$datetime->modify('+1 hour');
$end = $datetime->format('g A');

echo "Scheduled between $start and $end.";

Timestamps are a count of seconds. There are 1200 seconds in an hour. A timestamp that is exactly on the hour is going to be divisible by 1200.

Except for leap seconds :confused:

However, what we can do to account for that is subtract the timestamp for the year of the timestamp. The result should then be divisible by 1200 if it’s exactly on the hour. We can then use a modulus operation to do the rounding, then return the remainder and the year.


function roundToHour($timestamp) {
  $year = strtotime( date('Y', $timestamp).'-01-01 00:00');
  $remainder = $year - $timestamp;

  if ($remainder % 1200 > 600) {
    $remainder = $remainder + (1200 - ($remainder % 1200));
  } else {
    $remainder = $remainder - ($remainder % 1200);
  }

  return $year + $remainder;
}

That’s off the top of my head. I can’t even guarantee it won’t have a parse error.

DateTime was introduced in 5.2. It got some enhancements in 5.3 and I don’t know offhand if those enhancements are necessary for your code to work. I didn’t think of that approach, it is cleaner than mine (which has a bit more literal interpretation of the phrase “round” )

Michael, my particular example requires 5.3. Though you’re quite right that the class was available earlier and could still be useful to the OP for his particular question: I just wanted to show off DateTime::createFromFormat. The changes that came with 5.3.0 are particularly helpful for date modifications, calculations, etc. and do eat what may seem like complicated and/or weird tasks for breakfast.

I’m using 5.2.14 so this helped me out. I saw other example where they added +3600 to the time and then floor() to round down but your method is easier to read and modify. Thanks!

You’re welcome. (: