Skip to content

Commit 8480b79

Browse files
patel-vanshCopilot
andcommitted
feat: Add clamp() method in TimeTrait with docs and tests
Co-authored-by: Copilot <[email protected]>
1 parent 2db0ed7 commit 8480b79

7 files changed

Lines changed: 114 additions & 19 deletions

File tree

system/I18n/Exceptions/I18nException.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,4 +96,14 @@ public static function forInvalidSeconds(string $seconds)
9696
{
9797
return new static(lang('Time.invalidSeconds', [$seconds]));
9898
}
99+
100+
/**
101+
* Thrown when the supplied clamp range is invalid.
102+
*
103+
* @return static
104+
*/
105+
public static function forInvalidClampRange(string $start, string $end)
106+
{
107+
return new static(lang('Time.invalidClampRange', [$start, $end]));
108+
}
99109
}

system/I18n/TimeTrait.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -862,6 +862,32 @@ public function subYears(int $years)
862862
return $time->sub(DateInterval::createFromDateString("{$years} years"));
863863
}
864864

865+
/**
866+
* Returns a new Time instance with the time clamped between the two provided times.
867+
* If the current instance is before the $start time, a new instance will be returned with the same time as $start.
868+
* If the current instance is after the $end time, a new instance will be returned with the same time as $end.
869+
* Otherwise, the current instance will be returned.
870+
*/
871+
public function clamp(DateTimeInterface|self|string $start, DateTimeInterface|self|string $end): static
872+
{
873+
$start = $start instanceof DateTimeInterface ? $start : new static($start, $this->timezone, $this->locale);
874+
$end = $end instanceof DateTimeInterface ? $end : new static($end, $this->timezone, $this->locale);
875+
876+
if ($end->isBefore($start)) {
877+
throw I18nException::forInvalidClampRange($start->toDateTimeString(), $end->toDateTimeString());
878+
}
879+
880+
if ($this->isBefore($start)) {
881+
return static::createFromInstance($start, $this->locale);
882+
}
883+
884+
if ($this->isAfter($end)) {
885+
return static::createFromInstance($end, $this->locale);
886+
}
887+
888+
return $this;
889+
}
890+
865891
// --------------------------------------------------------------------
866892
// Formatters
867893
// --------------------------------------------------------------------

system/Language/en/Time.php

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,23 +13,24 @@
1313

1414
// Time language settings
1515
return [
16-
'invalidFormat' => '"{0}" is not a valid datetime format',
17-
'invalidMonth' => 'Months must be between 1 and 12. Given: {0}',
18-
'invalidDay' => 'Days must be between 1 and 31. Given: {0}',
19-
'invalidOverDay' => 'Days must be between 1 and {0}. Given: {1}',
20-
'invalidHours' => 'Hours must be between 0 and 23. Given: {0}',
21-
'invalidMinutes' => 'Minutes must be between 0 and 59. Given: {0}',
22-
'invalidSeconds' => 'Seconds must be between 0 and 59. Given: {0}',
23-
'years' => '{0, plural, =1{# year} other{# years}}',
24-
'months' => '{0, plural, =1{# month} other{# months}}',
25-
'weeks' => '{0, plural, =1{# week} other{# weeks}}',
26-
'days' => '{0, plural, =1{# day} other{# days}}',
27-
'hours' => '{0, plural, =1{# hour} other{# hours}}',
28-
'minutes' => '{0, plural, =1{# minute} other{# minutes}}',
29-
'seconds' => '{0, plural, =1{# second} other{# seconds}}',
30-
'ago' => '{0} ago',
31-
'inFuture' => 'in {0}',
32-
'yesterday' => 'Yesterday',
33-
'tomorrow' => 'Tomorrow',
34-
'now' => 'Just now',
16+
'invalidFormat' => '"{0}" is not a valid datetime format',
17+
'invalidMonth' => 'Months must be between 1 and 12. Given: {0}',
18+
'invalidDay' => 'Days must be between 1 and 31. Given: {0}',
19+
'invalidOverDay' => 'Days must be between 1 and {0}. Given: {1}',
20+
'invalidHours' => 'Hours must be between 0 and 23. Given: {0}',
21+
'invalidMinutes' => 'Minutes must be between 0 and 59. Given: {0}',
22+
'invalidSeconds' => 'Seconds must be between 0 and 59. Given: {0}',
23+
'invalidClampRange' => 'The start time "{0}" must be earlier than or equal to the end time "{1}".',
24+
'years' => '{0, plural, =1{# year} other{# years}}',
25+
'months' => '{0, plural, =1{# month} other{# months}}',
26+
'weeks' => '{0, plural, =1{# week} other{# weeks}}',
27+
'days' => '{0, plural, =1{# day} other{# days}}',
28+
'hours' => '{0, plural, =1{# hour} other{# hours}}',
29+
'minutes' => '{0, plural, =1{# minute} other{# minutes}}',
30+
'seconds' => '{0, plural, =1{# second} other{# seconds}}',
31+
'ago' => '{0} ago',
32+
'inFuture' => 'in {0}',
33+
'yesterday' => 'Yesterday',
34+
'tomorrow' => 'Tomorrow',
35+
'now' => 'Just now',
3536
];

tests/system/I18n/TimeTest.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -744,6 +744,35 @@ public function testSetTimestampDateTimeImmutable(): void
744744
$this->assertSame('2017-03-31 19:00:00 -05:00', $time2->format('Y-m-d H:i:s P'));
745745
}
746746

747+
public function testClamp(): void
748+
{
749+
$time = Time::parse('May 10, 2017', 'America/Chicago');
750+
$time2 = $time->clamp('2017-05-01', '2017-05-31');
751+
752+
$this->assertInstanceOf(Time::class, $time2);
753+
$this->assertSame($time, $time2);
754+
755+
$time3 = $time->clamp('2017-05-11', '2017-05-31');
756+
757+
$this->assertInstanceOf(Time::class, $time3);
758+
$this->assertNotSame($time, $time3);
759+
$this->assertSame('2017-05-11 00:00:00', $time3->toDateTimeString());
760+
761+
$time4 = $time->clamp('2017-05-01', '2017-05-09');
762+
763+
$this->assertInstanceOf(Time::class, $time4);
764+
$this->assertNotSame($time, $time4);
765+
$this->assertSame('2017-05-09 00:00:00', $time4->toDateTimeString());
766+
}
767+
768+
public function testClampException(): void
769+
{
770+
$this->expectException(I18nException::class);
771+
772+
$time = Time::parse('May 10, 2017', 'America/Chicago');
773+
$time->clamp('2017-05-31', '2017-05-01');
774+
}
775+
747776
public function testToDateString(): void
748777
{
749778
$time = Time::parse('May 10, 2017', 'America/Chicago');

user_guide_src/source/changelogs/v4.8.0.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,7 @@ Others
263263

264264
- **Float and Double Casting:** Added support for precision and rounding mode when casting to float or double in entities.
265265
- Float and Double casting now throws ``CastException::forInvalidFloatRoundingMode()`` if an rounding mode other than up, down, even or odd is provided.
266+
- Added new ``TimeTrait::clamp($min, $max)`` method which returns clamped time between two times. See :ref:`TimeTrait::clamp()`.
266267

267268
***************
268269
Message Changes

user_guide_src/source/libraries/time.rst

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,20 @@ Returns a new instance with the date set to the new timestamp:
317317
.. note:: Prior to v4.6.0, due to a bug, this method might return incorrect
318318
date/time. See :ref:`Upgrading Guide <upgrade-460-time-set-timestamp>` for details.
319319

320+
.. _time-setters-clamp:
321+
322+
clamp()
323+
-------
324+
325+
.. versionadded:: 4.8.0
326+
327+
Returns a new Time instance with the time clamped between the two times passed in.
328+
If the current instance is before the $min time, new instance with $min time will be returned.
329+
If the current instance is after the $max time, new instance with $max time will be returned.
330+
Otherwise, the current instance will be returned.
331+
332+
.. literalinclude:: time/045.php
333+
320334
Modifying the Value
321335
===================
322336

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
use CodeIgniter\I18n\Time;
4+
5+
$time = Time::parse('April 25, 2026 5:46:00pm UTC');
6+
7+
// If the time is between the two times, it will return the time itself.
8+
echo $time->clamp('April 25, 2026 5:00:00pm UTC', 'April 25, 2026 7:00:00pm UTC')->toDateTimeString(); // 2026-04-25 17:46:00
9+
10+
// If the time is before the minimum time, it will return new instance of minimum time.
11+
echo $time->clamp('April 25, 2026 6:05:00pm UTC', 'April 25, 2026 9:20:00pm UTC')->toDateTimeString(); // 2026-04-25 18:05:00
12+
13+
// If the time is after the maximum time, it will return new instance of maximum time.
14+
echo $time->clamp('April 25, 2026 3:40:00pm UTC', 'April 25, 2026 5:00:00pm UTC')->toDateTimeString(); // 2026-04-25 17:00:00

0 commit comments

Comments
 (0)