Upstream cakephp/chronos state of the touched files before cdfce65279

This commit is contained in:
upstream committed 2026-09-04 09:47:39 +02:00
commit 760a3e72b1
2 files changed
+961

No files matched your search

+582
View File
@@ -0,0 +1,582 @@
<?php
declare(strict_types=1);
/**
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
* @link https://cakephp.org CakePHP(tm) Project
* @license https://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Cake\Chronos;
use DateTimeImmutable;
use DateTimeInterface;
use DateTimeZone;
use InvalidArgumentException;
use Stringable;
/**
* @phpstan-consistent-constructor
*/
class ChronosTime implements Stringable
{
/**
* @var int
*/
protected const TICKS_PER_MICROSECOND = 1;
/**
* @var int
*/
protected const TICKS_PER_SECOND = 1000000;
/**
* @var int
*/
protected const TICKS_PER_MINUTE = self::TICKS_PER_SECOND * 60;
/**
* @var int
*/
protected const TICKS_PER_HOUR = self::TICKS_PER_MINUTE * 60;
/**
* @var int
*/
protected const TICKS_PER_DAY = self::TICKS_PER_HOUR * 24;
/**
* Default format to use for __toString method.
*
* @var string
*/
public const DEFAULT_TO_STRING_FORMAT = 'H:i:s';
/**
* Format to use for __toString method.
*/
protected static string $toStringFormat = self::DEFAULT_TO_STRING_FORMAT;
protected int $ticks;
/**
* Copies time from onther instance or from time string in the format HH[:.]mm or HH[:.]mm[:.]ss.u.
*
* Defaults to server time.
*
* @param \Cake\Chronos\ChronosTime|\DateTimeInterface|string|null $time Time
* @param \DateTimeZone|string|null $timezone The timezone to use for now
*/
public function __construct(
ChronosTime|DateTimeInterface|string|null $time = null,
DateTimeZone|string|null $timezone = null,
) {
if ($time === null) {
$time = Chronos::getTestNow() ?? Chronos::now();
if ($timezone !== null) {
$time = $time->setTimezone($timezone);
}
$this->ticks = static::parseString($time->format('H:i:s.u'));
} elseif (is_string($time)) {
$this->ticks = static::parseString($time);
} elseif ($time instanceof ChronosTime) {
$this->ticks = $time->ticks;
} else {
$this->ticks = static::parseString($time->format('H:i:s.u'));
}
}
/**
* Copies time from onther instance or from string in the format HH[:.]mm or HH[:.]mm[:.]ss.u
*
* Defaults to server time.
*
* @param \Cake\Chronos\ChronosTime|\DateTimeInterface|string $time Time
* @param \DateTimeZone|string|null $timezone The timezone to use for now
* @return static
*/
public static function parse(
ChronosTime|DateTimeInterface|string|null $time = null,
DateTimeZone|string|null $timezone = null,
): static {
return new static($time, $timezone);
}
/**
* @param string $time Time string in the format HH[:.]mm or HH[:.]mm[:.]ss.u
* @return int
*/
protected static function parseString(string $time): int
{
if (!preg_match('/^\s*(\d{1,2})[:.](\d{1,2})(?|[:.](\d{1,2})[.](\d+)|[:.](\d{1,2}))?\s*$/', $time, $matches)) {
throw new InvalidArgumentException(
sprintf('Time string `%s` is not in expected format `HH[:.]mm` or `HH[:.]mm[:.]ss.u`.', $time),
);
}
$hours = (int)$matches[1];
$minutes = (int)$matches[2];
$seconds = (int)($matches[3] ?? 0);
$microseconds = (int)substr($matches[4] ?? '', 0, 6);
if ($hours > 24 || $minutes > 59 || $seconds > 59 || $microseconds > 999_999) {
throw new InvalidArgumentException(sprintf('Time string `%s` contains invalid values.', $time));
}
$ticks = $hours * self::TICKS_PER_HOUR;
$ticks += $minutes * self::TICKS_PER_MINUTE;
$ticks += $seconds * self::TICKS_PER_SECOND;
$ticks += $microseconds * self::TICKS_PER_MICROSECOND;
return $ticks % self::TICKS_PER_DAY;
}
/**
* Returns instance set to server time.
*
* @param \DateTimeZone|string|null $timezone The timezone to use for now
* @return static
*/
public static function now(DateTimeZone|string|null $timezone = null): static
{
return new static(null, $timezone);
}
/**
* Returns instance set to midnight.
*
* @return static
*/
public static function midnight(): static
{
return new static('00:00:00');
}
/**
* Returns instance set to noon.
*
* @return static
*/
public static function noon(): static
{
return new static('12:00:00');
}
/**
* Returns instance set to end of day - either
* 23:59:59 or 23:59:59.999999 if `$microseconds` is true
*
* @param bool $microseconds Whether to set microseconds or not
* @return static
*/
public static function endOfDay(bool $microseconds = false): static
{
if ($microseconds) {
return new static('23:59:59.999999');
}
return new static('23:59:59');
}
/**
* Returns clock microseconds.
*
* @return int
*/
public function getMicroseconds(): int
{
return intdiv($this->ticks % self::TICKS_PER_SECOND, self::TICKS_PER_MICROSECOND);
}
/**
* Sets clock microseconds.
*
* @param int $microseconds Clock microseconds
* @return static
*/
public function setMicroseconds(int $microseconds): static
{
$baseTicks = $this->ticks - $this->ticks % self::TICKS_PER_SECOND;
$newTicks = static::mod($baseTicks + $microseconds * self::TICKS_PER_MICROSECOND, self::TICKS_PER_DAY);
$clone = clone $this;
$clone->ticks = $newTicks;
return $clone;
}
/**
* Return clock seconds.
*
* @return int
*/
public function getSeconds(): int
{
$secondsTicks = $this->ticks % self::TICKS_PER_MINUTE - $this->ticks % self::TICKS_PER_SECOND;
return intdiv($secondsTicks, self::TICKS_PER_SECOND);
}
/**
* Set clock seconds.
*
* @param int $seconds Clock seconds
* @return static
*/
public function setSeconds(int $seconds): static
{
$baseTicks = $this->ticks - ($this->ticks % self::TICKS_PER_MINUTE - $this->ticks % self::TICKS_PER_SECOND);
$newTicks = static::mod($baseTicks + $seconds * self::TICKS_PER_SECOND, self::TICKS_PER_DAY);
$clone = clone $this;
$clone->ticks = $newTicks;
return $clone;
}
/**
* Returns clock minutes.
*
* @return int
*/
public function getMinutes(): int
{
$minutesTicks = $this->ticks % self::TICKS_PER_HOUR - $this->ticks % self::TICKS_PER_MINUTE;
return intdiv($minutesTicks, self::TICKS_PER_MINUTE);
}
/**
* Set clock minutes.
*
* @param int $minutes Clock minutes
* @return static
*/
public function setMinutes(int $minutes): static
{
$baseTicks = $this->ticks - ($this->ticks % self::TICKS_PER_HOUR - $this->ticks % self::TICKS_PER_MINUTE);
$newTicks = static::mod($baseTicks + $minutes * self::TICKS_PER_MINUTE, self::TICKS_PER_DAY);
$clone = clone $this;
$clone->ticks = $newTicks;
return $clone;
}
/**
* Returns clock hours.
*
* @return int
*/
public function getHours(): int
{
$hoursInTicks = $this->ticks - $this->ticks % self::TICKS_PER_HOUR;
return intdiv($hoursInTicks, self::TICKS_PER_HOUR);
}
/**
* Set clock hours.
*
* @param int $hours Clock hours
* @return static
*/
public function setHours(int $hours): static
{
$baseTicks = $this->ticks - ($this->ticks - $this->ticks % self::TICKS_PER_HOUR);
$newTicks = static::mod($baseTicks + $hours * self::TICKS_PER_HOUR, self::TICKS_PER_DAY);
$clone = clone $this;
$clone->ticks = $newTicks;
return $clone;
}
/**
* Sets clock time.
*
* @param int $hours Clock hours
* @param int $minutes Clock minutes
* @param int $seconds Clock seconds
* @param int $microseconds Clock microseconds
* @return static
*/
public function setTime(int $hours = 0, int $minutes = 0, int $seconds = 0, int $microseconds = 0): static
{
$ticks = $hours * self::TICKS_PER_HOUR +
$minutes * self::TICKS_PER_MINUTE +
$seconds * self::TICKS_PER_SECOND +
$microseconds * self::TICKS_PER_MICROSECOND;
$ticks = static::mod($ticks, self::TICKS_PER_DAY);
$clone = clone $this;
$clone->ticks = $ticks;
return $clone;
}
/**
* Resets time to the start of the current hour.
*
* @return static
*/
public function startOfHour(): static
{
$hourTicks = $this->ticks - $this->ticks % self::TICKS_PER_HOUR;
$clone = clone $this;
$clone->ticks = $hourTicks;
return $clone;
}
/**
* Sets time to the end of the current hour.
*
* @return static
*/
public function endOfHour(): static
{
$hourTicks = $this->ticks - $this->ticks % self::TICKS_PER_HOUR;
$endTicks = $hourTicks + self::TICKS_PER_HOUR - 1;
$clone = clone $this;
$clone->ticks = $endTicks;
return $clone;
}
/**
* @param int $a Left side
* @param int $a Right side
* @return int
*/
protected static function mod(int $a, int $b): int
{
if ($a < 0) {
return $a % $b + $b;
}
return $a % $b;
}
/**
* Formats string using the same syntax as `DateTimeImmutable::format()`.
*
* As this uses DateTimeImmutable::format() to format the string, non-time formatters
* will still be interpreted. Be sure to escape those characters first.
*
* @param string $format Format string
* @return string
*/
public function format(string $format): string
{
return $this->toDateTimeImmutable()->format($format);
}
/**
* Reset the format used to the default when converting to a string
*
* @return void
*/
public static function resetToStringFormat(): void
{
static::setToStringFormat(static::DEFAULT_TO_STRING_FORMAT);
}
/**
* Set the default format used when converting to a string
*
* @param string $format The format to use in future __toString() calls.
* @return void
*/
public static function setToStringFormat(string $format): void
{
static::$toStringFormat = $format;
}
/**
* Format the instance as a string using the set format
*
* @return string
*/
public function __toString(): string
{
return $this->format(static::$toStringFormat);
}
/**
* Returns whether time is equal to target time.
*
* @param \Cake\Chronos\ChronosTime $target Target time
* @return bool
*/
public function equals(ChronosTime $target): bool
{
return $this->ticks === $target->ticks;
}
/**
* Returns whether time is greater than target time.
*
* @param \Cake\Chronos\ChronosTime $target Target time
* @return bool
*/
public function greaterThan(ChronosTime $target): bool
{
return $this->ticks > $target->ticks;
}
/**
* Returns whether time is greater than or equal to target time.
*
* @param \Cake\Chronos\ChronosTime $target Target time
* @return bool
*/
public function greaterThanOrEquals(ChronosTime $target): bool
{
return $this->ticks >= $target->ticks;
}
/**
* Returns whether time is less than target time.
*
* @param \Cake\Chronos\ChronosTime $target Target time
* @return bool
*/
public function lessThan(ChronosTime $target): bool
{
return $this->ticks < $target->ticks;
}
/**
* Returns whether time is less than or equal to target time.
*
* @param \Cake\Chronos\ChronosTime $target Target time
* @return bool
*/
public function lessThanOrEquals(ChronosTime $target): bool
{
return $this->ticks <= $target->ticks;
}
/**
* Returns whether time is between time range.
*
* @param \Cake\Chronos\ChronosTime $start Start of target range
* @param \Cake\Chronos\ChronosTime $end End of target range
* @param bool $equals Whether to include the beginning and end of range
* @return bool
*/
public function between(ChronosTime $start, ChronosTime $end, bool $equals = true): bool
{
if ($start->greaterThan($end)) {
[$start, $end] = [$end, $start];
}
if ($equals) {
return $this->greaterThanOrEquals($start) && $this->lessThanOrEquals($end);
}
return $this->greaterThan($start) && $this->lessThan($end);
}
/**
* Returns whether time is start of day.
*
* @return bool
*/
public function isStartOfDay(): bool
{
return $this->ticks === 0;
}
/**
* Returns whether time is end of day.
*
* Compares against 23:59:59, ignoring microseconds.
*
* @return bool
*/
public function isEndOfDay(): bool
{
$endOfDayTicks = 23 * self::TICKS_PER_HOUR
+ 59 * self::TICKS_PER_MINUTE
+ 59 * self::TICKS_PER_SECOND;
$ticksWithoutMicroseconds = $this->ticks - $this->ticks % self::TICKS_PER_SECOND;
return $ticksWithoutMicroseconds === $endOfDayTicks;
}
/**
* Returns whether time is midnight.
*
* @return bool
*/
public function isMidnight(): bool
{
return $this->isStartOfDay();
}
/**
* Returns whether time is midday.
*
* @return bool
*/
public function isMidday(): bool
{
return $this->ticks === 12 * self::TICKS_PER_HOUR;
}
/**
* Returns an `DateTimeImmutable` instance set to this clock time.
*
* @param \DateTimeZone|string|null $timezone Time zone the DateTimeImmutable instance will be in
* @return \DateTimeImmutable
*/
public function toDateTimeImmutable(DateTimeZone|string|null $timezone = null): DateTimeImmutable
{
$timezone = is_string($timezone) ? new DateTimeZone($timezone) : $timezone;
return (new DateTimeImmutable(timezone: $timezone))->setTime(
$this->getHours(),
$this->getMinutes(),
$this->getSeconds(),
$this->getMicroseconds(),
);
}
/**
* Returns an `DateTimeImmutable` instance set to this clock time.
*
* Alias of `toDateTimeImmutable()`.
*
* @param \DateTimeZone|string|null $timezone Time zone the DateTimeImmutable instance will be in
* @return \DateTimeImmutable
*/
public function toNative(DateTimeZone|string|null $timezone = null): DateTimeImmutable
{
return $this->toDateTimeImmutable($timezone);
}
/**
* Returns the time as an associative array.
*
* @return array{hour: int, minute: int, second: int, microsecond: int}
*/
public function toArray(): array
{
return [
'hour' => $this->getHours(),
'minute' => $this->getMinutes(),
'second' => $this->getSeconds(),
'microsecond' => $this->getMicroseconds(),
];
}
}
+379
View File
@@ -0,0 +1,379 @@
<?php
declare(strict_types=1);
/**
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
* @link https://cakephp.org CakePHP(tm) Project
* @license https://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Cake\Chronos\Test\TestCase;
use Cake\Chronos\Chronos;
use Cake\Chronos\ChronosTime;
use DateTimeImmutable;
use InvalidArgumentException;
class ChronosTimeTest extends TestCase
{
public function testConstructNow(): void
{
Chronos::setTestNow('2001-01-01 12:13:14.123456');
$t = new ChronosTime();
$this->assertSame('12:13:14.123456', $t->format('H:i:s.u'));
$t = new ChronosTime();
$this->assertSame('12:13:14.123456', $t->format('H:i:s.u'));
}
public function testConstructFromString(): void
{
$t = new ChronosTime('12:13');
$this->assertSame('12:13:00.000000', $t->format('H:i:s.u'));
$t = new ChronosTime('0.0.0.0');
$this->assertSame('00:00:00.000000', $t->format('H:i:s.u'));
$t = new ChronosTime('1:01:1.000001');
$this->assertSame('01:01:01.000001', $t->format('H:i:s.u'));
$t = new ChronosTime('23:59.59.999999');
$this->assertSame('23:59:59.999999', $t->format('H:i:s.u'));
$t = new ChronosTime('23:59.59.9999991');
$this->assertSame('23:59:59.999999', $t->format('H:i:s.u'));
$t = new ChronosTime('24:59.59.9999991');
$this->assertSame('00:59:59.999999', $t->format('H:i:s.u'));
}
public function testConstructFromInstance(): void
{
$t = new ChronosTime(new DateTimeImmutable('23:59:59.999999'));
$this->assertSame('23:59:59.999999', $t->format('H:i:s.u'));
$t = new ChronosTime(new Chronos('23:59:59.999999'));
$this->assertSame('23:59:59.999999', $t->format('H:i:s.u'));
$t = new ChronosTime(new ChronosTime(new Chronos('23:59:59.999999')));
$this->assertSame('23:59:59.999999', $t->format('H:i:s.u'));
}
public function testConstructInvalid(): void
{
$this->expectException(InvalidArgumentException::class);
new ChronosTime('tomorrow');
}
public function testConstructIncomplete(): void
{
$this->expectException(InvalidArgumentException::class);
new ChronosTime('23');
}
public function testConstructInvalidHours(): void
{
$this->expectException(InvalidArgumentException::class);
new ChronosTime('25:00:00');
}
public function testConstructInvalidMinutes(): void
{
$this->expectException(InvalidArgumentException::class);
new ChronosTime('23:60:00');
}
public function testConstructInvalidSeconds(): void
{
$this->expectException(InvalidArgumentException::class);
new ChronosTime('23:59:60');
}
public function testParse(): void
{
$t = ChronosTime::parse('23:59:59.999999');
$this->assertSame('23:59:59.999999', $t->format('H:i:s.u'));
Chronos::setTestNow(new Chronos('2001-01-01 12:13:14.123456', 'America/Chicago'));
$t = ChronosTime::parse(null, 'America/New_York');
$this->assertSame('13:13:14.123456', $t->format('H:i:s.u'));
}
public function testNow(): void
{
Chronos::setTestNow(new Chronos('2001-01-01 12:13:14.123456', 'America/Chicago'));
$t = ChronosTime::now();
$this->assertSame('12:13:14.123456', $t->format('H:i:s.u'));
$t = ChronosTime::now('America/New_York');
$this->assertSame('13:13:14.123456', $t->format('H:i:s.u'));
}
public function testMidnight(): void
{
$t = ChronosTime::midnight();
$this->assertSame('00:00:00.000000', $t->format('H:i:s.u'));
}
public function testNoon(): void
{
$t = ChronosTime::noon();
$this->assertSame('12:00:00.000000', $t->format('H:i:s.u'));
}
public function testEndOfDay(): void
{
$t = ChronosTime::endOfDay();
$this->assertSame('23:59:59.000000', $t->format('H:i:s.u'));
$t = ChronosTime::endOfDay(microseconds: true);
$this->assertSame('23:59:59.999999', $t->format('H:i:s.u'));
}
public function testSetters(): void
{
$t = ChronosTime::midnight()->setHours(24);
$this->assertSame('00:00:00.000000', $t->format('H:i:s.u'));
$t = ChronosTime::midnight()->setHours(-1);
$this->assertSame('23:00:00.000000', $t->format('H:i:s.u'));
$t = ChronosTime::midnight()->setMinutes(60);
$this->assertSame('01:00:00.000000', $t->format('H:i:s.u'));
$t = ChronosTime::midnight()->setMinutes(-1);
$this->assertSame('23:59:00.000000', $t->format('H:i:s.u'));
$t = ChronosTime::midnight()->setSeconds(60);
$this->assertSame('00:01:00.000000', $t->format('H:i:s.u'));
$t = ChronosTime::midnight()->setSeconds(-1);
$this->assertSame('23:59:59.000000', $t->format('H:i:s.u'));
$t = ChronosTime::midnight()->setMicroseconds(1_000_000);
$this->assertSame('00:00:01.000000', $t->format('H:i:s.u'));
$t = ChronosTime::midnight()->setMicroseconds(-1);
$this->assertSame('23:59:59.999999', $t->format('H:i:s.u'));
$t = ChronosTime::midnight()->setHours(25)->setMinutes(120)->setSeconds(120)->setMicroseconds(2_000_001);
$this->assertSame('03:02:02.000001', $t->format('H:i:s.u'));
}
public function testGetters(): void
{
$t = ChronosTime::midnight()->setTime(-1, -1, -1, -1);
$this->assertSame(22, $t->getHours());
$this->assertSame(58, $t->getMinutes());
$this->assertSame(58, $t->getSeconds());
$this->assertSame(999_999, $t->getMicroseconds());
}
public function testSetTime(): void
{
$t = new ChronosTime();
$new = $t->setTime();
$this->assertNotSame($new, $t);
$this->assertSame('00:00:00.000000', $new->format('H:i:s.u'));
$t = ChronosTime::midnight()->setTime(24, 120, 120, 1_000_000);
$this->assertSame('02:02:01.000000', $t->format('H:i:s.u'));
$t = ChronosTime::midnight()->setTime(-1, -1, -1, -1);
$this->assertSame('22:58:58.999999', $t->format('H:i:s.u'));
$t = ChronosTime::midnight()->setTime(-1, 120, -1, 1_000_001);
$this->assertSame('01:00:00.000001', $t->format('H:i:s.u'));
}
public function testStartOfHour(): void
{
$t = ChronosTime::parse('12:30:45.123456');
$start = $t->startOfHour();
$this->assertNotSame($t, $start);
$this->assertSame('12:00:00.000000', $start->format('H:i:s.u'));
$t = ChronosTime::parse('00:59:59.999999');
$this->assertSame('00:00:00.000000', $t->startOfHour()->format('H:i:s.u'));
$t = ChronosTime::parse('23:01:01');
$this->assertSame('23:00:00.000000', $t->startOfHour()->format('H:i:s.u'));
}
public function testEndOfHour(): void
{
$t = ChronosTime::parse('12:30:45.123456');
$end = $t->endOfHour();
$this->assertNotSame($t, $end);
$this->assertSame('12:59:59.999999', $end->format('H:i:s.u'));
$t = ChronosTime::parse('00:00:00');
$this->assertSame('00:59:59.999999', $t->endOfHour()->format('H:i:s.u'));
$t = ChronosTime::parse('23:30:00');
$this->assertSame('23:59:59.999999', $t->endOfHour()->format('H:i:s.u'));
}
public function testFormat(): void
{
$t = new ChronosTime('23:59:59.999999');
$this->assertSame('23:59:59.999999', $t->format('H:i:s.u'));
}
public function testComparisons(): void
{
$t1 = ChronosTime::parse('00:00:00');
$t2 = ChronosTime::parse('00:00:00');
$this->assertTrue($t1->equals($t2));
$this->assertTrue($t1->greaterThanOrEquals($t2));
$this->assertTrue($t1->lessThanOrEquals($t2));
$this->assertFalse($t1->greaterThan($t2));
$this->assertFalse($t1->lessThan($t2));
$t1 = ChronosTime::parse('00:00:00');
$t2 = ChronosTime::parse('00:00:00')->setHours(24);
$this->assertTrue($t1->equals($t2));
$this->assertTrue($t1->greaterThanOrEquals($t2));
$this->assertTrue($t1->lessThanOrEquals($t2));
$this->assertFalse($t1->greaterThan($t2));
$this->assertFalse($t1->lessThan($t2));
$t1 = ChronosTime::parse('00:00:00');
$t2 = ChronosTime::parse('00:00:00.000001');
$this->assertTrue($t1->lessThan($t2));
$this->assertTrue($t1->lessThanOrEquals($t2));
$this->assertFalse($t1->equals($t2));
$this->assertFalse($t1->greaterThan($t2));
$this->assertFalse($t1->greaterThanOrEquals($t2));
$t1 = ChronosTime::parse('00:00:00.000001');
$t2 = ChronosTime::parse('00:00:00');
$this->assertTrue($t1->greaterThan($t2));
$this->assertTrue($t1->greaterThanOrEquals($t2));
$this->assertFalse($t1->equals($t2));
$this->assertFalse($t1->lessThan($t2));
$this->assertFalse($t1->lessThanOrEquals($t2));
$t1 = ChronosTime::parse('00:00:00.000001');
$t2 = ChronosTime::parse('00:00:00.000002');
$t3 = ChronosTime::parse('00:00:00.000003');
$this->assertTrue($t2->between($t1, $t3));
$t1 = ChronosTime::parse('00:00:00.000001');
$t2 = ChronosTime::parse('00:00:00.000002');
$t3 = ChronosTime::parse('00:00:00.000003');
$this->assertTrue($t2->between($t1, $t3, false));
$t1 = ChronosTime::parse('00:00:00.000001');
$t2 = ChronosTime::parse('00:00:00.000002');
$t3 = ChronosTime::parse('00:00:00.000003');
$this->assertTrue($t1->between($t1, $t3, true));
$t1 = ChronosTime::parse('00:00:00.000001');
$t2 = ChronosTime::parse('00:00:00.000002');
$t3 = ChronosTime::parse('00:00:00.000003');
$this->assertFalse($t1->between($t1, $t3, false));
$t1 = ChronosTime::parse('00:00:00.000001');
$t2 = ChronosTime::parse('00:00:00.000002');
$t3 = ChronosTime::parse('00:00:00.000003');
$this->assertTrue($t2->between($t3, $t1, false));
$t1 = ChronosTime::parse('00:00:00.000001');
$t2 = ChronosTime::parse('00:00:00.000002');
$t3 = ChronosTime::parse('00:00:00.000003');
$this->assertFalse($t1->between($t2, $t3));
$t1 = ChronosTime::parse('00:00:00.000001');
$t2 = ChronosTime::parse('00:00:00.000002');
$t3 = ChronosTime::parse('00:00:00.000003');
$this->assertFalse($t3->between($t1, $t2));
}
public function testIsStartOfDay(): void
{
$this->assertTrue(ChronosTime::parse('00:00:00')->isStartOfDay());
$this->assertTrue(ChronosTime::midnight()->isStartOfDay());
$this->assertFalse(ChronosTime::parse('00:00:00.000001')->isStartOfDay());
$this->assertFalse(ChronosTime::parse('00:00:01')->isStartOfDay());
$this->assertFalse(ChronosTime::noon()->isStartOfDay());
}
public function testIsEndOfDay(): void
{
$this->assertTrue(ChronosTime::parse('23:59:59')->isEndOfDay());
$this->assertTrue(ChronosTime::endOfDay()->isEndOfDay());
$this->assertTrue(ChronosTime::parse('23:59:59.999999')->isEndOfDay());
$this->assertFalse(ChronosTime::parse('23:59:58')->isEndOfDay());
$this->assertFalse(ChronosTime::midnight()->isEndOfDay());
$this->assertFalse(ChronosTime::noon()->isEndOfDay());
}
public function testIsMidnight(): void
{
$this->assertTrue(ChronosTime::midnight()->isMidnight());
$this->assertTrue(ChronosTime::parse('00:00:00')->isMidnight());
$this->assertFalse(ChronosTime::parse('00:00:00.000001')->isMidnight());
$this->assertFalse(ChronosTime::noon()->isMidnight());
}
public function testIsMidday(): void
{
$this->assertTrue(ChronosTime::noon()->isMidday());
$this->assertTrue(ChronosTime::parse('12:00:00')->isMidday());
$this->assertFalse(ChronosTime::parse('12:00:00.000001')->isMidday());
$this->assertFalse(ChronosTime::parse('12:00:01')->isMidday());
$this->assertFalse(ChronosTime::midnight()->isMidday());
}
public function testToDateTimeImmutable(): void
{
$time = ChronosTime::parse('23:59:59.999999');
$native = $time->toDateTimeImmutable();
$this->assertSame('23:59:59.999999', $native->format('H:i:s.u'));
$native = $time->toNative();
$this->assertSame('23:59:59.999999', $native->format('H:i:s.u'));
$native = $time->toDateTimeImmutable('Asia/Tokyo');
$this->assertSame('23:59:59.999999', $native->format('H:i:s.u'));
$this->assertSame('Asia/Tokyo', $native->getTimezone()->getName());
$native = $time->toNative('Asia/Tokyo');
$this->assertSame('23:59:59.999999', $native->format('H:i:s.u'));
$this->assertSame('Asia/Tokyo', $native->getTimezone()->getName());
}
public function testToString(): void
{
$t = new ChronosTime('12:13:14.123456');
$this->assertSame('12:13:14', (string)$t);
ChronosTime::setToStringFormat('H:i:s.u');
$this->assertSame('12:13:14.123456', (string)$t);
ChronosTime::resetToStringFormat();
$this->assertSame('12:13:14', (string)$t);
}
public function testToArray(): void
{
$t = new ChronosTime('12:30:45.123456');
$array = $t->toArray();
$this->assertSame(12, $array['hour']);
$this->assertSame(30, $array['minute']);
$this->assertSame(45, $array['second']);
$this->assertSame(123456, $array['microsecond']);
$this->assertCount(4, $array);
}
}