3

Starting with a date in this format: 2011-05-01 09:00:00, how can I create an array that contains all office hours (09:00 to 17:00) for all working days of the year (so excluding all Saturday and Sundays). What I want to arrive to is something like this:

2011-05-01 09:00:00
2011-05-01 10:00:00
2011-05-01 11:00:00
2011-05-01 12:00:00
2011-05-01 13:00:00
2011-05-01 14:00:00
2011-05-01 15:00:00
2011-05-01 16:00:00
2011-05-01 17:00:00
//next day, starting at 09:00 and ending at 17:00
2011-05-02 09:00:00
...
2011-05-02 17:00:00
//until the last day of the year from 09:00 to 17:00
2011-12-31 09:00:00
...
2011-12-31 17:00:00

The start date will be the first of the current month at with 09:00 as time and the very last date (last element of the array) will always be 17:00 on the last day of the year.

Again, weekends should be excluded.

Pseudocode idea: I thought of something like strtotime($start, "+1 one hour") with a check for "if smaller than 17:00" but it doesn't seem to be that simple.

canni
  • 5,737
  • 9
  • 46
  • 68
stef
  • 26,771
  • 31
  • 105
  • 143
  • If you don't care about Saturday/Sunday, just iterate by adding 86400 seconds (1 day) to any start time. Start from a complete day, and iterate till you hit the time range. Then skip it till it's ok again. – JohnP May 24 '11 at 13:51

7 Answers7

5

How about this:

$start = strtotime('2011-05-01');
$end = strtotime('2011-12-31');

$times = array();

for ($i = $start; $i <= $end; $i += 24 * 3600)
{
    if (date("D", $i) == "Sun" || date("D", $i) == "Sat")
    {
        continue;
    }

    for ($j = 9; $j <= 17; $j++)
    {
        $times []= date("Y-m-d $j:00:00", $i);
    }
}

The outer loop iterates through all the days in the given time period. In the outer loop, we check to see if the day is either Saturday or Sunday (a weekend), and if it is, we skip that day. If it's not a weekend, we loop through all the valid hours, adding the full date and time to the array as we go.

Jimmy Sawczuk
  • 13,488
  • 7
  • 46
  • 60
1

Some tips:

  1. date("G", $some_timestamp) gives you the hour of the day in 24-hour format
  2. date("N", $some_timestamp) gives you the day of the week, 1 (for Monday) through 7 (for Sunday)

Take a look at the php manual for date.

Edit: You can pick any start timestamp and add 3600 to add one hour, if your hour is greater than 17, you can add a bigger step to go right to the next morning, same for a weekend, and just do a while ($timestamp < $end_timestamp) {}

jeroen
  • 91,079
  • 21
  • 114
  • 132
  • Yep I know the date function well, just not sure how I can "add one hour" between the values of 9AM and 5PM. – stef May 24 '11 at 13:50
  • @stef Ummmmmm, add 3600 to the timestamp? – jeroen May 24 '11 at 13:51
  • Jeroen's solution brings me closer! – stef May 24 '11 at 13:56
  • @Gordon Doesn´t php handle that automatically if you set your timezone? – jeroen May 24 '11 at 13:57
  • @jeroen php will know if your timezone has DST but if you are in a tz with DST and add 3600 to a timestamp and run it through date, you will not get consecutive hours when DST happens, which is why you dont use arithmentics but `strtotime('+1 hour')` – Gordon May 24 '11 at 14:01
  • @Gordon Ah, ok, so you would need to make sure that if you add a big step after 5pm, you never pass 8am the next day or use a second loop for the days. – jeroen May 24 '11 at 14:06
1
$datetime = new DateTime(); // Set your start date here
do { // Iterate over .. dont know, a long time?
  do { // Iterate over the week ...
    $datetime->setTime(9,0,0);
    do { // Iterate over the hours ...
      echo $datetime->format('c') . PHP_EOL; // Do something with $datetime here
      $datetime->add(new DateInterval('PT1H'));
    } while ($datetime->format('G') < 18); // .. till < 18
    $datetime->add(new DateInterval('P1D')); // next day
  } while (!in_array($datetime->format('w'), array('0','6'))); // until we hit sunday or saturday
  $datetime->add(new DateInterval('P2D')); // next monday
} while (true); // replace with your "end" expression

Currently untested.

You can use the common interval-strings (like 1 hour and so on) too http://php.net/dateinterval.createfromdatestring

KingCrunch
  • 128,817
  • 21
  • 151
  • 173
1

I'd encourage you to use the wonderful DateTime class and its related classes. Here, you can make good use of DatePeriod:

<?php

$now = new DateTime('today'); // starting time 0.00 this morning
$endOfYear = new DateTime('31 December this year 23:00'); // end time
$interval = new DateInterval('PT1H'); // frequency -- every hour

$times = array();

foreach (new DatePeriod($now, $interval, $endOfYear ) as $datetime) {
// $datetime is a DateTime object for the hour and time in question
    $dow = $datetime->format('w'); // 0 is Sunday
    if (($dow == '0') || ($dow == '6')) {
        continue; // miss Saturday and Sunday out
    }

    $time = $datetime->format('G'); // hour without leading 0
    if (($time < '9') || ($time > '17')) {
        continue;
    }

    $times[] = $datetime->format('r'); // output format
}

var_dump($times);

Obviously there are various aspects of this that you can configure, especially the output format. Depending on your purpose, you may prefer to put the DateTime objects themselves into the array.

lonesomeday
  • 233,373
  • 50
  • 316
  • 318
0

You could calculate your dates with two nested loops and generate the string with date().

Daniel
  • 261
  • 2
  • 5
0

I would just loop through all dates, incremented by hour, from now until the end of the year, as follows (pseudocode, obviously):

for n = now until end of year
    if (date(n) is between 9:00 and 17:00) AND (if date(n) is not sat or sun)
        add to array
    end if
    increment n by 1 hour
end
eykanal
  • 26,437
  • 19
  • 82
  • 113
0

Here is a solution which should be reasonably fast since it uses no string comparisons and has only two function calls inside the loops:

function hours()
{
    $start = mktime(0, 0, 0, date('n'), 1, date('Y'));
    $end = mktime(0, 0, 0, 1, 1, date('Y') + 1);
    $wday = date('w', $start);
    $result = array();
    for ($t = $start; $t < $end; $t += 3600 * 24) {
        if (($wday > 0) && ($wday < 6)) {
            for ($hour = 9; $hour <= 17; $hour++) {
                $result[] = date('Y-m-d', $t) . sprintf(' %02d:00:00', $hour);
            }
        }
        $wday = ($wday + 1) % 7;
    }
    return $result;
}
August Karlstrom
  • 10,773
  • 7
  • 38
  • 60