-
Notifications
You must be signed in to change notification settings - Fork 7
Relative date format feature #26
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
Merged
frankdekker
merged 14 commits into
123inkt:master
from
123InktJules:relative-date-format-feature
Nov 25, 2024
Merged
Changes from 12 commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
716b47e
created relative date formatter
123InktJules cca251a
created relative date formatter
123InktJules 632a2ec
fix code quality
123InktJules 95fa002
refactor
123InktJules 206d91c
refactor
123InktJules b1a79b4
fix review points
123InktJules c70aa84
fix review points
123InktJules a22b7bf
fix review points
123InktJules b6579d4
fix review points
123InktJules 437de6b
fix review points
123InktJules 04a2e4b
fix review points
123InktJules 29ca2d4
fix review points
123InktJules c02be31
fix review points
123InktJules 451079c
fix review points
123InktJules File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace DR\Internationalization\Date; | ||
|
||
use DateTimeImmutable; | ||
use DateTimeInterface; | ||
use IntlDateFormatter; | ||
use RuntimeException; | ||
|
||
class DateFormatHelper | ||
{ | ||
private DateFormatterCacheInterface $cache; | ||
private DateFormatterFactory $dateFactory; | ||
|
||
public function __construct(?DateFormatterCacheInterface $cache = null, ?DateFormatterFactory $dateFactory = null) | ||
{ | ||
$this->cache = $cache ?? new DateFormatterCache(); | ||
$this->dateFactory = $dateFactory ?? new DateFormatterFactory(); | ||
} | ||
|
||
public function getDateFormatter(DateFormatOptions $options, string $pattern): IntlDateFormatter | ||
{ | ||
// Get or create from cache. | ||
return $this->cache->get($options . $pattern, fn() => $this->dateFactory->create($options, $pattern)); | ||
} | ||
|
||
public function getParsedDate(int|string|DateTimeInterface $date): DateTimeInterface | ||
{ | ||
if (is_string($date)) { | ||
return new DateTimeImmutable($date); | ||
} | ||
|
||
if (is_int($date)) { | ||
return new DateTimeImmutable('@' . $date); | ||
123InktJules marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
return $date; | ||
} | ||
|
||
public function validateResult(bool|string|null $result, int|string|DateTimeInterface $value, string $pattern): string | ||
{ | ||
if (is_bool($result) || $result === null) { | ||
$scalarValue = $value instanceof DateTimeInterface ? $value->getTimestamp() : $value; | ||
throw new RuntimeException(sprintf('Unable to format date `%s` to format `%s`', $scalarValue, $pattern)); | ||
} | ||
|
||
return $result; | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace DR\Internationalization\Date; | ||
|
||
use IntlDateFormatter; | ||
use IntlTimeZone; | ||
|
||
/** | ||
* @phpstan-type CalendarType IntlDateFormatter::GREGORIAN|IntlDateFormatter::TRADITIONAL | ||
* @phpstan-type DateFormatType IntlTimeZone::* | ||
*/ | ||
class DateFormatOptions | ||
{ | ||
/** @phpstan-var DateFormatType $dateType */ | ||
protected int $dateType = IntlDateFormatter::FULL; | ||
|
||
/** @phpstan-var DateFormatType $timeType */ | ||
protected int $timeType = IntlDateFormatter::FULL; | ||
|
||
/** @phpstan-var CalendarType $calendar */ | ||
protected int $calendar = IntlDateFormatter::GREGORIAN; | ||
|
||
public function __construct(protected string $locale, protected string $timezone) | ||
{ | ||
} | ||
|
||
public function getLocale(): string | ||
{ | ||
return $this->locale; | ||
} | ||
|
||
/** | ||
* Set the preferred locale for the formatting. Expects an POSIX code (nl_NL, nl_BE, en_GB, etc...). Defaults to system configuration. | ||
* @return static | ||
*/ | ||
public function setLocale(string $locale): self | ||
{ | ||
$this->locale = $locale; | ||
|
||
return $this; | ||
} | ||
|
||
public function getTimezone(): string | ||
{ | ||
return $this->timezone; | ||
} | ||
|
||
/** | ||
* Set the preferred timezone for the formatting. Expects a timezone identifier (Europe/Amsterdam, UTC, etc...). Defaults to system configuration. | ||
* @return static | ||
*/ | ||
public function setTimezone(string $timezone): self | ||
{ | ||
$this->timezone = $timezone; | ||
|
||
return $this; | ||
} | ||
|
||
/** | ||
* @phpstan-return DateFormatType | ||
*/ | ||
public function getDateType(): int | ||
{ | ||
return $this->dateType; | ||
} | ||
|
||
/** | ||
* @phpstan-param DateFormatType $dateType | ||
*/ | ||
public function setDateType(int $dateType): DateFormatOptions | ||
{ | ||
$this->dateType = $dateType; | ||
|
||
return $this; | ||
} | ||
|
||
/** | ||
* @phpstan-return DateFormatType | ||
*/ | ||
public function getTimeType(): int | ||
{ | ||
return $this->timeType; | ||
} | ||
|
||
/** | ||
* @phpstan-param DateFormatType $timeType | ||
*/ | ||
public function setTimeType(int $timeType): DateFormatOptions | ||
{ | ||
$this->timeType = $timeType; | ||
|
||
return $this; | ||
} | ||
|
||
/** | ||
* @phpstan-return CalendarType | ||
*/ | ||
public function getCalendar(): int | ||
{ | ||
return $this->calendar; | ||
} | ||
|
||
/** | ||
* @phpstan-param CalendarType $calendar | ||
*/ | ||
public function setCalendar(int $calendar): DateFormatOptions | ||
{ | ||
$this->calendar = $calendar; | ||
|
||
return $this; | ||
} | ||
|
||
public function __toString(): string | ||
{ | ||
return "date:" . serialize([ | ||
'locale' => $this->locale, | ||
'timezone' => $this->timezone, | ||
'dateType' => $this->dateType, | ||
'timeType' => $this->timeType, | ||
'calendar' => $this->calendar, | ||
]); | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
<?php | ||
declare(strict_types=1); | ||
|
||
namespace DR\Internationalization\Date; | ||
|
||
use IntlDateFormatter; | ||
|
||
/** | ||
* @internal | ||
*/ | ||
class DateFormatterCache implements DateFormatterCacheInterface | ||
{ | ||
/** @var IntlDateFormatter[] */ | ||
private array $formatters = []; | ||
|
||
public function get(string $key, callable $factoryCallback): IntlDateFormatter | ||
{ | ||
return $this->formatters[$key] ??= $factoryCallback(); | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace DR\Internationalization\Date; | ||
|
||
use IntlDateFormatter; | ||
|
||
interface DateFormatterCacheInterface | ||
{ | ||
/** | ||
* @param callable():IntlDateFormatter $factoryCallback | ||
*/ | ||
public function get(string $key, callable $factoryCallback): IntlDateFormatter; | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
<?php | ||
declare(strict_types=1); | ||
|
||
namespace DR\Internationalization\Date; | ||
|
||
use IntlDateFormatter; | ||
|
||
class DateFormatterFactory | ||
{ | ||
public function create(DateFormatOptions $options, string $pattern): IntlDateFormatter | ||
{ | ||
return new IntlDateFormatter( | ||
$options->getLocale(), | ||
$options->getDateType(), | ||
$options->getTimeType(), | ||
$options->getTimezone(), | ||
$options->getCalendar(), | ||
$pattern | ||
); | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace DR\Internationalization\Date; | ||
|
||
class RelativeDateFallbackResult | ||
{ | ||
public function __construct(private readonly bool $fallback, private readonly string|bool $date = '') | ||
123InktJules marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
} | ||
|
||
public function isFallback(): bool | ||
{ | ||
return $this->fallback; | ||
} | ||
|
||
public function getDate(): string|bool | ||
{ | ||
return $this->date; | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace DR\Internationalization\Date; | ||
|
||
use DateTimeImmutable; | ||
use DateTimeInterface; | ||
|
||
class RelativeDateFallbackService | ||
{ | ||
private const MAX_TRANSLATABLE_DAYS_AMOUNT = 4; | ||
private RelativeDateFormatterFactory $relativeFormatterFactory; | ||
|
||
public function __construct(?RelativeDateFormatterFactory $relativeFormatterFactory = null) | ||
{ | ||
$this->relativeFormatterFactory = $relativeFormatterFactory ?? new RelativeDateFormatterFactory(); | ||
} | ||
|
||
public function getFallbackResult( | ||
string $locale, | ||
DateTimeInterface $dateTime, | ||
RelativeDateFormatOptions $relativeOptions | ||
): RelativeDateFallbackResult { | ||
$currentDateTime = (new DateTimeImmutable())->setTime(0, 0); | ||
|
||
if ($dateTime->diff($currentDateTime)->d > self::MAX_TRANSLATABLE_DAYS_AMOUNT | ||
|| $relativeOptions->getRelativeDaysAmount() === 0 | ||
|| $relativeOptions->getRelativeDaysAmount() === null | ||
|| $dateTime->diff($currentDateTime)->d > $relativeOptions->getRelativeDaysAmount() | ||
) { | ||
return new RelativeDateFallbackResult(true); | ||
} | ||
|
||
$relativeDate = $this->relativeFormatterFactory->createRelativeFull($locale)->format($dateTime); | ||
$fullDate = $this->relativeFormatterFactory->createFull($locale)->format($dateTime); | ||
|
||
if ($relativeDate === $fullDate) { | ||
return new RelativeDateFallbackResult(true); | ||
} | ||
|
||
return new RelativeDateFallbackResult(false, $relativeDate); | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace DR\Internationalization\Date; | ||
|
||
class RelativeDateFormatOptions | ||
{ | ||
public function __construct(private readonly ?int $relativeDaysAmount) | ||
{ | ||
} | ||
|
||
public function getRelativeDaysAmount(): ?int | ||
{ | ||
return $this->relativeDaysAmount; | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
<?php | ||
declare(strict_types=1); | ||
|
||
namespace DR\Internationalization\Date; | ||
|
||
use IntlDateFormatter; | ||
|
||
class RelativeDateFormatterFactory | ||
{ | ||
public function createRelativeFull(string $locale): IntlDateFormatter | ||
{ | ||
return new IntlDateFormatter( | ||
$locale, | ||
IntlDateFormatter::RELATIVE_FULL, | ||
IntlDateFormatter::NONE, | ||
'UTC', | ||
IntlDateFormatter::GREGORIAN, | ||
); | ||
} | ||
|
||
public function createFull(string $locale): IntlDateFormatter | ||
{ | ||
return new IntlDateFormatter( | ||
$locale, | ||
IntlDateFormatter::FULL, | ||
IntlDateFormatter::NONE, | ||
'UTC', | ||
IntlDateFormatter::GREGORIAN | ||
); | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.