diff --git a/src/Parser/IsoParsers.php b/src/Parser/IsoParsers.php index 4d45bc4..590a11a 100644 --- a/src/Parser/IsoParsers.php +++ b/src/Parser/IsoParsers.php @@ -166,6 +166,23 @@ public static function yearMonthRange(): PatternParser ->toParser(); } + /** + * Returns a parser for a year such as `2014`. + */ + public static function year(): PatternParser + { + /** @var PatternParser|null $parser */ + static $parser; + + if ($parser) { + return $parser; + } + + return $parser = (new PatternParserBuilder()) + ->appendCapturePattern(Year::PATTERN, Year::NAME) + ->toParser(); + } + /** * Returns a parser for a year-month such as `2014-12`. */ diff --git a/src/Year.php b/src/Year.php index 6caa41d..10a56f3 100644 --- a/src/Year.php +++ b/src/Year.php @@ -4,6 +4,10 @@ namespace Brick\DateTime; +use Brick\DateTime\Parser\DateTimeParseException; +use Brick\DateTime\Parser\DateTimeParser; +use Brick\DateTime\Parser\DateTimeParseResult; +use Brick\DateTime\Parser\IsoParsers; use JsonSerializable; /** @@ -37,6 +41,35 @@ public static function of(int $year): Year return new Year($year); } + /** + * @throws DateTimeException If the year is not valid. + * @throws DateTimeParseException If required fields are missing from the result. + */ + public static function from(DateTimeParseResult $result): Year + { + $year = (int) $result->getField(Field\Year::NAME); + + return Year::of($year); + } + + /** + * Obtains an instance of `Year` from a text string. + * + * @param string $text The text to parse, such as `2007`. + * @param DateTimeParser|null $parser The parser to use, defaults to the ISO 8601 parser. + * + * @throws DateTimeException If the year is not valid. + * @throws DateTimeParseException If the text string does not follow the expected format. + */ + public static function parse(string $text, ?DateTimeParser $parser = null): Year + { + if (! $parser) { + $parser = IsoParsers::year(); + } + + return Year::from($parser->parse($text)); + } + /** * Returns the current year in the given time-zone, according to the given clock. * diff --git a/tests/YearTest.php b/tests/YearTest.php index b5dbb01..afdf0da 100644 --- a/tests/YearTest.php +++ b/tests/YearTest.php @@ -35,6 +35,46 @@ public function testOfInvalidYearThrowsException(int $invalidYear): void Year::of($invalidYear); } + /** + * @dataProvider providerParse + */ + public function testParse(string $string, int $expectedYear): void + { + self::assertYearIs($expectedYear, Year::parse($string)); + } + + public function providerParse(): array + { + return [ + ['-2023', -2023], + ['-0100', -100], + ['1987', 1987], + ['121241', 121241], + ]; + } + + /** + * @dataProvider providerParseInvalidValues + */ + public function testParseInvalidYearThrowsException(string $invalidValue): void + { + $this->expectException(DateTimeException::class); + $this->expectExceptionMessage('Failed to parse "' . $invalidValue . '"'); + + Year::parse($invalidValue); + } + + public function providerParseInvalidValues(): array + { + return [ + [''], + ['+2000'], + ['-100'], + ['ABC'], + ['9999999999'], + ]; + } + public function providerOfInvalidYearThrowsException(): array { return [