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
23 changes: 23 additions & 0 deletions Mf2/Parser.php
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,26 @@ function convertTimeFormat($time) {
}
}

/**
* Normalize an ordinal date to YYYY-MM-DD
* This function should only be called after validating the $dtValue
* matches regex \d{4}-\d{2}
* @param string $dtValue
* @return string
*/
function normalizeOrdinalDate($dtValue) {
list($year, $day) = explode('-', $dtValue, 2);
$day = intval($day);
if ($day < 367 && $day > 0) {
$date = \DateTime::createFromFormat('Y-z', $dtValue);
$date->modify('-1 day'); # 'z' format is zero-based so need to adjust
if ($date->format('Y') === $year) {
return $date->format('Y-m-d');
}
}
return '';
}

/**
* If a date value has a timezone offset, normalize it.
* @param string $dtValue
Expand Down Expand Up @@ -711,6 +731,9 @@ public function parseDT(\DOMElement $dt, &$dates = array(), &$impliedTimezone =
// Is the current part a valid date AND no other date representation has been found?
} elseif (preg_match('/^\d{4}-\d{2}-\d{2}$/', $part) and empty($datePart)) {
$datePart = $part;
// Is the current part a valid ordinal date AND no other date representation has been found?
} elseif (preg_match('/^\d{4}-\d{3}$/', $part) and empty($datePart)) {
$datePart = normalizeOrdinalDate($part);
// Is the current part a valid timezone offset AND no other timezone part has been found?
} elseif (preg_match('/^(Z|[+-]\d{1,2}:?(\d{2})?)$/', $part) and empty($timezonePart)) {
$timezonePart = $part;
Expand Down
19 changes: 19 additions & 0 deletions tests/Mf2/ParseDTTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -531,5 +531,24 @@ public function testDtWithoutYear() {
$this->assertEquals('--12-28', $output['items'][0]['properties']['bday'][0]);
}

/**
* @see https://github.com/indieweb/php-mf2/issues/167
* @see https://github.com/microformats/mf2py/blob/master/test/examples/datetimes.html
*/
public function testNormalizeOrdinalDate() {
$input = '<div class="h-event">
<h1 class="p-name">Ordinal date</h1>
<p> When:
<span class="dt-start">
<span class="value">2016-062</span>
<span class="value">12:30AM</span>
(UTC<span class="value">-06:00</span>)
</p>
</div>';
$parser = new Parser($input);
$output = $parser->parse();

$this->assertEquals('2016-03-02 12:30-0600', $output['items'][0]['properties']['start'][0]);
}
}

13 changes: 13 additions & 0 deletions tests/Mf2/ParserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -823,5 +823,18 @@ public function testNotMutatingPassedInDOM() {
Mf2\parse($inputDoc, 'http://snarfed.org/2013-10-23_oauth-dropins');
$this->assertEquals($refDoc, $inputDoc, 'Parsing mutated the DOMDocument.');
}

/**
* Make sure day of year passed to normalizeOrdinalDate() is valid
* @see https://github.com/indieweb/php-mf2/issues/167
*/
public function testInvalidOrdinalDate() {
# 365 days in non-leap years
$this->assertEquals('2018-12-31', Mf2\normalizeOrdinalDate('2018-365'));
$this->assertEquals('', Mf2\normalizeOrdinalDate('2018-366'));
# 366 days in leap years
$this->assertEquals('2016-12-31', Mf2\normalizeOrdinalDate('2016-366'));
$this->assertEquals('', Mf2\normalizeOrdinalDate('2016-367'));
}
}