I have the following array called $exhibitions:
Array
(
[0] => Array
(
[exhibition_title] => Picasso
[venue_name] => Gallery 1
[room_name] => Room 4
[start_date] => 2023-11-15
[end_date] => 2023-12-10
[room_id] => 261
[exhibition_id] => 3540
[venue_order] => 2
)
[1] => Array
(
[exhibition_title] => Monet
[venue_name] => Gallery 4
[room_name] => Room 2
[start_date] => 2023-10-01
[end_date] => 2023-11-13
[room_id] => 274
[exhibition_id] => 8417
[venue_order] => 1
)
)
What I need to do is use the start_date
and end_date
to create a range of dates each exhibition is open, and then for each of those dates essentially duplicate the rest of the information in the existing sub-array with the individual date appended to the end of the sub-array. My desired output would be:
Array
(
[0] => Array
(
[exhibition_title] => Picasso
[venue_name] => Gallery 1
[room_name] => Room 4
[start_date] => 2023-11-15
[end_date] => 2023-12-10
[room_id] => 261
[exhibition_id] => 3540
[venue_order] => 2
[date] => 2023-11-15
)
[1] => Array
(
[exhibition_title] => Picasso
[venue_name] => Gallery 1
[room_name] => Room 4
[start_date] => 2023-11-15
[end_date] => 2023-12-10
[room_id] => 261
[exhibition_id] => 3540
[venue_order] => 2
[date] => 2023-11-16
)
[2] => Array
(
[exhibition_title] => Picasso
[venue_name] => Gallery 1
[room_name] => Room 4
[start_date] => 2023-11-15
[end_date] => 2023-12-10
[room_id] => 261
[exhibition_id] => 3540
[venue_order] => 2
[date] => 2023-11-17
)
[... etc. for the rest of the dates in the Picasso date range]
[25] => Array
(
[exhibition_title] => Monet
[venue_name] => Gallery 4
[room_name] => Room 2
[start_date] => 2023-10-01
[end_date] => 2023-11-13
[room_id] => 274
[exhibition_id] => 8417
[venue_order] => 1
[date] => 2023-10-01
)
[26] => Array
(
[exhibition_title] => Monet
[venue_name] => Gallery 4
[room_name] => Room 2
[start_date] => 2023-10-01
[end_date] => 2023-11-13
[room_id] => 274
[exhibition_id] => 8417
[venue_order] => 1
[date] => 2023-10-02
)
[27] => Array
(
[exhibition_title] => Monet
[venue_name] => Gallery 4
[room_name] => Room 2
[start_date] => 2023-10-01
[end_date] => 2023-11-13
[room_id] => 274
[exhibition_id] => 8417
[venue_order] => 1
[date] => 2023-10-03
)
[... etc. for the rest of the dates in the Monet date range]
)
I saw this similar post and modified it so that instead of echoing the $given_date
, it added it to the array in a new column called "date".
foreach ($exhibitions as $key => $value) {
$startDate = strtotime($value['start_date']);
$endDate = strtotime($value['end_date']);
// Loop between timestamps, 24 hours at a time
for ($i = $startDate; $i <= $endDate; $i = $i + 86400 ) {
$given_date = date('Y-m-d', $i );
$exhibitions[$key]['date'] = $given_date;
}
};
The problem was that instead of adding one date per date in the date range, it added the last date in the range only. When I echoed the $given_date
just to make sure it was iterating each date, it lists every date in the range, so I'm assuming there's something wrong with how I added the new column but I can't figure out what.
To have an "inclusive" range of dates, add 1 day to the end date (otherwise every range will be one day short).
By appending the generated date to the row data with the union operator (+
), you avoid needing to write out every element in the row while pushing.
Code: (Demo)
$result = [];
foreach ($exhibitions as $row) {
$dateRange = new DatePeriod(
new DateTime($row['start_date']),
new DateInterval('P1D'), // 1 day per step
new DateTime("{$row['end_date']} +1 day") // +1 day to include end date
);
foreach ($dateRange as $d) {
$result[] = $row + ['date' => $d->format("Y-m-d")];
}
}
var_export($result);
...from PHP8.2, you can use a special flag instead of +1 day
. (Demo)
$dateRange = new DatePeriod(
new DateTime($row['start_date']),
new DateInterval('P1D'),
new DateTime($row['end_date']),
DatePeriod::INCLUDE_END_DATE
);