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

Add parsing methods where missing. #86

Merged
merged 2 commits into from
Oct 2, 2023
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
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],
];
}

gnutix marked this conversation as resolved.
Show resolved Hide resolved
/**
* @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],
];
}

gnutix marked this conversation as resolved.
Show resolved Hide resolved
/**
* @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
Loading