diff --git a/src/Bundle/ChillMainBundle/Service/RollingDate/RollingDate.php b/src/Bundle/ChillMainBundle/Service/RollingDate/RollingDate.php index cc00c7777..7294e6816 100644 --- a/src/Bundle/ChillMainBundle/Service/RollingDate/RollingDate.php +++ b/src/Bundle/ChillMainBundle/Service/RollingDate/RollingDate.php @@ -77,7 +77,7 @@ class RollingDate * @param DateTimeImmutable|null $pivotDate Will be "now" if null is given * @param DateTimeImmutable|null $fixedDate Only to insert if $roll equals @see{self::T_FIXED_DATE} */ - public function __construct(string $roll, ?DateTimeImmutable $pivotDate = null, ?DateTimeImmutable $fixedDate = null) + public function __construct(string $roll, ?DateTimeImmutable $fixedDate = null, ?DateTimeImmutable $pivotDate = null) { $this->roll = $roll; $this->pivotDate = $pivotDate ?? new DateTimeImmutable('now'); diff --git a/src/Bundle/ChillMainBundle/Service/RollingDate/RollingDateConverter.php b/src/Bundle/ChillMainBundle/Service/RollingDate/RollingDateConverter.php new file mode 100644 index 000000000..e3cfb8e89 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Service/RollingDate/RollingDateConverter.php @@ -0,0 +1,141 @@ +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')) + ); + } +} diff --git a/src/Bundle/ChillMainBundle/Tests/Services/RollingDate/RollingDateConverterTest.php b/src/Bundle/ChillMainBundle/Tests/Services/RollingDate/RollingDateConverterTest.php new file mode 100644 index 000000000..6df2c889b --- /dev/null +++ b/src/Bundle/ChillMainBundle/Tests/Services/RollingDate/RollingDateConverterTest.php @@ -0,0 +1,101 @@ +converter = new RollingDateConverter(); + } + + public function generateDataConversionDate(): iterable + { + $format = 'Y-m-d His'; + + yield [RollingDate::T_MONTH_CURRENT_START, '2022-11-01 000000', $format]; + + yield [RollingDate::T_MONTH_NEXT_START, '2022-12-01 000000', $format]; + + yield [RollingDate::T_MONTH_PREVIOUS_START, '2022-10-01 000000', $format]; + + yield [RollingDate::T_QUARTER_CURRENT_START, '2022-10-01 000000', $format]; + + yield [RollingDate::T_QUARTER_NEXT_START, '2023-01-01 000000', $format]; + + yield [RollingDate::T_QUARTER_PREVIOUS_START, '2022-07-01 000000', $format]; + + yield [RollingDate::T_TODAY, '2022-11-07 000000', $format]; + + yield [RollingDate::T_WEEK_CURRENT_START, '2022-11-07 000000', $format]; + + yield [RollingDate::T_WEEK_NEXT_START, '2022-11-14 000000', $format]; + + yield [RollingDate::T_WEEK_PREVIOUS_START, '2022-10-31 000000', $format]; + + yield [RollingDate::T_YEAR_CURRENT_START, '2022-01-01 000000', $format]; + + yield [RollingDate::T_YEAR_NEXT_START, '2023-01-01 000000', $format]; + + yield [RollingDate::T_YEAR_PREVIOUS_START, '2021-01-01 000000', $format]; + } + + public function testConversionFixedDate() + { + $rollingDate = new RollingDate(RollingDate::T_FIXED_DATE, new DateTimeImmutable('2022-01-01')); + + $this->assertEquals( + '2022-01-01', + $this->converter->convert($rollingDate)->format('Y-m-d') + ); + } + + public function testConvertOnDateNow() + { + $rollingDate = new RollingDate(RollingDate::T_YEAR_PREVIOUS_START); + + $actual = $this->converter->convert($rollingDate); + + $this->assertEquals( + (int) (new DateTimeImmutable('now'))->format('Y') - 1, + (int) $actual->format('Y') + ); + $this->assertEquals(1, (int) $actual->format('m')); + $this->assertEquals(1, (int) $actual->format('d')); + } + + /** + * @dataProvider generateDataConversionDate + */ + public function testConvertOnPivotDate(string $roll, string $expectedDateTime, string $format) + { + $pivot = DateTimeImmutable::createFromFormat('Y-m-d His', '2022-11-07 000000'); + $rollingDate = new RollingDate($roll, null, $pivot); + + $this->assertEquals( + DateTime::createFromFormat($format, $expectedDateTime), + $this->converter->convert($rollingDate) + ); + } +}