Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

- Add `Intl\NumberFormatOptions` to allow users to configure number string formatting.
- Add `Intl\DateTimeFormatOptions` to allow users to configure date and time string formatting.
- Provide functionality for formatting dates and times through `Intl\DateTimeFormat`, as well as `FormatPHP::formatDate()` and `FormatPHP::formatTime()` convenience methods.
- Add `UnableToFormatStringException` from which other formatting exceptions will descend.
- Add `UnableToFormatDateTimeException` thrown when we're unable to format a date or time string.

### Changed

Expand Down
30 changes: 30 additions & 0 deletions src/Exception/UnableToFormatDateTimeException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

/**
* This file is part of skillshare/formatphp
*
* skillshare/formatphp is open source software: you can distribute
* it and/or modify it under the terms of the MIT License
* (the "License"). You may not use this file except in
* compliance with the License.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
* @copyright Copyright (c) Skillshare, Inc. <https://www.skillshare.com>
* @license https://opensource.org/licenses/MIT MIT License
*/

declare(strict_types=1);

namespace FormatPHP\Exception;

/**
* Thrown when we are unable to format a date/time
*/
class UnableToFormatDateTimeException extends UnableToFormatStringException
{
}
79 changes: 74 additions & 5 deletions src/FormatPHP.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,25 @@

namespace FormatPHP;

use FormatPHP\Exception\InvalidArgumentException;
use FormatPHP\Exception\UnableToGenerateMessageIdException;
use DateTimeImmutable as PhpDateTimeImmutable;
use DateTimeInterface as PhpDateTimeInterface;
use Exception as PhpException;
use FormatPHP\Intl\DateTimeFormat;
use FormatPHP\Intl\DateTimeFormatOptions;
use FormatPHP\Intl\MessageFormat;
use FormatPHP\Util\MessageCleaner;
use FormatPHP\Util\MessageRetriever;

use function array_merge;
use function gettype;
use function is_int;
use function is_string;
use function sprintf;

/**
* FormatPHP internationalization and localization
*
* @psalm-import-type DateTimeType from FormatterInterface
*/
class FormatPHP implements FormatterInterface
{
Expand Down Expand Up @@ -76,19 +84,80 @@ public function formatMessage(array $descriptor, array $values = []): string
$descriptor['description'] ?? null,
),
);
} catch (UnableToGenerateMessageIdException $exception) {
throw new InvalidArgumentException(
} catch (Exception\UnableToGenerateMessageIdException $exception) {
throw new Exception\InvalidArgumentException(
'The message descriptor must have an ID or default message',
is_int($exception->getCode()) ? $exception->getCode() : 0, // @phpstan-ignore-line
(int) $exception->getCode(),
$exception,
);
}

return $this->messageFormat->format($this->cleanMessage($messagePattern), $values);
}

/**
* @throws Exception\InvalidArgumentException
* @throws Exception\UnableToFormatDateTimeException
*
* @inheritdoc
*/
public function formatDate($date = null, ?DateTimeFormatOptions $options = null): string
{
$formatter = new DateTimeFormat($this->config->getLocale(), $options);

return $formatter->format($this->convertToDateTime($date));
}

/**
* @throws Exception\InvalidArgumentException
* @throws Exception\UnableToFormatDateTimeException
*
* @inheritdoc
*/
public function formatTime($date = null, ?DateTimeFormatOptions $options = null): string
{
$options = $options ? clone $options : new DateTimeFormatOptions();

if ($options->dateStyle === null && $options->timeStyle === null) {
$options->hour = $options->hour ?? 'numeric';
Comment thread
ramsey marked this conversation as resolved.
$options->minute = $options->minute ?? 'numeric';
}

return $this->formatDate($date, $options);
}

protected function getConfig(): ConfigInterface
{
return $this->config;
}

/**
* @param DateTimeType | mixed $date
*
* @throws Exception\InvalidArgumentException
* @throws PhpException
*/
private function convertToDateTime($date): PhpDateTimeInterface
{
if ($date === null) {
return new PhpDateTimeImmutable();
}

if ($date instanceof PhpDateTimeInterface) {
return $date;
}

if (is_string($date)) {
return new PhpDateTimeImmutable($date);
}

if (is_int($date)) {
return new PhpDateTimeImmutable('@' . $date);
}

throw new Exception\InvalidArgumentException(sprintf(
'Value must be a string, integer, or instance of DateTimeInterface; received \'%s\'',
gettype($date),
));
}
}
42 changes: 40 additions & 2 deletions src/FormatterInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,15 @@

namespace FormatPHP;

use DateTimeInterface as PhpDateTimeInterface;
use FormatPHP\Intl\DateTimeFormatOptions;

/**
* FormatPHP formatter methods
*
* @psalm-type MessageDescriptorType = array{id?: string, defaultMessage?: string, description?: string}
* @psalm-type MessageValuesType = array<array-key, float | int | string | callable(string):string>
* @psalm-type DateTimeType = PhpDateTimeInterface | string | int
*/
interface FormatterInterface
{
Expand All @@ -36,8 +43,39 @@ interface FormatterInterface
* If we cannot find the given ID in the configured messages, we will use
* the descriptor's defaultMessage, if provided.
*
* @param array{id?: string, defaultMessage?: string, description?: string} $descriptor
* @param array<array-key, int | float | string> $values
* @throws Exception\InvalidArgumentException
* @throws Exception\UnableToFormatMessageException
*
* @psalm-param MessageDescriptorType $descriptor
* @psalm-param MessageValuesType $values
*/
public function formatMessage(array $descriptor, array $values = []): string;

/**
* Returns a date string formatted according to the locale of this formatter
*
* Additional options may be provided to configure how the date should be
* formatted.
*
* @param DateTimeType | null $date
*
* @throws Exception\InvalidArgumentException
* @throws Exception\UnableToFormatDateTimeException
*/
public function formatDate($date = null, ?DateTimeFormatOptions $options = null): string;

/**
* Returns a date string formatted according to the locale of this formatter,
* but it differs from `formatDate()` by using "numeric" as the default value
* for the `hour` and `minute` options
*
* Additional options may be provided to configure how the date should be
* formatted.
*
* @param DateTimeType | null $date
*
* @throws Exception\InvalidArgumentException
* @throws Exception\UnableToFormatDateTimeException
*/
public function formatTime($date = null, ?DateTimeFormatOptions $options = null): string;
}
Loading