Skip to content

Commit ee41586

Browse files
committed
Add version 0.1.6
1 parent 79b92b7 commit ee41586

File tree

8 files changed

+820
-169
lines changed

8 files changed

+820
-169
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
77

88
## Releases
99

10+
### [0.1.6] - 2023-07-16
11+
12+
* Add timezone support
13+
1014
### [0.1.5] - 2023-07-09
1115

1216
* Add more parser options like next-year, last-year, etc.

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,16 @@ $dateParser = (new DateParser('today'))->formatTo('Y-m-d H:i:s');
4343
// 2023-07-07 23:59:59
4444
```
4545
46+
### Timezones
47+
48+
```php
49+
$dateParser = (new DateParser('<2023-07-01', 'America/New_York'))->formatFrom('Y-m-d H:i:s', 'Europe/Berlin');
50+
// null
51+
52+
$dateParser = (new DateParser('<2023-07-01', 'America/New_York'))->formatTo('Y-m-d H:i:s', 'Europe/Berlin');
53+
// 2023-07-01 09:59:59
54+
```
55+
4656
## Parsing formats
4757
4858
### Supported words

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.1.5
1+
0.1.6

src/Base/BaseDateParser.php

Lines changed: 62 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,11 @@
1414
namespace Ixnode\PhpDateParser\Base;
1515

1616
use DateTime;
17+
use DateTimeImmutable;
18+
use DateTimeZone;
1719
use Exception;
1820
use Ixnode\PhpDateParser\DateRange;
21+
use Ixnode\PhpException\Case\CaseUnsupportedException;
1922
use Ixnode\PhpException\Parser\ParserException;
2023
use Ixnode\PhpException\Type\TypeInvalidException;
2124

@@ -52,6 +55,8 @@ class BaseDateParser
5255

5356
final public const FORMAT_THIS_YEAR_LAST = 'Y-12-31';
5457

58+
final public const VALUE_NOW = 'now';
59+
5560
final public const VALUE_TOMORROW = 'tomorrow';
5661

5762
final public const VALUE_TODAY = 'today';
@@ -78,10 +83,11 @@ class BaseDateParser
7883

7984
/**
8085
* @param string|null $range
81-
* @throws TypeInvalidException
86+
* @param DateTimeZone $dateTimeZoneInput
8287
* @throws ParserException
88+
* @throws TypeInvalidException
8389
*/
84-
public function __construct(string|null $range)
90+
public function __construct(string|null $range, protected DateTimeZone $dateTimeZoneInput = new DateTimeZone('UTC'))
8591
{
8692
$this->range = !is_null($range) ? trim(strtolower($range)) : null;
8793

@@ -102,7 +108,7 @@ public function __construct(string|null $range)
102108
private function parseRange(string|null $range): DateRange
103109
{
104110
if (is_null($range)) {
105-
return new DateRange(
111+
return $this->getDateRangeInstance(
106112
null,
107113
null
108114
);
@@ -114,30 +120,30 @@ private function parseRange(string|null $range): DateRange
114120

115121
/* Parses "tomorrow" date. */
116122
case $range === self::VALUE_TOMORROW:
117-
return new DateRange(
118-
(new DateTime(self::VALUE_TOMORROW))->setTime(self::HOUR_FIRST, self::MINUTE_FIRST, self::SECOND_FIRST),
119-
(new DateTime(self::VALUE_TOMORROW))->setTime(self::HOUR_LAST, self::MINUTE_LAST, self::SECOND_LAST)
123+
return $this->getDateRangeInstance(
124+
$this->getDateTimeRaw(self::VALUE_TOMORROW, self::HOUR_FIRST, self::MINUTE_FIRST, self::SECOND_FIRST),
125+
$this->getDateTimeRaw(self::VALUE_TOMORROW, self::HOUR_LAST, self::MINUTE_LAST, self::SECOND_LAST)
120126
);
121127
/* Parses "today" date. */
122128
case $range === self::VALUE_TODAY:
123-
return new DateRange(
124-
(new DateTime())->setTime(self::HOUR_FIRST, self::MINUTE_FIRST, self::SECOND_FIRST),
125-
(new DateTime())->setTime(self::HOUR_LAST, self::MINUTE_LAST, self::SECOND_LAST)
129+
return $this->getDateRangeInstance(
130+
$this->getDateTimeRaw(self::VALUE_NOW, self::HOUR_FIRST, self::MINUTE_FIRST, self::SECOND_FIRST),
131+
$this->getDateTimeRaw(self::VALUE_NOW, self::HOUR_LAST, self::MINUTE_LAST, self::SECOND_LAST)
126132
);
127133
/* Parses "yesterday" date. */
128134
case $range === self::VALUE_YESTERDAY:
129-
return new DateRange(
130-
(new DateTime(self::VALUE_YESTERDAY))->setTime(self::HOUR_FIRST, self::MINUTE_FIRST, self::SECOND_FIRST),
131-
(new DateTime(self::VALUE_YESTERDAY))->setTime(self::HOUR_LAST, self::MINUTE_LAST, self::SECOND_LAST)
135+
return $this->getDateRangeInstance(
136+
$this->getDateTimeRaw(self::VALUE_YESTERDAY, self::HOUR_FIRST, self::MINUTE_FIRST, self::SECOND_FIRST),
137+
$this->getDateTimeRaw(self::VALUE_YESTERDAY, self::HOUR_LAST, self::MINUTE_LAST, self::SECOND_LAST)
132138
);
133139
/* Parses "next-month" date. */
134140
case $range === self::VALUE_NEXT_MONTH:
135141
return $this->getDateRangeNextMonth();
136142
/* Parses "this-month" date. */
137143
case $range === self::VALUE_THIS_MONTH:
138-
return new DateRange(
139-
(new DateTime(date(self::FORMAT_THIS_MONTH_FIRST)))->setTime(self::HOUR_FIRST, self::MINUTE_FIRST, self::SECOND_FIRST),
140-
(new DateTime(date(self::FORMAT_THIS_MONTH_LAST)))->setTime(self::HOUR_LAST, self::MINUTE_LAST, self::SECOND_LAST)
144+
return $this->getDateRangeInstance(
145+
$this->getDateTimeRaw(date(self::FORMAT_THIS_MONTH_FIRST), self::HOUR_FIRST, self::MINUTE_FIRST, self::SECOND_FIRST),
146+
$this->getDateTimeRaw(date(self::FORMAT_THIS_MONTH_LAST), self::HOUR_LAST, self::MINUTE_LAST, self::SECOND_LAST)
141147
);
142148
/* Parses "last-month" date. */
143149
case $range === self::VALUE_LAST_MONTH:
@@ -147,9 +153,9 @@ private function parseRange(string|null $range): DateRange
147153
return $this->getDateRangeNextYear();
148154
/* Parses "this-year" date. */
149155
case $range === self::VALUE_THIS_YEAR:
150-
return new DateRange(
151-
(new DateTime(date(self::FORMAT_THIS_YEAR_FIRST)))->setTime(self::HOUR_FIRST, self::MINUTE_FIRST, self::SECOND_FIRST),
152-
(new DateTime(date(self::FORMAT_THIS_YEAR_LAST)))->setTime(self::HOUR_LAST, self::MINUTE_LAST, self::SECOND_LAST)
156+
return $this->getDateRangeInstance(
157+
$this->getDateTimeRaw(date(self::FORMAT_THIS_YEAR_FIRST), self::HOUR_FIRST, self::MINUTE_FIRST, self::SECOND_FIRST),
158+
$this->getDateTimeRaw(date(self::FORMAT_THIS_YEAR_LAST), self::HOUR_LAST, self::MINUTE_LAST, self::SECOND_LAST)
153159
);
154160
/* Parses "last-year" date. */
155161
case $range === self::VALUE_LAST_YEAR:
@@ -158,13 +164,13 @@ private function parseRange(string|null $range): DateRange
158164

159165
/* Starts with <+: parses a "∞ (infinity)" to given "from" date (including given date). */
160166
case preg_match('~^(<[+=]|-)~', $range, $matches) === 1:
161-
return new DateRange(
167+
return $this->getDateRangeInstance(
162168
null,
163169
$this->parseRange(substr($range, strlen($matches[1])))->getTo()
164170
);
165171
/* Starts with <: parses a "∞ (infinity)" to given "from" date (excluding given date). */
166172
case str_starts_with($range, '<'):
167-
return new DateRange(
173+
return $this->getDateRangeInstance(
168174
null,
169175
$this->parseRange(substr($range, 1))
170176
->getTo()
@@ -174,13 +180,13 @@ private function parseRange(string|null $range): DateRange
174180

175181
/* Starts with >+: parses a given "from" (including given date) to "∞ (infinity)" date. */
176182
case preg_match('~^(>[+=]|[+])~', $range, $matches) === 1:
177-
return new DateRange(
183+
return $this->getDateRangeInstance(
178184
$this->parseRange(substr($range, strlen($matches[1])))->getFrom(),
179185
null
180186
);
181187
/* Starts with >: parses a given "from" (excluding given date) to "∞ (infinity)" date. */
182188
case str_starts_with($range, '>'):
183-
return new DateRange(
189+
return $this->getDateRangeInstance(
184190
$this->parseRange(substr($range, 1))->getTo()?->modify('+1 second'),
185191
null
186192
);
@@ -189,23 +195,23 @@ private function parseRange(string|null $range): DateRange
189195
/* Starts with |: parses a given "from" (including given date) to "to" date (including given date). */
190196
case str_contains($range, '|'):
191197
$splitted = explode('|', $range);
192-
return new DateRange(
198+
return $this->getDateRangeInstance(
193199
$this->parseRange($splitted[0])->getFrom(),
194200
$this->parseRange($splitted[1])->getTo()
195201
);
196202

197203

198204
/* Starts with =: a given date exactly. */
199205
case str_starts_with($range, '='):
200-
return new DateRange(
206+
return $this->getDateRangeInstance(
201207
$this->parseRange(substr($range, 1))->getFrom(),
202208
$this->parseRange(substr($range, 1))->getTo(),
203209
);
204210

205211

206212
/* Parse the date */
207213
default:
208-
return new DateRange(
214+
return $this->getDateRangeInstance(
209215
$this->parseDate($range)->setTime(self::HOUR_FIRST, self::MINUTE_FIRST, self::SECOND_FIRST),
210216
$this->parseDate($range)->setTime(self::HOUR_LAST, self::MINUTE_LAST, self::SECOND_LAST),
211217
);
@@ -227,7 +233,7 @@ private function getDateRangeNextMonth(): DateRange
227233
$lastNextMonth = (new DateTime($firstNextMonth->format(self::FORMAT_THIS_MONTH_LAST)))
228234
->setTime(self::HOUR_LAST, self::MINUTE_LAST, self::SECOND_LAST);
229235

230-
return new DateRange($firstNextMonth, $lastNextMonth);
236+
return $this->getDateRangeInstance($firstNextMonth, $lastNextMonth);
231237
}
232238

233239
/**
@@ -246,7 +252,7 @@ private function getDateRangeLastMonth(): DateRange
246252
$firstLastMonth = (new DateTime($lastLastMonth->format(self::FORMAT_THIS_MONTH_FIRST)))
247253
->setTime(self::HOUR_FIRST, self::MINUTE_FIRST, self::SECOND_FIRST);
248254

249-
return new DateRange($firstLastMonth, $lastLastMonth);
255+
return $this->getDateRangeInstance($firstLastMonth, $lastLastMonth);
250256
}
251257

252258
/**
@@ -264,7 +270,7 @@ private function getDateRangeNextYear(): DateRange
264270
$lastNextYear = (new DateTime($firstNextYear->format(self::FORMAT_THIS_YEAR_LAST)))
265271
->setTime(self::HOUR_LAST, self::MINUTE_LAST, self::SECOND_LAST);
266272

267-
return new DateRange($firstNextYear, $lastNextYear);
273+
return $this->getDateRangeInstance($firstNextYear, $lastNextYear);
268274
}
269275

270276
/**
@@ -283,7 +289,7 @@ private function getDateRangeLastYear(): DateRange
283289
$firstLastYear = (new DateTime($lastLastYear->format(self::FORMAT_THIS_YEAR_FIRST)))
284290
->setTime(self::HOUR_FIRST, self::MINUTE_FIRST, self::SECOND_FIRST);
285291

286-
return new DateRange($firstLastYear, $lastLastYear);
292+
return $this->getDateRangeInstance($firstLastYear, $lastLastYear);
287293
}
288294

289295
/**
@@ -308,4 +314,31 @@ protected function parseDate(string $date): DateTime
308314

309315
return $date;
310316
}
317+
318+
/**
319+
* @param string $dateTime
320+
* @param int $hour
321+
* @param int $minute
322+
* @param int $second
323+
* @return DateTime
324+
* @throws Exception
325+
*/
326+
protected function getDateTimeRaw(string $dateTime, int $hour, int $minute, int $second): DateTime
327+
{
328+
return (new DateTime($dateTime))->setTime($hour, $minute, $second);
329+
}
330+
331+
/**
332+
* Returns the DateRange instance from given date range.
333+
*
334+
* @param DateTime|DateTimeImmutable|null $from
335+
* @param DateTime|DateTimeImmutable|null $to
336+
* @return DateRange
337+
* @throws CaseUnsupportedException
338+
* @SuppressWarnings(PHPMD.ShortVariable)
339+
*/
340+
protected function getDateRangeInstance(DateTime|DateTimeImmutable|null $from, DateTime|DateTimeImmutable|null $to): DateRange
341+
{
342+
return new DateRange($from, $to, $this->dateTimeZoneInput);
343+
}
311344
}

src/Constants/Timezones.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the ixnode/php-date-parser project.
5+
*
6+
* (c) Björn Hempel <https://www.hempel.li/>
7+
*
8+
* For the full copyright and license information, please view the LICENSE.md
9+
* file that was distributed with this source code.
10+
*/
11+
12+
declare(strict_types=1);
13+
14+
namespace Ixnode\PhpDateParser\Constants;
15+
16+
/**
17+
* Class Timezones
18+
*
19+
* @author Björn Hempel <bjoern@hempel.li>
20+
* @version 0.1.0 (2023-07-16)
21+
* @since 0.1.0 (2023-07-16) First version.
22+
*/
23+
class Timezones
24+
{
25+
final public const UTC = 'UTC';
26+
27+
final public const EUROPE_BERLIN = 'Europe/Berlin';
28+
29+
final public const AMERICA_NEW_YORK = 'America/New_York';
30+
}

src/DateParser.php

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@
1515

1616
use DateTime;
1717
use DateTimeImmutable;
18+
use DateTimeZone;
1819
use Ixnode\PhpDateParser\Base\BaseDateParser;
20+
use Ixnode\PhpDateParser\Constants\Timezones;
1921
use Ixnode\PhpDateParser\Tests\Unit\DateParserTest;
2022

2123
/**
@@ -42,61 +44,67 @@ public function getDateRange(): DateRange
4244
* Returns the "from" date as string.
4345
*
4446
* @param string $format
47+
* @param DateTimeZone $dateTimeZoneOutput
4548
* @return string|null
4649
*/
47-
public function formatFrom(string $format): string|null
50+
public function formatFrom(string $format, DateTimeZone $dateTimeZoneOutput = new DateTimeZone(Timezones::UTC)): string|null
4851
{
49-
return $this->dateRange->getFrom()?->format($format);
52+
return $this->dateRange->getFrom($dateTimeZoneOutput)?->format($format);
5053
}
5154

5255
/**
5356
* Returns the "to" date as string.
5457
*
5558
* @param string $format
59+
* @param DateTimeZone $dateTimeZoneOutput
5660
* @return string|null
5761
*/
58-
public function formatTo(string $format): string|null
62+
public function formatTo(string $format, DateTimeZone $dateTimeZoneOutput = new DateTimeZone(Timezones::UTC)): string|null
5963
{
60-
return $this->dateRange->getTo()?->format($format);
64+
return $this->dateRange->getTo($dateTimeZoneOutput)?->format($format);
6165
}
6266

6367
/**
6468
* Returns the "from" date as DateTime object.
6569
*
70+
* @param DateTimeZone $dateTimeZoneOutput
6671
* @return DateTime|null
6772
*/
68-
public function getFrom(): DateTime|null
73+
public function getFrom(DateTimeZone $dateTimeZoneOutput = new DateTimeZone(Timezones::UTC)): DateTime|null
6974
{
70-
return $this->dateRange->getFrom();
75+
return $this->dateRange->getFrom($dateTimeZoneOutput);
7176
}
7277

7378
/**
7479
* Returns the "to" date as DateTime object.
7580
*
81+
* @param DateTimeZone $dateTimeZoneOutput
7682
* @return DateTime|null
7783
*/
78-
public function getTo(): DateTime|null
84+
public function getTo(DateTimeZone $dateTimeZoneOutput = new DateTimeZone(Timezones::UTC)): DateTime|null
7985
{
80-
return $this->dateRange->getTo();
86+
return $this->dateRange->getTo($dateTimeZoneOutput);
8187
}
8288

8389
/**
8490
* Returns the "from" date as DateTimeImmutable object.
8591
*
92+
* @param DateTimeZone $dateTimeZoneOutput
8693
* @return DateTimeImmutable|null
8794
*/
88-
public function getFromImmutable(): DateTimeImmutable|null
95+
public function getFromImmutable(DateTimeZone $dateTimeZoneOutput = new DateTimeZone(Timezones::UTC)): DateTimeImmutable|null
8996
{
90-
return $this->dateRange->getFromImmutable();
97+
return $this->dateRange->getFromImmutable($dateTimeZoneOutput);
9198
}
9299

93100
/**
94101
* Returns the "to" date as DateTimeImmutable object.
95102
*
103+
* @param DateTimeZone $dateTimeZoneOutput
96104
* @return DateTimeImmutable|null
97105
*/
98-
public function getToImmutable(): DateTimeImmutable|null
106+
public function getToImmutable(DateTimeZone $dateTimeZoneOutput = new DateTimeZone(Timezones::UTC)): DateTimeImmutable|null
99107
{
100-
return $this->dateRange->getToImmutable();
108+
return $this->dateRange->getToImmutable($dateTimeZoneOutput);
101109
}
102110
}

0 commit comments

Comments
 (0)