Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Re-add ChronosDate::now() and other time-relative helpers #353

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 0 additions & 6 deletions phpstan-baseline.neon

This file was deleted.

3 changes: 0 additions & 3 deletions phpstan.neon
@@ -1,6 +1,3 @@
includes:
- phpstan-baseline.neon

parameters:
level: 6
checkMissingIterableValueType: false
Expand Down
19 changes: 15 additions & 4 deletions psalm-baseline.xml
Expand Up @@ -70,22 +70,23 @@
<ImpureStaticVariable occurrences="1"/>
</file>
<file src="src/ChronosDate.php">
<ImpureFunctionCall occurrences="2">
<ImpureFunctionCall occurrences="3">
<code>array_filter</code>
<code>date_default_timezone_get</code>
<code>iterator_to_array</code>
</ImpureFunctionCall>
<ImpureMethodCall occurrences="40">
<ImpureMethodCall occurrences="50">
<code>$period</code>
<code>diffForHumans</code>
<code>diffFormatter</code>
<code>format</code>
<code>getTestNow</code>
<code>getWeekEndsAt</code>
<code>getWeekEndsAt</code>
<code>getWeekStartsAt</code>
<code>getWeekStartsAt</code>
<code>getWeekendDays</code>
<code>hasTestNow</code>
<code>isRelativeOnly</code>
<code>modify</code>
<code>modify</code>
<code>modify</code>
Expand Down Expand Up @@ -114,7 +115,17 @@
<code>now</code>
<code>now</code>
<code>now</code>
<code>stripTime</code>
<code>now</code>
<code>now</code>
<code>now</code>
<code>now</code>
<code>now</code>
<code>now</code>
<code>now</code>
<code>now</code>
<code>now</code>
<code>tomorrow</code>
<code>yesterday</code>
</ImpureMethodCall>
<ImpureStaticProperty occurrences="9">
<code>static::$days</code>
Expand Down
2 changes: 1 addition & 1 deletion src/Chronos.php
Expand Up @@ -240,7 +240,7 @@ protected function createNative(
Chronos|ChronosDate|DateTimeInterface|string|int|null $time,
DateTimeZone|string|null $timezone = null
): DateTimeImmutable {
if (is_int($time)) {
if (is_int($time) || (is_string($time) && ctype_digit($time))) {
return new DateTimeImmutable("@{$time}");
}

Expand Down
201 changes: 190 additions & 11 deletions src/ChronosDate.php
Expand Up @@ -18,6 +18,7 @@
use DatePeriod;
use DateTimeImmutable;
use DateTimeInterface;
use DateTimeZone;
use InvalidArgumentException;

/**
Expand Down Expand Up @@ -90,35 +91,92 @@ class ChronosDate
* subtraction/addition to have deterministic results.
*
* @param \Cake\Chronos\Chronos|\Cake\Chronos\ChronosDate|\DateTimeInterface|string $time Fixed or relative time
* @param \DateTimeZone|string|null $timezone The time zone used for 'now'
*/
public function __construct(Chronos|ChronosDate|DateTimeInterface|string $time)
{
$this->native = $this->createNative($time);
public function __construct(
Chronos|ChronosDate|DateTimeInterface|string $time = 'now',
DateTimeZone|string|null $timezone = null
) {
$this->native = $this->createNative($time, $timezone);
}

/**
* Initializes the PHP DateTimeImmutable object.
*
* @param \Cake\Chronos\Chronos|\Cake\Chronos\ChronosDate|\DateTimeInterface|string|int|null $time Fixed or relative time
* @param \Cake\Chronos\Chronos|\Cake\Chronos\ChronosDate|\DateTimeInterface|string $time Fixed or relative time
* @param \DateTimeZone|string|null $timezone The time zone used for 'now'
* @return \DateTimeImmutable
*/
protected function createNative(Chronos|ChronosDate|DateTimeInterface|string|int|null $time): DateTimeImmutable
{
protected function createNative(
Chronos|ChronosDate|DateTimeInterface|string $time,
DateTimeZone|string|null $timezone
): DateTimeImmutable {
if (!is_string($time)) {
return new DateTimeImmutable($time->format('Y-m-d 00:00:00'));
}

$timezone ??= date_default_timezone_get();
$timezone = $timezone instanceof DateTimeZone ? $timezone : new DateTimeZone($timezone);

$testNow = Chronos::getTestNow();
if ($testNow === null || !static::isRelativeOnly($time)) {
$time = $this->stripTime($time);
if ($testNow === null) {
$time = new DateTimeImmutable($time, $timezone);

return new DateTimeImmutable($time);
return new DateTimeImmutable($time->format('Y-m-d 00:00:00'));
}

$testNow = clone $testNow;
if (!empty($time)) {
$testNow = $testNow->setTimezone($timezone);
if ($time !== 'now') {
$testNow = $testNow->modify($time);
}

return new DateTimeImmutable($testNow->format('Y-m-d 00:00:00'));
}

/**
* Get today's date.
*
* @param \DateTimeZone|string|null $timezone Time zone to use for now.
* @return static
*/
public static function now(DateTimeZone|string|null $timezone = null): static
{
return new static('now', $timezone);
}

/**
* Get today's date.
*
* @param \DateTimeZone|string|null $timezone Time zone to use for now.
* @return static
*/
public static function today(DateTimeZone|string|null $timezone = null): static
{
return static::now($timezone);
}

/**
* Get tomorrow's date.
*
* @param \DateTimeZone|string|null $timezone Time zone to use for now.
* @return static
*/
public static function tomorrow(DateTimeZone|string|null $timezone = null): static
{
return new static('tomorrow', $timezone);
}

/**
* Get yesterday's date.
*
* @param \DateTimeZone|string|null $timezone Time zone to use for now.
* @return static
*/
public static function yesterday(DateTimeZone|string|null $timezone = null): static
{
return new static('yesterday', $timezone);
}

/**
* Create an instance from a string. This is an alias for the
* constructor that allows better fluent syntax as it allows you to do
Expand Down Expand Up @@ -965,6 +1023,127 @@ public function isWeekend(): bool
return in_array($this->dayOfWeek, Chronos::getWeekendDays(), true);
}

/**
* Determines if the instance is yesterday
*
* @param \DateTimeZone|string|null $timezone Time zone to use for now.
* @return bool
*/
public function isYesterday(DateTimeZone|string|null $timezone = null): bool
{
return $this->equals(static::yesterday($timezone));
}

/**
* Determines if the instance is today
*
* @param \DateTimeZone|string|null $timezone Time zone to use for now.
* @return bool
*/
public function isToday(DateTimeZone|string|null $timezone = null): bool
{
return $this->equals(static::now($timezone));
}

/**
* Determines if the instance is tomorrow
*
* @param \DateTimeZone|string|null $timezone Time zone to use for now.
* @return bool
*/
public function isTomorrow(DateTimeZone|string|null $timezone = null): bool
{
return $this->equals(static::tomorrow($timezone));
}

/**
* Determines if the instance is within the next week
*
* @param \DateTimeZone|string|null $timezone Time zone to use for now.
* @return bool
*/
public function isNextWeek(DateTimeZone|string|null $timezone = null): bool
{
return $this->format('W o') === static::now($timezone)->addWeeks(1)->format('W o');
}

/**
* Determines if the instance is within the last week
*
* @param \DateTimeZone|string|null $timezone Time zone to use for now.
* @return bool
*/
public function isLastWeek(DateTimeZone|string|null $timezone = null): bool
{
return $this->format('W o') === static::now($timezone)->subWeeks(1)->format('W o');
}

/**
* Determines if the instance is within the next month
*
* @param \DateTimeZone|string|null $timezone Time zone to use for now.
* @return bool
*/
public function isNextMonth(DateTimeZone|string|null $timezone = null): bool
{
return $this->format('m Y') === static::now($timezone)->addMonths(1)->format('m Y');
}

/**
* Determines if the instance is within the last month
*
* @param \DateTimeZone|string|null $timezone Time zone to use for now.
* @return bool
*/
public function isLastMonth(DateTimeZone|string|null $timezone = null): bool
{
return $this->format('m Y') === static::now($timezone)->subMonths(1)->format('m Y');
}

/**
* Determines if the instance is within the next year
*
* @param \DateTimeZone|string|null $timezone Time zone to use for now.
* @return bool
*/
public function isNextYear(DateTimeZone|string|null $timezone = null): bool
{
return $this->year === static::now($timezone)->addYears(1)->year;
}

/**
* Determines if the instance is within the last year
*
* @param \DateTimeZone|string|null $timezone Time zone to use for now.
* @return bool
*/
public function isLastYear(DateTimeZone|string|null $timezone = null): bool
{
return $this->year === static::now($timezone)->subYears(1)->year;
}

/**
* Determines if the instance is in the future, ie. greater (after) than now
*
* @param \DateTimeZone|string|null $timezone Time zone to use for now.
* @return bool
*/
public function isFuture(DateTimeZone|string|null $timezone = null): bool
{
return $this->greaterThan(static::now($timezone));
}

/**
* Determines if the instance is in the past, ie. less (before) than now
*
* @param \DateTimeZone|string|null $timezone Time zone to use for now.
* @return bool
*/
public function isPast(DateTimeZone|string|null $timezone = null): bool
{
return $this->lessThan(static::now($timezone));
}

/**
* Determines if the instance is a leap year
*
Expand Down
21 changes: 0 additions & 21 deletions src/Traits/FrozenTimeTrait.php
Expand Up @@ -13,11 +13,7 @@
*/
namespace Cake\Chronos\Traits;

use Cake\Chronos\Chronos;
use Cake\Chronos\ChronosDate;
use DateInterval;
use DateTimeImmutable;
use DateTimeInterface;
use InvalidArgumentException;

/**
Expand All @@ -29,23 +25,6 @@ trait FrozenTimeTrait
{
use RelativeKeywordTrait;

/**
* Removes the time components from an input string.
*
* Used to ensure constructed objects always lack time.
*
* @param \Cake\Chronos\Chronos|\Cake\Chronos\ChronosDate|\DateTimeInterface|string $time The input time
* @return string The date component of $time.
*/
protected function stripTime(Chronos|ChronosDate|DateTimeInterface|string $time): string
{
if (is_string($time)) {
$time = new DateTimeImmutable($time);
}

return $time->format('Y-m-d 00:00:00');
}

/**
* Remove time components from strtotime relative strings.
*
Expand Down