Skip to content

Commit

Permalink
integrated level 1 extended interval, prefixed year, and qualification
Browse files Browse the repository at this point in the history
  • Loading branch information
kilip authored and JeroenDeDauw committed Nov 12, 2020
1 parent 19a1d47 commit d3c0268
Show file tree
Hide file tree
Showing 11 changed files with 507 additions and 160 deletions.
100 changes: 98 additions & 2 deletions src/ExtDateTime.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,52 @@

class ExtDateTime implements DateTimeInterface
{
/**
* Normal date value
*/
public const STATUS_NORMAL = 1;

/**
* There is a value, but we don't know anything about it
*/
public const STATUS_UNKNOWN = 2;

/**
* The specified edtf date use value ".."
*/
public const STATUS_OPEN = 3;

/**
* For EndDate when the value is a single date
*/
public const STATUS_UNUSED = 4;

private int $status = self::STATUS_UNKNOWN;

/**
* EDTF date doesn't define the qualification.
*/
public const QUALIFICATION_UNSPECIFIED = 0;

/**
* EDTF date uncertain, determined by flag "?"
*/
public const QUALIFICATION_UNCERTAIN = 1;

/**
* EDTF date approximate,
* determined by flag "~"
*/
public const QUALIFICATION_APPROXIMATE = 2;

/**
* EDTF date both uncertain and approximate,
* determined by flag "%"
*/
public const QUALIFICATION_BOTH = 3;

private int $qualification = self::QUALIFICATION_UNSPECIFIED;

private ?int $year = null;

private ?int $month = null;
Expand All @@ -28,15 +74,65 @@ class ExtDateTime implements DateTimeInterface

private ?int $timezoneOffset = 0;

public function isStatusTypeNormal(): bool
{
return $this->status === self::STATUS_NORMAL;
}

public function isStatusTypeOpen(): bool
{
return $this->status === self::STATUS_OPEN;
}

public function isStatusTypeUnknown(): bool
{
return $this->status === self::STATUS_UNKNOWN;
}

public function isQualificationUncertain(): bool
{
return $this->qualification === self::QUALIFICATION_UNCERTAIN;
}

public function isQualificationApproximate(): bool
{
return $this->qualification === self::QUALIFICATION_APPROXIMATE;
}

public function isQualificationBoth(): bool
{
return $this->qualification === self::QUALIFICATION_BOTH;
}

public function isQualificationUnspecified(): bool
{
return $this->qualification === self::QUALIFICATION_UNSPECIFIED;
}

public function setQualification(int $qualification): self
{
$this->qualification = $qualification;

return $this;
}

public function setStatus(int $status): self
{
$this->status = $status;

return $this;
}

public function fromRegexMatches(array $matches): void
{
$props = [
'year', 'month', 'day', 'hour', 'minute', 'second'
];
foreach ($props as $field) {
if (isset($matches[$field])) {
$fieldName = $field.'Num';
if (isset($matches[$fieldName])) {
$setter = 'set' . $field;
call_user_func_array([$this, $setter], [$matches[$field]]);
call_user_func_array([$this, $setter], [$matches[$fieldName]]);
}
}

Expand Down
20 changes: 10 additions & 10 deletions src/Interval.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,28 @@

class Interval implements DateTimeInterface
{
private ?ExtDateTime $lower = null;
private ?ExtDateTime $upper = null;
private ?ExtDateTime $start = null;
private ?ExtDateTime $end = null;

public function getLower(): ?ExtDateTime
public function getStart(): ?ExtDateTime
{
return $this->lower;
return $this->start;
}

public function setLower(ExtDateTime $lower): Interval
public function setStart(ExtDateTime $start): Interval
{
$this->lower = $lower;
$this->start = $start;
return $this;
}

public function getUpper(): ?ExtDateTime
public function getEnd(): ?ExtDateTime
{
return $this->upper;
return $this->end;
}

public function setUpper(ExtDateTime $upper): Interval
public function setEnd(ExtDateTime $end): Interval
{
$this->upper = $upper;
$this->end = $end;
return $this;
}
}
53 changes: 37 additions & 16 deletions src/Parser.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@ class Parser
# Year start
(?<year>
(?<yearOpenFlags>[~?%]{0,2})
(?<yearNum>[+-]?(?:\d+e\d+|[0-9u][0-9ux]*))
(?>S # Literal S letter. It is for the significant digit indicator
(?<yearPrecision>\d+))?
(?<yearEnd>\)?[~?]{0,2})
(?<yearCloseFlag>\)?[~%?]{0,2})
)
# Year end
Expand All @@ -42,14 +43,14 @@ class Parser
(?<day>
(?<dayOpenParents>\(+)?
(?<dayNum>(?>[012u][0-9u]|3[01u])))
(?<dayEnd>[)~?]*)
(?<dayEnd>[)~%?]*)
# Day end
# Others start #
(?>T # Literal T
(?<hour>2[0-3]|[01][0-9]):
(?<minute>[0-5][0-9]):
(?<second>[0-5][0-9])
(?<hourNum>2[0-3]|[01][0-9]):
(?<minuteNum>[0-5][0-9]):
(?<secondNum>[0-5][0-9])
(?>(?<tzUtc>Z)|
(?<tzSign>[+-])
(?<tzHour>[01][0-9]):
Expand All @@ -65,7 +66,7 @@ public function parse(string $data): DateTimeInterface
return $this->createExtDateTime($data);
}

private function createInterval(string $data): DateTimeInterface
public function createInterval(string $data): Interval
{
$pos = strrpos($data, '/');

Expand All @@ -77,26 +78,46 @@ private function createInterval(string $data): DateTimeInterface
$endDateStr = substr( $data, $pos + 1 );
$interval = new Interval();

$startDate = $this->createExtDateTime($startDateStr);
$endDate = $this->createExtDateTime($endDateStr);
$startDate = $this->createExtDateTime($startDateStr, true);
$endDate = $this->createExtDateTime($endDateStr, true);

$interval
->setLower($startDate)
->setUpper($endDate)
->setStart($startDate)
->setEnd($endDate)
;
return $interval;
}

/**
* @TODO: add a way to validate and handle invalid $data format
*/
private function createExtDateTime(string $data): ExtDateTime
public function createExtDateTime(string $data, bool $isInterval = false): ExtDateTime
{
//@TODO: add a way to validate and handle invalid $data format

$regexPattern = $this->regexPattern;
$dateTime = new ExtDateTime();

preg_match($regexPattern, $data, $matches);
$dateTime->fromRegexMatches($matches);
if("" === $data){
$status = $isInterval ? ExtDateTime::STATUS_UNKNOWN : ExtDateTime::STATUS_UNUSED;
$dateTime->setStatus($status);
}elseif('..' === $data){
$dateTime->setStatus(ExtDateTime::STATUS_OPEN);
}else{
preg_match($regexPattern, $data, $matches);
$dateTime->fromRegexMatches($matches);
$dateTime->setStatus(ExtDateTime::STATUS_NORMAL);
$this->setDateQualification($data, $dateTime);
}

return $dateTime;
}

private function setDateQualification(string $data, ExtDateTime $dateTime): void
{
if(false !== strpos($data, "~")){
$dateTime->setQualification(ExtDateTime::QUALIFICATION_APPROXIMATE);
}elseif(false !== strpos($data, "?")){
$dateTime->setQualification(ExtDateTime::QUALIFICATION_UNCERTAIN);
}elseif(false !== strpos($data, "%")){
$dateTime->setQualification(ExtDateTime::QUALIFICATION_BOTH);
}
}
}
23 changes: 23 additions & 0 deletions tests/Unit/FactoryTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

namespace EDTF\Tests\Unit;


use EDTF\ExtDateTime;
use EDTF\Interval;
use EDTF\Parser;

trait FactoryTrait
{
public function createExtDateTime(string $data): ExtDateTime
{
return (new Parser())->createExtDateTime($data);
}

public function createInterval(string $data): Interval
{
return (new Parser())->createInterval($data);
}
}
Loading

0 comments on commit d3c0268

Please sign in to comment.