Skip to content

Instantly share code, notes, and snippets.

@mRoca
Last active March 10, 2022 09:26
Show Gist options
  • Save mRoca/249d8374ee4e6fdfac502c100841b266 to your computer and use it in GitHub Desktop.
Save mRoca/249d8374ee4e6fdfac502c100841b266 to your computer and use it in GitHub Desktop.
<?php
/**
* Returns all days between two dates matching a wanted position in a week, in a month.
*
* For instance, in order to get all dates matching the request:
* "First and third monday and friday of each month between 2022-01-08 and 2022-06-15" :
*
* $days = getDatesInRangeByDaysInMonth(new DateTimeImmutable('2022-01-08'), new DateTimeImmutable('2022-06-15'), [1, 5], [1, 3]);
*
* @param DateTimeInterface $startDate
* @param DateTimeInterface $endDate
* @param int[] $daysOfWeek
* @param int[] $daysOfWeekInMonth
* @return DateTimeImmutable[]
*/
function getDatesInRangeByDaysInMonth(DateTimeInterface $startDate, DateTimeInterface $endDate, array $daysOfWeek, array $daysOfWeekInMonth): array
{
$days = [1 => 'Monday', 2 => 'Tuesday', 3 => 'Wednesday', 4 => 'Thursday', 5 => 'Friday', 6 => 'Saturday', 7 => 'Sunday'];
$ordinals = [1 => 'first', 2 => 'second', 3 => 'third', 4 => 'fourth', 5 => 'fifth'];
// Clean passed variables
$startDate = $startDate instanceof DateTime ? DateTimeImmutable::createFromMutable($startDate) : $startDate;
$endDate = $endDate instanceof DateTime ? DateTimeImmutable::createFromMutable($endDate) : $endDate;
$daysOfWeek = array_unique(array_filter($daysOfWeek, static fn($d) => array_key_exists((int)$d, $days)));
$daysOfWeekInMonth = array_unique(array_filter($daysOfWeekInMonth, static fn($d) => array_key_exists((int)$d, $ordinals)));
/** @var DateTimeImmutable[] $result */
$result = [];
// Iterator
$period = new DatePeriod($startDate->modify('first day of this month'), new DateInterval('P1M'), $endDate);
foreach ($period as $firstDayOfMonth) {
/** @var DateTimeImmutable $firstDayOfMonth */
foreach ($daysOfWeekInMonth as $dayOfWeekInMonth) {
foreach ($daysOfWeek as $dayOfWeek) {
$newDate = $firstDayOfMonth->modify(sprintf('%s %s of this month', $ordinals[$dayOfWeekInMonth], $days[$dayOfWeek]));
if ($newDate < $startDate || $newDate > $endDate) {
continue;
}
$result[] = $newDate;
}
}
}
return $result;
}
$startDate = new DateTimeImmutable('2022-01-08');
$endDate = new DateTimeImmutable('2022-06-15');
$daysOfWeek = [1, 5]; // 1 = monday, 5 = friday
$daysOfWeekInMonth = [1, 3]; // First and third monday and friday of each month
$days = getDatesInRangeByDaysInMonth($startDate, $endDate, $daysOfWeek, $daysOfWeekInMonth);
print_r($days);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment