Skip to content

Commit 9d12f04

Browse files
christianberkmanpaulbalandanmichalsn
authored
feat: add Time::addCalendarMonths() and Time::subCalendarMonths() methods (#9528)
* feat: [I18n\Time] addCalendarMonths() * Remove return type * fix addCalendarMonths() return type * make addCalendarMonths() bi-directional and add subCalendarMonths() * update userguide and changelog * add tests for addCalendarMonths() and subCalendarMonths() * user guide: functions -> methods Co-authored-by: John Paul E. Balandan, CPA <[email protected]> * revert change for TimeTrait::setTimeNow() * Update TimeTrait.php revert change to TimeTrait::setTimeNow() * update user guide * Update user_guide_src/source/libraries/time.rst Co-authored-by: Michal Sniatala <[email protected]> --------- Co-authored-by: John Paul E. Balandan, CPA <[email protected]> Co-authored-by: Michal Sniatala <[email protected]>
1 parent e15078c commit 9d12f04

File tree

5 files changed

+90
-0
lines changed

5 files changed

+90
-0
lines changed

system/I18n/TimeTrait.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -749,6 +749,39 @@ public function addMonths(int $months)
749749
return $time->add(DateInterval::createFromDateString("{$months} months"));
750750
}
751751

752+
/**
753+
* Returns a new Time instance with $months calendar months added to the time.
754+
*/
755+
public function addCalendarMonths(int $months): static
756+
{
757+
$time = clone $this;
758+
759+
$year = (int) $time->getYear();
760+
$month = (int) $time->getMonth();
761+
$day = (int) $time->getDay();
762+
763+
// Adjust total months since year 0
764+
$totalMonths = ($year * 12 + $month - 1) + $months;
765+
766+
// Recalculate year and month
767+
$newYear = intdiv($totalMonths, 12);
768+
$newMonth = $totalMonths % 12 + 1;
769+
770+
// Get last day of new month
771+
$lastDayOfMonth = cal_days_in_month(CAL_GREGORIAN, $newMonth, $newYear);
772+
$correctedDay = min($day, $lastDayOfMonth);
773+
774+
return static::create($newYear, $newMonth, $correctedDay, (int) $this->getHour(), (int) $this->getMinute(), (int) $this->getSecond(), $this->getTimezone(), $this->locale);
775+
}
776+
777+
/**
778+
* Returns a new Time instance with $months calendar months subtracted from the time
779+
*/
780+
public function subCalendarMonths(int $months): static
781+
{
782+
return $this->addCalendarMonths(-$months);
783+
}
784+
752785
/**
753786
* Returns a new Time instance with $years added to the time.
754787
*

tests/system/I18n/TimeTest.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -812,6 +812,22 @@ public function testCanAddMonthsOverYearBoundary(): void
812812
$this->assertSame('2018-02-10 13:20:33', $newTime->toDateTimeString());
813813
}
814814

815+
public function testCanAddCalendarMonths(): void
816+
{
817+
$time = Time::parse('January 31, 2017 13:20:33', 'America/Chicago');
818+
$newTime = $time->addCalendarMonths(1);
819+
$this->assertSame('2017-01-31 13:20:33', $time->toDateTimeString());
820+
$this->assertSame('2017-02-28 13:20:33', $newTime->toDateTimeString());
821+
}
822+
823+
public function testCanAddCalendarMonthsOverYearBoundary(): void
824+
{
825+
$time = Time::parse('January 31, 2017 13:20:33', 'America/Chicago');
826+
$newTime = $time->addCalendarMonths(13);
827+
$this->assertSame('2017-01-31 13:20:33', $time->toDateTimeString());
828+
$this->assertSame('2018-02-28 13:20:33', $newTime->toDateTimeString());
829+
}
830+
815831
public function testCanAddYears(): void
816832
{
817833
$time = Time::parse('January 10, 2017 13:20:33', 'America/Chicago');
@@ -860,6 +876,22 @@ public function testCanSubtractMonths(): void
860876
$this->assertSame('2016-10-10 13:20:33', $newTime->toDateTimeString());
861877
}
862878

879+
public function testCanSubtractCalendarMonths(): void
880+
{
881+
$time = Time::parse('March 31, 2017 13:20:33', 'America/Chicago');
882+
$newTime = $time->subCalendarMonths(1);
883+
$this->assertSame('2017-03-31 13:20:33', $time->toDateTimeString());
884+
$this->assertSame('2017-02-28 13:20:33', $newTime->toDateTimeString());
885+
}
886+
887+
public function testCanSubtractCalendarMonthsOverYearBoundary(): void
888+
{
889+
$time = Time::parse('March 31, 2017 13:20:33', 'America/Chicago');
890+
$newTime = $time->subCalendarMonths(13);
891+
$this->assertSame('2017-03-31 13:20:33', $time->toDateTimeString());
892+
$this->assertSame('2016-02-29 13:20:33', $newTime->toDateTimeString());
893+
}
894+
863895
public function testCanSubtractYears(): void
864896
{
865897
$time = Time::parse('January 10, 2017 13:20:33', 'America/Chicago');

user_guide_src/source/changelogs/v4.7.0.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ Method Signature Changes
3333
Enhancements
3434
************
3535

36+
Libraries
37+
=========
38+
39+
- **Time:** added methods ``Time::addCalendarMonths()`` and ``Time::subCalendarMonths()``
40+
3641
Commands
3742
========
3843

user_guide_src/source/libraries/time.rst

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,24 @@ modify the existing Time instance, but will return a new instance.
325325

326326
.. literalinclude:: time/031.php
327327

328+
addCalendarMonths() / subCalendarMonths()
329+
-----------------------------------------
330+
331+
Modifies the current Time by adding or subtracting whole calendar months. These methods can be useful if you
332+
require no calendar months are skipped in recurring dates. Refer to the table below for a comparison between
333+
``addMonths()`` and ``addCalendarMonths()`` for an initial date of ``2025-01-31``.
334+
335+
======= =========== ===================
336+
$months addMonths() addCalendarMonths()
337+
======= =========== ===================
338+
1 2025-03-03 2025-02-28
339+
2 2025-03-31 2025-03-31
340+
3 2025-05-01 2025-04-30
341+
4 2025-05-31 2025-05-31
342+
5 2025-07-01 2025-06-30
343+
6 2025-07-31 2025-07-31
344+
======= =========== ===================
345+
328346
Comparing Two Times
329347
===================
330348

user_guide_src/source/libraries/time/031.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@
55
$time = $time->addHours(12);
66
$time = $time->addDays(21);
77
$time = $time->addMonths(14);
8+
$time = $time->addCalendarMonths(2);
89
$time = $time->addYears(5);
910

1011
$time = $time->subSeconds(23);
1112
$time = $time->subMinutes(15);
1213
$time = $time->subHours(12);
1314
$time = $time->subDays(21);
1415
$time = $time->subMonths(14);
16+
$time = $time->subCalendarMonths(2);
1517
$time = $time->subYears(5);

0 commit comments

Comments
 (0)