3 namespace Drupal\Tests\Component\Datetime;
5 use Drupal\Component\Datetime\DateTimePlus;
6 use PHPUnit\Framework\TestCase;
9 * @coversDefaultClass \Drupal\Component\Datetime\DateTimePlus
12 class DateTimePlusTest extends TestCase {
15 * Test creating dates from string and array input.
18 * Input argument for DateTimePlus.
19 * @param string $timezone
20 * Timezone argument for DateTimePlus.
21 * @param string $expected
22 * Expected output from DateTimePlus::format().
24 * @dataProvider providerTestDates
26 public function testDates($input, $timezone, $expected) {
27 $date = new DateTimePlus($input, $timezone);
28 $value = $date->format('c');
30 if (is_array($input)) {
31 $input = var_export($input, TRUE);
33 $this->assertEquals($expected, $value, sprintf("Test new DateTimePlus(%s, %s): should be %s, found %s.", $input, $timezone, $expected, $value));
37 * Test creating dates from string and array input.
40 * Input argument for DateTimePlus.
41 * @param string $timezone
42 * Timezone argument for DateTimePlus.
43 * @param string $expected
44 * Expected output from DateTimePlus::format().
46 * @dataProvider providerTestDateArrays
48 public function testDateArrays($input, $timezone, $expected) {
49 $date = DateTimePlus::createFromArray($input, $timezone);
50 $value = $date->format('c');
52 if (is_array($input)) {
53 $input = var_export($input, TRUE);
55 $this->assertEquals($expected, $value, sprintf("Test new DateTimePlus(%s, %s): should be %s, found %s.", $input, $timezone, $expected, $value));
61 * @param mixed $input1
62 * A DateTimePlus object.
63 * @param mixed $input2
64 * Date argument for DateTimePlus::diff method.
65 * @param bool $absolute
66 * Absolute flag for DateTimePlus::diff method.
67 * @param \DateInterval $expected
68 * The expected result of the DateTimePlus::diff operation.
70 * @dataProvider providerTestDateDiff
72 public function testDateDiff($input1, $input2, $absolute, \DateInterval $expected) {
73 $interval = $input1->diff($input2, $absolute);
74 $this->assertEquals($interval, $expected);
78 * Test date diff exception caused by invalid input.
80 * @param mixed $input1
81 * A DateTimePlus object.
82 * @param mixed $input2
83 * Date argument for DateTimePlus::diff method.
84 * @param bool $absolute
85 * Absolute flag for DateTimePlus::diff method.
87 * @dataProvider providerTestInvalidDateDiff
89 public function testInvalidDateDiff($input1, $input2, $absolute) {
90 $this->setExpectedException(\BadMethodCallException::class, 'Method Drupal\Component\Datetime\DateTimePlus::diff expects parameter 1 to be a \DateTime or \Drupal\Component\Datetime\DateTimePlus object');
91 $interval = $input1->diff($input2, $absolute);
95 * Test creating dates from invalid array input.
98 * Input argument for DateTimePlus.
99 * @param string $timezone
100 * Timezone argument for DateTimePlus.
101 * @param string $class
102 * The Exception subclass to expect to be thrown.
104 * @dataProvider providerTestInvalidDateArrays
106 public function testInvalidDateArrays($input, $timezone, $class) {
107 $this->setExpectedException($class);
108 $this->assertInstanceOf(
109 '\Drupal\Component\DateTimePlus',
110 DateTimePlus::createFromArray($input, $timezone)
115 * Test creating dates from timestamps, and manipulating timezones.
118 * Input argument for DateTimePlus::createFromTimestamp().
119 * @param array $initial
120 * An array containing:
121 * - 'timezone_initial' - Timezone argument for DateTimePlus.
122 * - 'format_initial' - Format argument for DateTimePlus.
123 * - 'expected_initial_date' - Expected output from DateTimePlus::format().
124 * - 'expected_initial_timezone' - Expected output from
125 * DateTimePlus::getTimeZone()::getName().
126 * - 'expected_initial_offset' - Expected output from DateTimePlus::getOffset().
127 * @param array $transform
128 * An array containing:
129 * - 'timezone_transform' - Argument to transform date to another timezone via
130 * DateTimePlus::setTimezone().
131 * - 'format_transform' - Format argument to use when transforming date to
133 * - 'expected_transform_date' - Expected output from DateTimePlus::format(),
134 * after timezone transform.
135 * - 'expected_transform_timezone' - Expected output from
136 * DateTimePlus::getTimeZone()::getName(), after timezone transform.
137 * - 'expected_transform_offset' - Expected output from
138 * DateTimePlus::getOffset(), after timezone transform.
140 * @dataProvider providerTestTimestamp
142 public function testTimestamp($input, array $initial, array $transform) {
143 // Initialize a new date object.
144 $date = DateTimePlus::createFromTimestamp($input, $initial['timezone']);
145 $this->assertDateTimestamp($date, $input, $initial, $transform);
149 * Test creating dates from datetime strings.
151 * @param string $input
152 * Input argument for DateTimePlus().
153 * @param array $initial
154 * @see testTimestamp()
155 * @param array $transform
156 * @see testTimestamp()
158 * @dataProvider providerTestDateTimestamp
160 public function testDateTimestamp($input, array $initial, array $transform) {
161 // Initialize a new date object.
162 $date = new DateTimePlus($input, $initial['timezone']);
163 $this->assertDateTimestamp($date, $input, $initial, $transform);
167 * Assertion helper for testTimestamp and testDateTimestamp since they need
168 * different dataProviders.
170 * @param \Drupal\Component\Datetime\DateTimePlus $date
171 * DateTimePlus to test.
172 * @input mixed $input
173 * The original input passed to the test method.
174 * @param array $initial
175 * @see testTimestamp()
176 * @param array $transform
177 * @see testTimestamp()
179 public function assertDateTimestamp($date, $input, $initial, $transform) {
181 $value = $date->format($initial['format']);
182 $this->assertEquals($initial['expected_date'], $value, sprintf("Test new DateTimePlus(%s, %s): should be %s, found %s.", $input, $initial['timezone'], $initial['expected_date'], $value));
184 // Check timezone name.
185 $value = $date->getTimeZone()->getName();
186 $this->assertEquals($initial['expected_timezone'], $value, sprintf("The current timezone is %s: should be %s.", $value, $initial['expected_timezone']));
189 $value = $date->getOffset();
190 $this->assertEquals($initial['expected_offset'], $value, sprintf("The current offset is %s: should be %s.", $value, $initial['expected_offset']));
192 // Transform the date to another timezone.
193 $date->setTimezone(new \DateTimeZone($transform['timezone']));
195 // Check transformed format.
196 $value = $date->format($transform['format']);
197 $this->assertEquals($transform['expected_date'], $value, sprintf("Test \$date->setTimezone(new \\DateTimeZone(%s)): should be %s, found %s.", $transform['timezone'], $transform['expected_date'], $value));
199 // Check transformed timezone.
200 $value = $date->getTimeZone()->getName();
201 $this->assertEquals($transform['expected_timezone'], $value, sprintf("The current timezone should be %s, found %s.", $transform['expected_timezone'], $value));
203 // Check transformed offset.
204 $value = $date->getOffset();
205 $this->assertEquals($transform['expected_offset'], $value, sprintf("The current offset should be %s, found %s.", $transform['expected_offset'], $value));
209 * Test creating dates from format strings.
211 * @param string $input
212 * Input argument for DateTimePlus.
213 * @param string $timezone
214 * Timezone argument for DateTimePlus.
215 * @param string $format_date
216 * Format argument for DateTimePlus::format().
217 * @param string $expected
218 * Expected output from DateTimePlus::format().
220 * @dataProvider providerTestDateFormat
222 public function testDateFormat($input, $timezone, $format, $format_date, $expected) {
223 $date = DateTimePlus::createFromFormat($format, $input, $timezone);
224 $value = $date->format($format_date);
225 $this->assertEquals($expected, $value, sprintf("Test new DateTimePlus(%s, %s, %s): should be %s, found %s.", $input, $timezone, $format, $expected, $value));
229 * Test invalid date handling.
231 * @param mixed $input
232 * Input argument for DateTimePlus.
233 * @param string $timezone
234 * Timezone argument for DateTimePlus.
235 * @param string $format
236 * Format argument for DateTimePlus.
237 * @param string $message
238 * Message to print if no errors are thrown by the invalid dates.
239 * @param string $class
240 * The Exception subclass to expect to be thrown.
242 * @dataProvider providerTestInvalidDates
244 public function testInvalidDates($input, $timezone, $format, $message, $class) {
245 $this->setExpectedException($class);
246 DateTimePlus::createFromFormat($format, $input, $timezone);
250 * Tests that DrupalDateTime can detect the right timezone to use.
251 * When specified or not.
253 * @param mixed $input
254 * Input argument for DateTimePlus.
255 * @param mixed $timezone
256 * Timezone argument for DateTimePlus.
257 * @param string $expected_timezone
258 * Expected timezone returned from DateTimePlus::getTimezone::getName().
259 * @param string $message
260 * Message to print on test failure.
262 * @dataProvider providerTestDateTimezone
264 public function testDateTimezone($input, $timezone, $expected_timezone, $message) {
265 $date = new DateTimePlus($input, $timezone);
266 $timezone = $date->getTimezone()->getName();
267 $this->assertEquals($timezone, $expected_timezone, $message);
271 * Test that DrupalDateTime can detect the right timezone to use when
272 * constructed from a datetime object.
274 public function testDateTimezoneWithDateTimeObject() {
275 // Create a date object with another date object.
276 $input = new \DateTime('now', new \DateTimeZone('Pacific/Midway'));
278 $expected_timezone = 'Pacific/Midway';
279 $message = 'DateTimePlus uses the specified timezone if provided.';
281 $date = DateTimePlus::createFromDateTime($input, $timezone);
282 $timezone = $date->getTimezone()->getName();
283 $this->assertEquals($timezone, $expected_timezone, $message);
287 * Provides data for date tests.
290 * An array of arrays, each containing the input parameters for
291 * DateTimePlusTest::testDates().
293 * @see DateTimePlusTest::testDates()
295 public function providerTestDates() {
298 // Create date object from datetime string.
299 ['2009-03-07 10:30', 'America/Chicago', '2009-03-07T10:30:00-06:00'],
300 // Same during daylight savings time.
301 ['2009-06-07 10:30', 'America/Chicago', '2009-06-07T10:30:00-05:00'],
302 // Create date object from date string.
303 ['2009-03-07', 'America/Chicago', '2009-03-07T00:00:00-06:00'],
304 // Same during daylight savings time.
305 ['2009-06-07', 'America/Chicago', '2009-06-07T00:00:00-05:00'],
306 // Create date object from date string.
307 ['2009-03-07 10:30', 'Australia/Canberra', '2009-03-07T10:30:00+11:00'],
308 // Same during daylight savings time.
309 ['2009-06-07 10:30', 'Australia/Canberra', '2009-06-07T10:30:00+10:00'],
312 // On 32-bit systems, timestamps are limited to 1901-2038.
313 if (PHP_INT_SIZE > 4) {
314 // Create a date object in the distant past.
315 // @see https://www.drupal.org/node/2795489#comment-12127088
316 if (version_compare(PHP_VERSION, '5.6.15', '>=')) {
317 $dates[] = ['1809-02-12 10:30', 'America/Chicago', '1809-02-12T10:30:00-06:00'];
319 // Create a date object in the far future.
320 $dates[] = ['2345-01-02 02:04', 'UTC', '2345-01-02T02:04:00+00:00'];
327 * Provides data for date tests.
330 * An array of arrays, each containing the input parameters for
331 * DateTimePlusTest::testDates().
333 * @see DateTimePlusTest::testDates()
335 public function providerTestDateArrays() {
338 // Create date object from date array, date only.
339 [['year' => 2010, 'month' => 2, 'day' => 28], 'America/Chicago', '2010-02-28T00:00:00-06:00'],
340 // Create date object from date array with hour.
341 [['year' => 2010, 'month' => 2, 'day' => 28, 'hour' => 10], 'America/Chicago', '2010-02-28T10:00:00-06:00'],
342 // Create date object from date array, date only.
343 [['year' => 2010, 'month' => 2, 'day' => 28], 'Europe/Berlin', '2010-02-28T00:00:00+01:00'],
344 // Create date object from date array with hour.
345 [['year' => 2010, 'month' => 2, 'day' => 28, 'hour' => 10], 'Europe/Berlin', '2010-02-28T10:00:00+01:00'],
348 // On 32-bit systems, timestamps are limited to 1901-2038.
349 if (PHP_INT_SIZE > 4) {
350 // Create a date object in the distant past.
351 // @see https://www.drupal.org/node/2795489#comment-12127088
352 if (version_compare(PHP_VERSION, '5.6.15', '>=')) {
353 $dates[] = [['year' => 1809, 'month' => 2, 'day' => 12], 'America/Chicago', '1809-02-12T00:00:00-06:00'];
355 // Create a date object in the far future.
356 $dates[] = [['year' => 2345, 'month' => 1, 'day' => 2], 'UTC', '2345-01-02T00:00:00+00:00'];
363 * Provides data for testDateFormats.
366 * An array of arrays, each containing:
367 * - 'input' - Input to DateTimePlus.
368 * - 'timezone' - Timezone for DateTimePlus.
369 * - 'format' - Date format for DateTimePlus.
370 * - 'format_date' - Date format for use in $date->format() method.
371 * - 'expected' - The expected return from DateTimePlus.
373 * @see testDateFormats()
375 public function providerTestDateFormat() {
377 // Create a year-only date.
378 ['2009', NULL, 'Y', 'Y', '2009'],
379 // Create a month and year-only date.
380 ['2009-10', NULL, 'Y-m', 'Y-m', '2009-10'],
381 // Create a time-only date.
382 ['T10:30:00', NULL, '\TH:i:s', 'H:i:s', '10:30:00'],
383 // Create a time-only date.
384 ['10:30:00', NULL, 'H:i:s', 'H:i:s', '10:30:00'],
389 * Provides data for testInvalidDates.
392 * An array of arrays, each containing:
393 * - 'input' - Input for DateTimePlus.
394 * - 'timezone' - Timezone for DateTimePlus.
395 * - 'format' - Format for DateTimePlus.
396 * - 'message' - Message to display on failure.
398 * @see testInvalidDates
400 public function providerTestInvalidDates() {
402 // Test for invalid month names when we are using a short version
404 ['23 abc 2012', NULL, 'd M Y', "23 abc 2012 contains an invalid month name and did not produce errors.", \InvalidArgumentException::class],
405 // Test for invalid hour.
406 ['0000-00-00T45:30:00', NULL, 'Y-m-d\TH:i:s', "0000-00-00T45:30:00 contains an invalid hour and did not produce errors.", \UnexpectedValueException::class],
407 // Test for invalid day.
408 ['0000-00-99T05:30:00', NULL, 'Y-m-d\TH:i:s', "0000-00-99T05:30:00 contains an invalid day and did not produce errors.", \UnexpectedValueException::class],
409 // Test for invalid month.
410 ['0000-75-00T15:30:00', NULL, 'Y-m-d\TH:i:s', "0000-75-00T15:30:00 contains an invalid month and did not produce errors.", \UnexpectedValueException::class],
411 // Test for invalid year.
412 ['11-08-01T15:30:00', NULL, 'Y-m-d\TH:i:s', "11-08-01T15:30:00 contains an invalid year and did not produce errors.", \UnexpectedValueException::class],
418 * Data provider for testInvalidDateArrays.
421 * An array of arrays, each containing:
422 * - 'input' - Input for DateTimePlus.
423 * - 'timezone' - Timezone for DateTimePlus.
425 * @see testInvalidDateArrays
427 public function providerTestInvalidDateArrays() {
429 // One year larger than the documented upper limit of checkdate().
430 [['year' => 32768, 'month' => 1, 'day' => 8, 'hour' => 8, 'minute' => 0, 'second' => 0], 'America/Chicago', \InvalidArgumentException::class],
431 // One year smaller than the documented lower limit of checkdate().
432 [['year' => 0, 'month' => 1, 'day' => 8, 'hour' => 8, 'minute' => 0, 'second' => 0], 'America/Chicago', \InvalidArgumentException::class],
433 // Test for invalid month from date array.
434 [['year' => 2010, 'month' => 27, 'day' => 8, 'hour' => 8, 'minute' => 0, 'second' => 0], 'America/Chicago', \InvalidArgumentException::class],
435 // Test for invalid hour from date array.
436 [['year' => 2010, 'month' => 2, 'day' => 28, 'hour' => 80, 'minute' => 0, 'second' => 0], 'America/Chicago', \InvalidArgumentException::class],
437 // Test for invalid minute from date array.
438 [['year' => 2010, 'month' => 7, 'day' => 8, 'hour' => 8, 'minute' => 88, 'second' => 0], 'America/Chicago', \InvalidArgumentException::class],
439 // Regression test for https://www.drupal.org/node/2084455.
440 [['hour' => 59, 'minute' => 1, 'second' => 1], 'America/Chicago', \InvalidArgumentException::class],
445 * Provides data for testDateTimezone.
448 * An array of arrays, each containing:
449 * - 'date' - Date string or object for DateTimePlus.
450 * - 'timezone' - Timezone string for DateTimePlus.
451 * - 'expected' - Expected return from DateTimePlus::getTimezone()::getName().
452 * - 'message' - Message to display on test failure.
454 * @see testDateTimezone
456 public function providerTestDateTimezone() {
457 // Use a common date for most of the tests.
458 $date_string = '2007-01-31 21:00:00';
460 // Detect the system timezone.
461 $system_timezone = date_default_timezone_get();
464 // Create a date object with an unspecified timezone, which should
465 // end up using the system timezone.
466 [$date_string, NULL, $system_timezone, 'DateTimePlus uses the system timezone when there is no site timezone.'],
467 // Create a date object with a specified timezone name.
468 [$date_string, 'America/Yellowknife', 'America/Yellowknife', 'DateTimePlus uses the specified timezone if provided.'],
469 // Create a date object with a timezone object.
470 [$date_string, new \DateTimeZone('Australia/Canberra'), 'Australia/Canberra', 'DateTimePlus uses the specified timezone if provided.'],
471 // Create a date object with another date object.
472 [new DateTimePlus('now', 'Pacific/Midway'), NULL, 'Pacific/Midway', 'DateTimePlus uses the specified timezone if provided.'],
477 * Provides data for testTimestamp.
480 * An array of arrays, each containing the arguments required for
481 * self::testTimestamp().
483 * @see testTimestamp()
485 public function providerTestTimestamp() {
487 // Create date object from a unix timestamp and display it in
494 'expected_date' => '1970-01-01T00:00:00+00:00',
495 'expected_timezone' => 'UTC',
496 'expected_offset' => 0,
499 'timezone' => 'America/Los_Angeles',
501 'expected_date' => '1969-12-31T16:00:00-08:00',
502 'expected_timezone' => 'America/Los_Angeles',
503 'expected_offset' => '-28800',
506 // Create a date using the timestamp of zero, then display its
507 // value both in UTC and the local timezone.
511 'timezone' => 'America/Los_Angeles',
513 'expected_date' => '1969-12-31T16:00:00-08:00',
514 'expected_timezone' => 'America/Los_Angeles',
515 'expected_offset' => '-28800',
520 'expected_date' => '1970-01-01T00:00:00+00:00',
521 'expected_timezone' => 'UTC',
522 'expected_offset' => 0,
529 * Provides data for testDateTimestamp.
532 * An array of arrays, each containing the arguments required for
533 * self::testDateTimestamp().
535 * @see testDateTimestamp()
537 public function providerTestDateTimestamp() {
539 // Create date object from datetime string in UTC, and convert
540 // it to a local date.
542 'input' => '1970-01-01 00:00:00',
546 'expected_date' => '1970-01-01T00:00:00+00:00',
547 'expected_timezone' => 'UTC',
548 'expected_offset' => 0,
551 'timezone' => 'America/Los_Angeles',
553 'expected_date' => '1969-12-31T16:00:00-08:00',
554 'expected_timezone' => 'America/Los_Angeles',
555 'expected_offset' => '-28800',
558 // Convert the local time to UTC using string input.
560 'input' => '1969-12-31 16:00:00',
562 'timezone' => 'America/Los_Angeles',
564 'expected_date' => '1969-12-31T16:00:00-08:00',
565 'expected_timezone' => 'America/Los_Angeles',
566 'expected_offset' => '-28800',
571 'expected_date' => '1970-01-01T00:00:00+00:00',
572 'expected_timezone' => 'UTC',
573 'expected_offset' => 0,
576 // Convert the local time to UTC using string input.
578 'input' => '1969-12-31 16:00:00',
580 'timezone' => 'Europe/Warsaw',
582 'expected_date' => '1969-12-31T16:00:00+01:00',
583 'expected_timezone' => 'Europe/Warsaw',
584 'expected_offset' => '+3600',
589 'expected_date' => '1969-12-31T15:00:00+00:00',
590 'expected_timezone' => 'UTC',
591 'expected_offset' => 0,
598 * Provides data for date tests.
601 * An array of arrays, each containing the input parameters for
602 * DateTimePlusTest::testDateDiff().
604 * @see DateTimePlusTest::testDateDiff()
606 public function providerTestDateDiff() {
608 $empty_interval = new \DateInterval('PT0S');
610 $positive_19_hours = new \DateInterval('PT19H');
612 $positive_18_hours = new \DateInterval('PT18H');
614 $positive_1_hour = new \DateInterval('PT1H');
616 $negative_1_hour = new \DateInterval('PT1H');
617 $negative_1_hour->invert = 1;
620 // There should be a 19 hour time interval between
621 // new years in Sydney and new years in LA in year 2000.
623 'input2' => DateTimePlus::createFromFormat('Y-m-d H:i:s', '2000-01-01 00:00:00', new \DateTimeZone('Australia/Sydney')),
624 'input1' => DateTimePlus::createFromFormat('Y-m-d H:i:s', '2000-01-01 00:00:00', new \DateTimeZone('America/Los_Angeles')),
626 'expected' => $positive_19_hours,
628 // In 1970 Sydney did not observe daylight savings time
629 // So there is only a 18 hour time interval.
631 'input2' => DateTimePlus::createFromFormat('Y-m-d H:i:s', '1970-01-01 00:00:00', new \DateTimeZone('Australia/Sydney')),
632 'input1' => DateTimePlus::createFromFormat('Y-m-d H:i:s', '1970-01-01 00:00:00', new \DateTimeZone('America/Los_Angeles')),
634 'expected' => $positive_18_hours,
637 'input1' => DateTimePlus::createFromFormat('U', 3600, new \DateTimeZone('America/Los_Angeles')),
638 'input2' => DateTimePlus::createFromFormat('U', 0, new \DateTimeZone('UTC')),
640 'expected' => $negative_1_hour,
643 'input1' => DateTimePlus::createFromFormat('U', 3600),
644 'input2' => DateTimePlus::createFromFormat('U', 0),
646 'expected' => $negative_1_hour,
649 'input1' => DateTimePlus::createFromFormat('U', 3600),
650 'input2' => \DateTime::createFromFormat('U', 0),
652 'expected' => $negative_1_hour,
655 'input1' => DateTimePlus::createFromFormat('U', 3600),
656 'input2' => DateTimePlus::createFromFormat('U', 0),
658 'expected' => $positive_1_hour,
661 'input1' => DateTimePlus::createFromFormat('U', 3600),
662 'input2' => \DateTime::createFromFormat('U', 0),
664 'expected' => $positive_1_hour,
667 'input1' => DateTimePlus::createFromFormat('U', 0),
668 'input2' => DateTimePlus::createFromFormat('U', 0),
670 'expected' => $empty_interval,
676 * Provides data for date tests.
679 * An array of arrays, each containing the input parameters for
680 * DateTimePlusTest::testInvalidDateDiff().
682 * @see DateTimePlusTest::testInvalidDateDiff()
684 public function providerTestInvalidDateDiff() {
687 'input1' => DateTimePlus::createFromFormat('U', 3600),
688 'input2' => '1970-01-01 00:00:00',
692 'input1' => DateTimePlus::createFromFormat('U', 3600),
700 * Tests invalid values passed to constructor.
702 * @param string $time
703 * A date/time string.
704 * @param string[] $errors
705 * An array of error messages.
707 * @covers ::__construct
709 * @dataProvider providerTestInvalidConstructor
711 public function testInvalidConstructor($time, array $errors) {
712 $date = new DateTimePlus($time);
714 $this->assertEquals(TRUE, $date->hasErrors());
715 $this->assertEquals($errors, $date->getErrors());
719 * Provider for testInvalidConstructor().
722 * An array of invalid date/time strings, and corresponding error messages.
724 public function providerTestInvalidConstructor() {
729 'The timezone could not be found in the database',
730 'Unexpected character',
731 'Double timezone specification',
737 'Unexpected character',
738 'The timezone could not be found in the database',
744 'The timezone could not be found in the database',
745 'Unexpected character',
746 'Double timezone specification',
752 'The timezone could not be found in the database',
753 'Unexpected character',
754 'Double timezone specification',
760 'Unexpected character',
764 'YYYY-MM-DD hh:mm:ss',
766 'The timezone could not be found in the database',
767 'Unexpected character',
768 'Double timezone specification',
772 '2017-03-07 25:70:80',
774 'Unexpected character',
775 'Double time specification',
779 'lorem ipsum dolor sit amet',
781 'The timezone could not be found in the database',
782 'Double timezone specification',
789 * Tests the $settings['validate_format'] parameter in ::createFromFormat().
791 public function testValidateFormat() {
792 // Check that an input that does not strictly follow the input format will
793 // produce the desired date. In this case the year string '11' doesn't
794 // precisely match the 'Y' formater parameter, but PHP will parse it
795 // regardless. However, when formatted with the same string, the year will
796 // be output with four digits. With the ['validate_format' => FALSE]
797 // $settings, this will not thrown an exception.
798 $date = DateTimePlus::createFromFormat('Y-m-d H:i:s', '11-03-31 17:44:00', 'UTC', ['validate_format' => FALSE]);
799 $this->assertEquals('0011-03-31 17:44:00', $date->format('Y-m-d H:i:s'));
801 // Parse the same date with ['validate_format' => TRUE] and make sure we
802 // get the expected exception.
803 $this->setExpectedException(\UnexpectedValueException::class);
804 $date = DateTimePlus::createFromFormat('Y-m-d H:i:s', '11-03-31 17:44:00', 'UTC', ['validate_format' => TRUE]);
808 * Tests that object methods are chainable.
812 public function testChainable() {
813 $date = new DateTimePlus('now', 'Australia/Sydney');
815 $date->setTimestamp(12345678);
816 $rendered = $date->render();
817 $this->assertEquals('1970-05-24 07:21:18 Australia/Sydney', $rendered);
819 $date->setTimestamp(23456789);
820 $rendered = $date->setTimezone(new \DateTimeZone('America/New_York'))->render();
821 $this->assertEquals('1970-09-29 07:46:29 America/New_York', $rendered);
823 $date = DateTimePlus::createFromFormat('Y-m-d H:i:s', '1970-05-24 07:21:18', new \DateTimeZone('Australia/Sydney'))
824 ->setTimezone(new \DateTimeZone('America/New_York'));
825 $rendered = $date->render();
826 $this->assertInstanceOf(DateTimePlus::class, $date);
827 $this->assertEquals(12345678, $date->getTimestamp());
828 $this->assertEquals('1970-05-23 17:21:18 America/New_York', $rendered);
832 * Tests that non-chainable methods work.
836 public function testChainableNonChainable() {
837 $datetime1 = new DateTimePlus('2009-10-11 12:00:00');
838 $datetime2 = new DateTimePlus('2009-10-13 12:00:00');
839 $interval = $datetime1->diff($datetime2);
840 $this->assertInstanceOf(\DateInterval::class, $interval);
841 $this->assertEquals('+2 days', $interval->format('%R%a days'));
845 * Tests that chained calls to non-existent functions throw an exception.
849 public function testChainableNonCallable() {
850 $this->setExpectedException(\BadMethodCallException::class, 'Call to undefined method Drupal\Component\Datetime\DateTimePlus::nonexistent()');
851 $date = new DateTimePlus('now', 'Australia/Sydney');
852 $date->setTimezone(new \DateTimeZone('America/New_York'))->nonexistent();