getRoll()) { case RollingDate::T_MONTH_CURRENT_START: return $this->toBeginOfMonth($rollingDate->getPivotDate()); case RollingDate::T_MONTH_NEXT_START: return $this->toBeginOfMonth($rollingDate->getPivotDate()->add(new DateInterval('P1M'))); case RollingDate::T_MONTH_PREVIOUS_START: return $this->toBeginOfMonth($rollingDate->getPivotDate()->sub(new DateInterval('P1M'))); case RollingDate::T_QUARTER_CURRENT_START: return $this->toBeginOfQuarter($rollingDate->getPivotDate()); case RollingDate::T_QUARTER_NEXT_START: return $this->toBeginOfQuarter($rollingDate->getPivotDate()->add(new DateInterval('P3M'))); case RollingDate::T_QUARTER_PREVIOUS_START: return $this->toBeginOfQuarter($rollingDate->getPivotDate()->sub(new DateInterval('P3M'))); case RollingDate::T_WEEK_CURRENT_START: return $this->toBeginOfWeek($rollingDate->getPivotDate()); case RollingDate::T_WEEK_NEXT_START: return $this->toBeginOfWeek($rollingDate->getPivotDate()->add(new DateInterval('P1W'))); case RollingDate::T_WEEK_PREVIOUS_START: return $this->toBeginOfWeek($rollingDate->getPivotDate()->sub(new DateInterval('P1W'))); case RollingDate::T_YEAR_CURRENT_START: return $this->toBeginOfYear($rollingDate->getPivotDate()); case RollingDate::T_YEAR_PREVIOUS_START: return $this->toBeginOfYear($rollingDate->getPivotDate()->sub(new DateInterval('P1Y'))); case RollingDate::T_YEAR_NEXT_START: return $this->toBeginOfYear($rollingDate->getPivotDate()->add(new DateInterval('P1Y'))); case RollingDate::T_TODAY: return $rollingDate->getPivotDate(); case RollingDate::T_FIXED_DATE: if (null === $rollingDate->getFixedDate()) { throw new LogicException('You must provide a fixed date when selecting a fixed date'); } return $rollingDate->getFixedDate(); default: throw new UnexpectedValueException(sprintf('%s rolling operation not supported', $rollingDate->getRoll())); } } private function toBeginOfMonth(DateTimeImmutable $date): DateTimeImmutable { return DateTimeImmutable::createFromFormat( 'Y-m-d His', sprintf('%s-%s-01 000000', $date->format('Y'), $date->format('m')) ); } private function toBeginOfQuarter(DateTimeImmutable $date): DateTimeImmutable { switch ((int) $date->format('n')) { case 1: case 2: case 3: $month = '01'; break; case 4: case 5: case 6: $month = '04'; break; case 7: case 8: case 9: $month = '07'; break; case 10: case 11: case 12: $month = '10'; break; default: throw new LogicException('this month is not valid: ' . $date->format('n')); } return DateTimeImmutable::createFromFormat( 'Y-m-d His', sprintf('%s-%s-01 000000', $date->format('Y'), $month) ); } private function toBeginOfWeek(DateTimeImmutable $date): DateTimeImmutable { if (1 === $dayOfWeek = (int) $date->format('N')) { return $date->setTime(0, 0, 0); } return $date ->sub(new DateInterval('P' . ($dayOfWeek - 1) . 'D')) ->setTime(0, 0, 0); } private function toBeginOfYear(DateTimeImmutable $date): DateTimeImmutable { return DateTimeImmutable::createFromFormat( 'Y-m-d His', sprintf('%s-01-01 000000', $date->format('Y')) ); } }