Skip to content

Commit

Permalink
Try to weed out non time strings (#3)
Browse files Browse the repository at this point in the history
* Handles non-date strings as well as yesterday and tomorrow

* code quality and linting
  • Loading branch information
edgrosvenor authored Jul 5, 2020
1 parent ba45d8a commit bfb8900
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 9 deletions.
6 changes: 6 additions & 0 deletions src/Languages.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,10 @@ public function eng(): array
'thursday' => [' thursday ', ' thu '],
'friday' => [' friday ', ' fri '],
'saturday' => [' saturday ', ' sat '],
'tomorrow' => [' tomorrow '],
'yesterday' => [' yesterday '],
],
'now' => [' now '],
];
}

Expand Down Expand Up @@ -69,7 +72,10 @@ public function esp(): array
'thursday' => [' jueves ', ' j ', ' ju ', ' jue '],
'friday' => [' viernes ', ' v ', ' vi ', ' vie '],
'saturday' => [' sábado ', ' sabado ', ' s ', '', ' sa ', ' sab '],
'tomorrow' => [' mañana ', ' manana '],
'yesterday' => [' ayer '],
],
'now' => [' ahora '],
];
}
}
9 changes: 9 additions & 0 deletions src/NoDateOrTimeStringFoundException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

declare(strict_types=1);

namespace Grosv\Sundial;

final class NoDateOrTimeStringFoundException extends \Exception
{
}
52 changes: 43 additions & 9 deletions src/Parser.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

namespace Grosv\Sundial;

use DateTime;

/**
* @internal
*/
Expand All @@ -16,7 +18,7 @@ final class Parser
private string $day;
private string $date;
private string $time;
private int $ts;
private int $ts = 0;
private string $test;
private array $matches;
private array $boundary = ['start' => 1, 'end' => 2147483647];
Expand Down Expand Up @@ -49,12 +51,6 @@ public function loadLanguage(): self

public function parse(string $string): self
{
$try = strtotime($string);
if (abs((int) $try) > 86400) {
$this->ts = (int) $try;

return $this;
}
$this->loadLanguage();
$this->string = strtolower(' ' . $string . ' ');
$this->test = (string) preg_replace('/[\W]/', ' ', $this->string);
Expand All @@ -65,7 +61,7 @@ public function parse(string $string): self
$this->day = $this->day ?? $this->getDay();
$this->time = $this->time ?? $this->getTime();

$this->ts = (int) strtotime(implode(' ', [$this->date, $this->month, $this->year, $this->time]));
$this->calculateTime();

return $this;
}
Expand Down Expand Up @@ -124,6 +120,11 @@ public function getDay(): string

public function getTime(): string
{
foreach ($this->matches['now'] as $word) {
if (in_array(trim($word), explode(' ', $this->test), true)) {
return date('H:i:s');
}
}
preg_match('/((1[0-2]|0?[1-9]):?([0-5][0-9])? ?([AaPp][Mm])) /', $this->string, $matches);
if (is_array($matches) && sizeof($matches) > 0) {
return $matches[0] ?? '';
Expand Down Expand Up @@ -159,14 +160,47 @@ public function parseNumericFormats(): void
}

if (checkdate((int) $m, (int) $d, (int) $y)) {
$this->month = (string) $this->matches['months'][ltrim((string) $m, '0')][0];
$this->month = trim((string) $this->matches['months'][ltrim((string) $m, '0')][0]);
$this->date = (string) $d;
$this->year = (string) $y;
}

return;
}

/**
* @throws NoDateOrTimeStringFoundException
* @throws \Exception
*/
public function calculateTime(): void
{
$string = null;

if ((bool) $this->time) {
$string = $this->time;
}

if ((bool) $this->day) {
$string = $this->day;
}

if ((bool) $this->day && (bool) $this->time) {
$string = implode(' ', [$this->day, $this->time]);
}

if ((bool) $this->month && (bool) $this->date) {
$string = implode(' ', [$this->date, $this->month, $this->year, $this->time]);
}

if (is_null($string)) {
throw new NoDateOrTimeStringFoundException('Unable to find a date or time string to parse.');
}

$ts = new DateTime($string);

$this->ts = $ts->getTimestamp();
}

/**
* @throws DateTimeOutOfRangeException
*/
Expand Down
20 changes: 20 additions & 0 deletions tests/Feature/EnglishTest.php
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
<?php

use Grosv\Sundial\DateTimeOutOfRangeException;
use Grosv\Sundial\NoDateOrTimeStringFoundException;
use Grosv\Sundial\Parser;

test('failures to the front', function () {
assertSame(true, true); // Just a placeholder test that makes it easy to dd() when things fail.
});

test('now as timestamp', function () {
assertSame(time(), (new Parser())->parse('now')->toTimestamp());
});
Expand Down Expand Up @@ -43,6 +48,17 @@
assertSame('02:00 AM', (new Parser())->parse('April 20, 2020 at 2am')->toFormat('h:i A'));
});

test('it can manage yesterday and tomorrow', function () {
assertSame((new DateTime('12:00 am'))->add(new DateInterval('P1D'))->format('c'),
(new Parser())->parse('tomorrow')->toFormat('c'));
assertSame((new DateTime('12:00 am'))->sub(new DateInterval('P1D'))->format('c'),
(new Parser())->parse('yesterday')->toFormat('c'));
assertSame((new DateTime('14:00'))->add(new DateInterval('P1D'))->format('c'),
(new Parser())->parse('2:00 pm tomorrow')->toFormat('c'));
assertSame((new DateTime('16:00'))->sub(new DateInterval('P1D'))->format('c'),
(new Parser())->parse('yesterday at 4:00 pm')->toFormat('c'));
});

it('throws an exception if earlier than boundary minimum', function () {
(new Parser())->parse('April 20, 1992')->setBetween(time(), strtotime('tomorrow'))->toFormat('Y-m-d');
})->throws(DateTimeOutOfRangeException::class);
Expand All @@ -58,3 +74,7 @@
it('throws an exception if timestamp later than boundary minimum', function () {
(new Parser())->parse('April 20, 2032')->setBetween(time(), strtotime('tomorrow'))->toTimestamp();
})->throws(DateTimeOutOfRangeException::class);

it('throws an exception if the string is not date or time related', function () {
(new Parser())->parse('Taco salad')->toTimestamp();
})->throws(NoDateOrTimeStringFoundException::class);

0 comments on commit bfb8900

Please sign in to comment.