diff --git a/src/main/php/util/TimeSpan.class.php b/src/main/php/util/TimeSpan.class.php index 98b1fe72b..0ba514666 100755 --- a/src/main/php/util/TimeSpan.class.php +++ b/src/main/php/util/TimeSpan.class.php @@ -1,27 +1,48 @@ getName()); + public function __construct($arg) { + if (is_numeric($arg)) { + $this->_seconds= (int)abs($arg); + } else { + try { + if ($arg instanceof DateInterval) { + $i= $arg; + } else if ('P' === $arg[0] ?? null) { + $i= new DateInterval($arg); + } else { + $i= DateInterval::createFromDateString($arg); + } + } catch (Exception $e) { + throw new IllegalArgumentException('Invalid time span '.Objects::stringOf($arg), $e); + } + + // PHP < 8.3 returns false for invalid time spans + if (false === $i) throw new IllegalArgumentException('Invalid time span '.Objects::stringOf($arg)); + + // Years and months do not have a constant amount of seconds. Technically, days + // don't either (think: leap seconds), but we'll handle them as 86400 seconds + if ($i->y || $i->m) throw new IllegalArgumentException('Cannot create from interval with years / months'); + + $this->_seconds= $i->d * 86400 + $i->h * 3600 + $i->i * 60 + $i->s; } - $this->_seconds= (int)abs($secs); } /** diff --git a/src/test/php/util/unittest/TimeSpanTest.class.php b/src/test/php/util/unittest/TimeSpanTest.class.php index ae8212ba5..828fff923 100755 --- a/src/test/php/util/unittest/TimeSpanTest.class.php +++ b/src/test/php/util/unittest/TimeSpanTest.class.php @@ -1,24 +1,35 @@ toString()); + #[Test, Values([7265, 7265.0, 'PT2H1M5S', '2 hours 1 minute 5 seconds'])] + public function span_from($arg) { + Assert::equals('0d, 2h, 1m, 5s', (new TimeSpan($arg))->toString()); } #[Test] - public function newNegativeTimeSpan() { + public function negative_span() { Assert::equals('0d, 0h, 0m, 1s', (new TimeSpan(-1))->toString()); } - #[Test, Expect(IllegalArgumentException::class)] - public function wrongArguments() { - new TimeSpan('2 days'); + #[Test, Expect(IllegalArgumentException::class), Values([null, '', 'not a time span', false, true])] + public function invalid_string_argument($arg) { + new TimeSpan($arg); + } + + #[Test, Expect(IllegalArgumentException::class), Values(['P1Y', 'P1M'])] + public function unsupported_dateinterval($arg) { + new TimeSpan(new DateInterval($arg)); + } + + #[Test] + public function span_from_dateinterval() { + Assert::equals('1d, 2h, 0m, 0s', (new TimeSpan(new DateInterval('P1DT2H')))->toString()); } #[Test] @@ -33,12 +44,13 @@ public function add() { public function subtract() { Assert::equals('0d, 22h, 58m, 55s', (new TimeSpan(86400)) ->substract(new TimeSpan(3600), new TimeSpan(60)) - ->substract(new TimeSpan(5))->toString() + ->substract(new TimeSpan(5)) + ->toString() ); } #[Test] - public function subtractToZero() { + public function subtract_resulting_in_zero() { Assert::equals( '0d, 0h, 0m, 0s', (new TimeSpan(6100))->substract(new TimeSpan(6100))->toString() @@ -46,50 +58,51 @@ public function subtractToZero() { } #[Test, Expect(IllegalStateException::class)] - public function subtractToNegative() { + public function subtract_may_not_result_in_negative_values() { (new TimeSpan(0))->substract(new TimeSpan(1)); } #[Test] - public function addAndSubstract() { + public function add_and_subtract() { Assert::equals('1d, 1h, 0m, 55s', (new TimeSpan(86400)) ->add(new TimeSpan(3600), new TimeSpan(60)) - ->substract(new TimeSpan(5))->toString() + ->substract(new TimeSpan(5)) + ->toString() ); } #[Test, Expect(IllegalArgumentException::class)] - public function addWrongArguments() { + public function incorrect_argument_to_add() { (new TimeSpan(0))->add('2 days'); } #[Test] - public function fromSeconds() { + public function from_seconds() { Assert::equals('0d, 1h, 0m, 0s', TimeSpan::seconds(3600)->toString()); } #[Test] - public function fromMinutes() { + public function from_minutes() { Assert::equals('0d, 2h, 7m, 0s', TimeSpan::minutes(127)->toString()); } #[Test] - public function fromHours() { + public function from_hours() { Assert::equals('1d, 3h, 0m, 0s', TimeSpan::hours(27)->toString()); } #[Test] - public function fromDays() { + public function from_days() { Assert::equals('40d, 0h, 0m, 0s', TimeSpan::days(40)->toString()); } #[Test] - public function fromWeeks() { + public function from_weeks() { Assert::equals('7d, 0h, 0m, 0s', TimeSpan::weeks(1)->toString()); } #[Test] - public function wholeValues() { + public function whole_values() { $t= new TimeSpan(91865); Assert::equals(5, $t->getWholeSeconds(), 'wholeSeconds'); Assert::equals(31, $t->getWholeMinutes(), 'wholeMinutes'); @@ -98,77 +111,77 @@ public function wholeValues() { } #[Test] - public function formatSeconds() { + public function format_seconds() { Assert::equals('91865', (new TimeSpan(91865))->format('%s')); } #[Test] - public function formatWholeSeconds() { + public function format_whole_seconds() { Assert::equals('5', (new TimeSpan(91865))->format('%w')); } #[Test] - public function formatMinutes() { + public function format_minutes() { Assert::equals('1531', (new TimeSpan(91865))->format('%m')); } #[Test] - public function formatFloatMinutes() { + public function format_float_minutes() { Assert::equals('1531.08', (new TimeSpan(91865))->format('%M')); } #[Test] - public function formatWholeMinutes() { + public function format_whole_minutes() { Assert::equals('31', (new TimeSpan(91865))->format('%j')); } #[Test] - public function formatHours() { + public function format_hours() { Assert::equals('25', (new TimeSpan(91865))->format('%h')); } #[Test] - public function formatFloatHours() { + public function format_float_hours() { Assert::equals('25.52', (new TimeSpan(91865))->format('%H')); } #[Test] - public function formatWholeHours() { + public function format_whole_hours() { Assert::equals('1', (new TimeSpan(91865))->format('%y')); } #[Test] - public function formatDays() { + public function format_days() { Assert::equals('1', (new TimeSpan(91865))->format('%d')); } #[Test] - public function formatFloatDays() { + public function format_float_days() { Assert::equals('1.06', (new TimeSpan(91865))->format('%D')); } #[Test] - public function formatWholeDays() { + public function format_whole_days() { Assert::equals('1', (new TimeSpan(91865))->format('%e')); } #[Test] - public function format() { + public function format_() { Assert::equals('1d1h', (new TimeSpan(91865))->format('%ed%yh')); } #[Test] - public function formatPercent() { + public function format_percent() { Assert::equals('%1d%1h%', (new TimeSpan(91865))->format('%%%ed%%%yh%%')); } #[Test] - public function compareTwoEqualInstances() { + public function compare_two_equal_instances() { Assert::equals(new TimeSpan(3600), new TimeSpan(3600)); } #[Test] - public function compareTwoUnequalInstances() { + public function compare_two_differing_instances() { Assert::notEquals(new TimeSpan(3600), new TimeSpan(0)); } } \ No newline at end of file