Skip to content

Commit

Permalink
Merge pull request #86 from gnutix/year-objects-add-parse-method
Browse files Browse the repository at this point in the history
Add parsing methods where missing.
  • Loading branch information
BenMorel authored Oct 2, 2023
2 parents f013742 + 89381c2 commit 5b6044c
Show file tree
Hide file tree
Showing 6 changed files with 192 additions and 0 deletions.
5 changes: 5 additions & 0 deletions src/Field/WeekOfYear.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ final class WeekOfYear
*/
public const NAME = 'week-of-year';

/**
* The regular expression pattern of the ISO 8601 representation.
*/
public const PATTERN = '[0-9]{2}';

/**
* @param int $weekOfYear The week-of-year to check.
* @param int|null $year An optional year to check against, validated.
Expand Down
37 changes: 37 additions & 0 deletions src/Parser/IsoParsers.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use Brick\DateTime\Field\TimeZoneOffsetSecond;
use Brick\DateTime\Field\TimeZoneOffsetSign;
use Brick\DateTime\Field\TimeZoneRegion;
use Brick\DateTime\Field\WeekOfYear;
use Brick\DateTime\Field\Year;

/**
Expand Down Expand Up @@ -165,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`.
*/
Expand All @@ -184,6 +202,25 @@ public static function yearMonth(): PatternParser
->toParser();
}

/**
* Returns a parser for a year-week such as `2014-W15`.
*/
public static function yearWeek(): PatternParser
{
/** @var PatternParser|null $parser */
static $parser;

if ($parser) {
return $parser;
}

return $parser = (new PatternParserBuilder())
->appendCapturePattern(Year::PATTERN, Year::NAME)
->appendLiteral('-W')
->appendCapturePattern(WeekOfYear::PATTERN, WeekOfYear::NAME)
->toParser();
}

/**
* Returns a parser for a month-day such as `12-31`.
*/
Expand Down
33 changes: 33 additions & 0 deletions src/Year.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/**
Expand Down Expand Up @@ -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.
*
Expand Down
34 changes: 34 additions & 0 deletions src/YearWeek.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;

use function sprintf;
Expand Down Expand Up @@ -49,6 +53,36 @@ public static function of(int $year, int $week): YearWeek
return new YearWeek($year, $week);
}

/**
* @throws DateTimeException If the year-week is not valid.
* @throws DateTimeParseException If required fields are missing from the result.
*/
public static function from(DateTimeParseResult $result): YearWeek
{
return YearWeek::of(
(int) $result->getField(Field\Year::NAME),
(int) $result->getField(Field\WeekOfYear::NAME)
);
}

/**
* Obtains an instance of `YearWeek` from a text string.
*
* @param string $text The text to parse, such as `2007-W48`.
* @param DateTimeParser|null $parser The parser to use, defaults to the ISO 8601 parser.
*
* @throws DateTimeException If the year-week is not valid.
* @throws DateTimeParseException If the text string does not follow the expected format.
*/
public static function parse(string $text, ?DateTimeParser $parser = null): YearWeek
{
if (! $parser) {
$parser = IsoParsers::yearWeek();
}

return YearWeek::from($parser->parse($text));
}

public static function now(TimeZone $timeZone, ?Clock $clock = null): YearWeek
{
return LocalDate::now($timeZone, $clock)->getYearWeek();
Expand Down
40 changes: 40 additions & 0 deletions tests/YearTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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 providerParseInvalidYearThrowsException
*/
public function testParseInvalidYearThrowsException(string $invalidValue): void
{
$this->expectException(DateTimeException::class);
$this->expectExceptionMessage('Failed to parse "' . $invalidValue . '"');

Year::parse($invalidValue);
}

public function providerParseInvalidYearThrowsException(): array
{
return [
[''],
['+2000'],
['-100'],
['ABC'],
['9999999999'],
];
}

public function providerOfInvalidYearThrowsException(): array
{
return [
Expand Down
43 changes: 43 additions & 0 deletions tests/YearWeekTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,49 @@ public function testToString(int $year, int $week, string $expected): void
self::assertSame($expected, (string) $yearWeek);
}

/**
* @dataProvider providerParse
*/
public function testParse(string $string, int $expectedYear, int $expectedWeek): void
{
$yearWeek = YearWeek::parse($string);
self::assertYearWeekIs($expectedYear, $expectedWeek, $yearWeek);
}

public function providerParse(): array
{
return [
['-2000-W12', -2000, 12],
['-0100-W01', -100, 1],
['2015-W01', 2015, 1],
['2015-W48', 2015, 48],
['2026-W53', 2026, 53],
['120195-W23', 120195, 23],
];
}

/**
* @dataProvider providerParseInvalidYearWeekThrowsException
*/
public function testParseInvalidYearWeekThrowsException(string $invalidValue, ?string $error = null): void
{
$this->expectException(DateTimeException::class);
$this->expectExceptionMessage($error ?? 'Failed to parse "' . $invalidValue . '"');

YearWeek::parse($invalidValue);
}

public function providerParseInvalidYearWeekThrowsException(): array
{
return [
[''],
['+2000-W01'],
['2000W01'],
['2000-W54', 'Invalid week-of-year: 54 is not in the range 1 to 53.'],
['2025-W53', 'Year 2025 does not have 53 weeks'],
];
}

public function testNow(): void
{
$now = new FixedClock(Instant::of(2000000000));
Expand Down

0 comments on commit 5b6044c

Please sign in to comment.