1012 lines
33 KiB
PHP
1012 lines
33 KiB
PHP
<?php
|
|
|
|
/*
|
|
* This file is part of the Symfony package.
|
|
*
|
|
* (c) Fabien Potencier <fabien@symfony.com>
|
|
*
|
|
* For the full copyright and license information, please view the LICENSE
|
|
* file that was distributed with this source code.
|
|
*/
|
|
|
|
namespace Symfony\Component\Intl\Tests\DateFormatter;
|
|
|
|
use PHPUnit\Framework\TestCase;
|
|
use Symfony\Component\Intl\DateFormatter\IntlDateFormatter;
|
|
use Symfony\Component\Intl\Globals\IntlGlobals;
|
|
use Symfony\Component\Intl\Intl;
|
|
use Symfony\Component\Intl\Util\IcuVersion;
|
|
|
|
/**
|
|
* Test case for IntlDateFormatter implementations.
|
|
*
|
|
* @author Bernhard Schussek <bschussek@gmail.com>
|
|
*/
|
|
abstract class AbstractIntlDateFormatterTest extends TestCase
|
|
{
|
|
private $defaultLocale;
|
|
|
|
protected function setUp()
|
|
{
|
|
parent::setUp();
|
|
|
|
$this->defaultLocale = \Locale::getDefault();
|
|
\Locale::setDefault('en');
|
|
}
|
|
|
|
protected function tearDown()
|
|
{
|
|
parent::tearDown();
|
|
|
|
\Locale::setDefault($this->defaultLocale);
|
|
}
|
|
|
|
/**
|
|
* When a time zone is not specified, it uses the system default however it returns null in the getter method.
|
|
*
|
|
* @see StubIntlDateFormatterTest::testDefaultTimeZoneIntl()
|
|
*/
|
|
public function testConstructorDefaultTimeZone()
|
|
{
|
|
$formatter = $this->getDateFormatter('en', IntlDateFormatter::MEDIUM, IntlDateFormatter::SHORT);
|
|
|
|
$this->assertEquals(date_default_timezone_get(), $formatter->getTimeZoneId());
|
|
|
|
$this->assertEquals(
|
|
$this->getDateTime(0, $formatter->getTimeZoneId())->format('M j, Y, g:i A'),
|
|
$formatter->format(0)
|
|
);
|
|
}
|
|
|
|
public function testConstructorWithoutDateType()
|
|
{
|
|
$formatter = new IntlDateFormatter('en', null, IntlDateFormatter::SHORT, 'UTC', IntlDateFormatter::GREGORIAN);
|
|
|
|
$this->assertSame('EEEE, LLLL d, y, h:mm a', $formatter->getPattern());
|
|
}
|
|
|
|
public function testConstructorWithoutTimeType()
|
|
{
|
|
$formatter = new IntlDateFormatter('en', IntlDateFormatter::SHORT, null, 'UTC', IntlDateFormatter::GREGORIAN);
|
|
|
|
$this->assertSame('M/d/yy, h:mm:ss a zzzz', $formatter->getPattern());
|
|
}
|
|
|
|
/**
|
|
* @dataProvider formatProvider
|
|
*/
|
|
public function testFormat($pattern, $timestamp, $expected)
|
|
{
|
|
$errorCode = IntlGlobals::U_ZERO_ERROR;
|
|
$errorMessage = 'U_ZERO_ERROR';
|
|
|
|
$formatter = $this->getDefaultDateFormatter($pattern);
|
|
$this->assertSame($expected, $formatter->format($timestamp));
|
|
$this->assertIsIntlSuccess($formatter, $errorMessage, $errorCode);
|
|
}
|
|
|
|
public function formatProvider()
|
|
{
|
|
$dateTime = new \DateTime('@0');
|
|
$dateTimeImmutable = new \DateTimeImmutable('@0');
|
|
|
|
$formatData = [
|
|
/* general */
|
|
['y-M-d', 0, '1970-1-1'],
|
|
["EEE, MMM d, ''yy", 0, "Thu, Jan 1, '70"],
|
|
['h:mm a', 0, '12:00 AM'],
|
|
['yyyyy.MMMM.dd hh:mm aaa', 0, '01970.January.01 12:00 AM'],
|
|
|
|
/* escaping */
|
|
["'M'", 0, 'M'],
|
|
["'yy'", 0, 'yy'],
|
|
["'''yy'", 0, "'yy"],
|
|
["''y", 0, "'1970"],
|
|
["''yy", 0, "'70"],
|
|
["H 'o'' clock'", 0, "0 o' clock"],
|
|
|
|
/* month */
|
|
['M', 0, '1'],
|
|
['MM', 0, '01'],
|
|
['MMM', 0, 'Jan'],
|
|
['MMMM', 0, 'January'],
|
|
['MMMMM', 0, 'J'],
|
|
['MMMMMM', 0, '000001'],
|
|
|
|
['L', 0, '1'],
|
|
['LL', 0, '01'],
|
|
['LLL', 0, 'Jan'],
|
|
['LLLL', 0, 'January'],
|
|
['LLLLL', 0, 'J'],
|
|
['LLLLLL', 0, '000001'],
|
|
|
|
/* year */
|
|
['y', 0, '1970'],
|
|
['yy', 0, '70'],
|
|
['yyy', 0, '1970'],
|
|
['yyyy', 0, '1970'],
|
|
['yyyyy', 0, '01970'],
|
|
['yyyyyy', 0, '001970'],
|
|
|
|
/* day */
|
|
['d', 0, '1'],
|
|
['dd', 0, '01'],
|
|
['ddd', 0, '001'],
|
|
|
|
/* quarter */
|
|
['Q', 0, '1'],
|
|
['QQ', 0, '01'],
|
|
['QQQ', 0, 'Q1'],
|
|
['QQQQ', 0, '1st quarter'],
|
|
['QQQQQ', 0, '1st quarter'],
|
|
|
|
['q', 0, '1'],
|
|
['qq', 0, '01'],
|
|
['qqq', 0, 'Q1'],
|
|
['qqqq', 0, '1st quarter'],
|
|
['qqqqq', 0, '1st quarter'],
|
|
|
|
// 4 months
|
|
['Q', 7776000, '2'],
|
|
['QQ', 7776000, '02'],
|
|
['QQQ', 7776000, 'Q2'],
|
|
['QQQQ', 7776000, '2nd quarter'],
|
|
|
|
// 7 months
|
|
['QQQQ', 15638400, '3rd quarter'],
|
|
|
|
// 10 months
|
|
['QQQQ', 23587200, '4th quarter'],
|
|
|
|
/* 12-hour (1-12) */
|
|
['h', 0, '12'],
|
|
['hh', 0, '12'],
|
|
['hhh', 0, '012'],
|
|
|
|
['h', 1, '12'],
|
|
['h', 3600, '1'],
|
|
['h', 43200, '12'], // 12 hours
|
|
|
|
/* day of year */
|
|
['D', 0, '1'],
|
|
['D', 86400, '2'], // 1 day
|
|
['D', 31536000, '1'], // 1 year
|
|
['D', 31622400, '2'], // 1 year + 1 day
|
|
|
|
/* day of week */
|
|
['E', 0, 'Thu'],
|
|
['EE', 0, 'Thu'],
|
|
['EEE', 0, 'Thu'],
|
|
['EEEE', 0, 'Thursday'],
|
|
['EEEEE', 0, 'T'],
|
|
['EEEEEE', 0, 'Th'],
|
|
|
|
['E', 1296540000, 'Tue'], // 2011-02-01
|
|
['E', 1296950400, 'Sun'], // 2011-02-06
|
|
|
|
/* am/pm marker */
|
|
['a', 0, 'AM'],
|
|
['aa', 0, 'AM'],
|
|
['aaa', 0, 'AM'],
|
|
['aaaa', 0, 'AM'],
|
|
|
|
// 12 hours
|
|
['a', 43200, 'PM'],
|
|
['aa', 43200, 'PM'],
|
|
['aaa', 43200, 'PM'],
|
|
['aaaa', 43200, 'PM'],
|
|
|
|
/* 24-hour (0-23) */
|
|
['H', 0, '0'],
|
|
['HH', 0, '00'],
|
|
['HHH', 0, '000'],
|
|
|
|
['H', 1, '0'],
|
|
['H', 3600, '1'],
|
|
['H', 43200, '12'],
|
|
['H', 46800, '13'],
|
|
|
|
/* 24-hour (1-24) */
|
|
['k', 0, '24'],
|
|
['kk', 0, '24'],
|
|
['kkk', 0, '024'],
|
|
|
|
['k', 1, '24'],
|
|
['k', 3600, '1'],
|
|
['k', 43200, '12'],
|
|
['k', 46800, '13'],
|
|
|
|
/* 12-hour (0-11) */
|
|
['K', 0, '0'],
|
|
['KK', 0, '00'],
|
|
['KKK', 0, '000'],
|
|
|
|
['K', 1, '0'],
|
|
['K', 3600, '1'],
|
|
['K', 43200, '0'], // 12 hours
|
|
|
|
/* minute */
|
|
['m', 0, '0'],
|
|
['mm', 0, '00'],
|
|
['mmm', 0, '000'],
|
|
|
|
['m', 1, '0'],
|
|
['m', 60, '1'],
|
|
['m', 120, '2'],
|
|
['m', 180, '3'],
|
|
['m', 3600, '0'],
|
|
['m', 3660, '1'],
|
|
['m', 43200, '0'], // 12 hours
|
|
|
|
/* second */
|
|
['s', 0, '0'],
|
|
['ss', 0, '00'],
|
|
['sss', 0, '000'],
|
|
|
|
['s', 1, '1'],
|
|
['s', 2, '2'],
|
|
['s', 5, '5'],
|
|
['s', 30, '30'],
|
|
['s', 59, '59'],
|
|
['s', 60, '0'],
|
|
['s', 120, '0'],
|
|
['s', 180, '0'],
|
|
['s', 3600, '0'],
|
|
['s', 3601, '1'],
|
|
['s', 3630, '30'],
|
|
['s', 43200, '0'], // 12 hours
|
|
];
|
|
|
|
/* general, DateTime */
|
|
$formatData[] = ['y-M-d', $dateTime, '1970-1-1'];
|
|
$formatData[] = ["EEE, MMM d, ''yy", $dateTime, "Thu, Jan 1, '70"];
|
|
$formatData[] = ['h:mm a', $dateTime, '12:00 AM'];
|
|
$formatData[] = ['yyyyy.MMMM.dd hh:mm aaa', $dateTime, '01970.January.01 12:00 AM'];
|
|
|
|
/* general, DateTimeImmutable */
|
|
$formatData[] = ['y-M-d', $dateTimeImmutable, '1970-1-1'];
|
|
$formatData[] = ["EEE, MMM d, ''yy", $dateTimeImmutable, "Thu, Jan 1, '70"];
|
|
$formatData[] = ['h:mm a', $dateTimeImmutable, '12:00 AM'];
|
|
$formatData[] = ['yyyyy.MMMM.dd hh:mm aaa', $dateTimeImmutable, '01970.January.01 12:00 AM'];
|
|
|
|
if (IcuVersion::compare(Intl::getIcuVersion(), '59.1', '>=', 1)) {
|
|
// Before ICU 59.1 GMT was used instead of UTC
|
|
$formatData[] = ["yyyy.MM.dd 'at' HH:mm:ss zzz", 0, '1970.01.01 at 00:00:00 UTC'];
|
|
$formatData[] = ['K:mm a, z', 0, '0:00 AM, UTC'];
|
|
$formatData[] = ["yyyy.MM.dd 'at' HH:mm:ss zzz", $dateTime, '1970.01.01 at 00:00:00 UTC'];
|
|
$formatData[] = ['K:mm a, z', $dateTime, '0:00 AM, UTC'];
|
|
}
|
|
|
|
return $formatData;
|
|
}
|
|
|
|
/**
|
|
* @requires PHP 5.5.10
|
|
*/
|
|
public function testFormatUtcAndGmtAreSplit()
|
|
{
|
|
$pattern = "yyyy.MM.dd 'at' HH:mm:ss zzz";
|
|
$gmtFormatter = $this->getDateFormatter('en', IntlDateFormatter::MEDIUM, IntlDateFormatter::SHORT, 'GMT', IntlDateFormatter::GREGORIAN, $pattern);
|
|
$utcFormatter = $this->getDateFormatter('en', IntlDateFormatter::MEDIUM, IntlDateFormatter::SHORT, 'UTC', IntlDateFormatter::GREGORIAN, $pattern);
|
|
|
|
$this->assertSame('1970.01.01 at 00:00:00 GMT', $gmtFormatter->format(new \DateTime('@0')));
|
|
$this->assertSame('1970.01.01 at 00:00:00 UTC', $utcFormatter->format(new \DateTime('@0')));
|
|
$this->assertSame('1970.01.01 at 00:00:00 GMT', $gmtFormatter->format(new \DateTimeImmutable('@0')));
|
|
$this->assertSame('1970.01.01 at 00:00:00 UTC', $utcFormatter->format(new \DateTimeImmutable('@0')));
|
|
}
|
|
|
|
/**
|
|
* @dataProvider formatErrorProvider
|
|
*/
|
|
public function testFormatIllegalArgumentError($pattern, $timestamp, $errorMessage)
|
|
{
|
|
$errorCode = IntlGlobals::U_ILLEGAL_ARGUMENT_ERROR;
|
|
|
|
$formatter = $this->getDefaultDateFormatter($pattern);
|
|
$this->assertFalse($formatter->format($timestamp));
|
|
$this->assertIsIntlFailure($formatter, $errorMessage, $errorCode);
|
|
}
|
|
|
|
public function formatErrorProvider()
|
|
{
|
|
return [
|
|
['y-M-d', 'foobar', 'datefmt_format: string \'foobar\' is not numeric, which would be required for it to be a valid date: U_ILLEGAL_ARGUMENT_ERROR'],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @dataProvider formatWithTimezoneProvider
|
|
*/
|
|
public function testFormatWithTimezone($timestamp, $timezone, $expected)
|
|
{
|
|
$pattern = 'yyyy-MM-dd HH:mm:ss';
|
|
$formatter = $this->getDateFormatter('en', IntlDateFormatter::MEDIUM, IntlDateFormatter::SHORT, $timezone, IntlDateFormatter::GREGORIAN, $pattern);
|
|
$this->assertSame($expected, $formatter->format($timestamp));
|
|
}
|
|
|
|
public function formatWithTimezoneProvider()
|
|
{
|
|
$data = [
|
|
[0, 'UTC', '1970-01-01 00:00:00'],
|
|
[0, 'GMT', '1970-01-01 00:00:00'],
|
|
[0, 'GMT-03:00', '1969-12-31 21:00:00'],
|
|
[0, 'GMT+03:00', '1970-01-01 03:00:00'],
|
|
[0, 'Europe/Zurich', '1970-01-01 01:00:00'],
|
|
[0, 'Europe/Paris', '1970-01-01 01:00:00'],
|
|
[0, 'Africa/Cairo', '1970-01-01 02:00:00'],
|
|
[0, 'Africa/Casablanca', '1970-01-01 00:00:00'],
|
|
[0, 'Africa/Djibouti', '1970-01-01 03:00:00'],
|
|
[0, 'Africa/Johannesburg', '1970-01-01 02:00:00'],
|
|
[0, 'America/Antigua', '1969-12-31 20:00:00'],
|
|
[0, 'America/Toronto', '1969-12-31 19:00:00'],
|
|
[0, 'America/Vancouver', '1969-12-31 16:00:00'],
|
|
[0, 'Asia/Aqtau', '1970-01-01 05:00:00'],
|
|
[0, 'Asia/Bangkok', '1970-01-01 07:00:00'],
|
|
[0, 'Asia/Dubai', '1970-01-01 04:00:00'],
|
|
[0, 'Australia/Brisbane', '1970-01-01 10:00:00'],
|
|
[0, 'Australia/Eucla', '1970-01-01 08:45:00'],
|
|
[0, 'Australia/Melbourne', '1970-01-01 10:00:00'],
|
|
[0, 'Europe/Berlin', '1970-01-01 01:00:00'],
|
|
[0, 'Europe/Dublin', '1970-01-01 01:00:00'],
|
|
[0, 'Europe/Warsaw', '1970-01-01 01:00:00'],
|
|
[0, 'Pacific/Fiji', '1970-01-01 12:00:00'],
|
|
];
|
|
|
|
return $data;
|
|
}
|
|
|
|
/**
|
|
* @dataProvider formatTimezoneProvider
|
|
* @requires PHP 5.5.10
|
|
*/
|
|
public function testFormatTimezone($pattern, $timezone, $expected)
|
|
{
|
|
$formatter = $this->getDefaultDateFormatter($pattern);
|
|
$formatter->setTimeZone(new \DateTimeZone($timezone));
|
|
|
|
$this->assertEquals($expected, $formatter->format(0));
|
|
}
|
|
|
|
public function formatTimezoneProvider()
|
|
{
|
|
$cases = [
|
|
['z', 'GMT', 'GMT'],
|
|
['zz', 'GMT', 'GMT'],
|
|
['zzz', 'GMT', 'GMT'],
|
|
['zzzz', 'GMT', 'Greenwich Mean Time'],
|
|
['zzzzz', 'GMT', 'Greenwich Mean Time'],
|
|
|
|
['z', 'Etc/GMT', 'GMT'],
|
|
['zz', 'Etc/GMT', 'GMT'],
|
|
['zzz', 'Etc/GMT', 'GMT'],
|
|
['zzzz', 'Etc/GMT', 'Greenwich Mean Time'],
|
|
['zzzzz', 'Etc/GMT', 'Greenwich Mean Time'],
|
|
|
|
['z', 'Etc/GMT+3', 'GMT-3'],
|
|
['zz', 'Etc/GMT+3', 'GMT-3'],
|
|
['zzz', 'Etc/GMT+3', 'GMT-3'],
|
|
['zzzz', 'Etc/GMT+3', 'GMT-03:00'],
|
|
['zzzzz', 'Etc/GMT+3', 'GMT-03:00'],
|
|
|
|
['z', 'UTC', 'UTC'],
|
|
['zz', 'UTC', 'UTC'],
|
|
['zzz', 'UTC', 'UTC'],
|
|
['zzzz', 'UTC', 'Coordinated Universal Time'],
|
|
['zzzzz', 'UTC', 'Coordinated Universal Time'],
|
|
|
|
['z', 'Etc/UTC', 'UTC'],
|
|
['zz', 'Etc/UTC', 'UTC'],
|
|
['zzz', 'Etc/UTC', 'UTC'],
|
|
['zzzz', 'Etc/UTC', 'Coordinated Universal Time'],
|
|
['zzzzz', 'Etc/UTC', 'Coordinated Universal Time'],
|
|
|
|
['z', 'Etc/Universal', 'UTC'],
|
|
['z', 'Etc/Zulu', 'UTC'],
|
|
['z', 'Etc/UCT', 'UTC'],
|
|
['z', 'Etc/Greenwich', 'GMT'],
|
|
['zzzzz', 'Etc/Universal', 'Coordinated Universal Time'],
|
|
['zzzzz', 'Etc/Zulu', 'Coordinated Universal Time'],
|
|
['zzzzz', 'Etc/UCT', 'Coordinated Universal Time'],
|
|
['zzzzz', 'Etc/Greenwich', 'Greenwich Mean Time'],
|
|
];
|
|
|
|
if (!\defined('HHVM_VERSION')) {
|
|
// these timezones are not considered valid in HHVM
|
|
$cases = array_merge($cases, [
|
|
['z', 'GMT+03:00', 'GMT+3'],
|
|
['zz', 'GMT+03:00', 'GMT+3'],
|
|
['zzz', 'GMT+03:00', 'GMT+3'],
|
|
['zzzz', 'GMT+03:00', 'GMT+03:00'],
|
|
['zzzzz', 'GMT+03:00', 'GMT+03:00'],
|
|
]);
|
|
}
|
|
|
|
return $cases;
|
|
}
|
|
|
|
public function testFormatWithGmtTimezone()
|
|
{
|
|
$formatter = $this->getDefaultDateFormatter('zzzz');
|
|
|
|
$formatter->setTimeZone('GMT+03:00');
|
|
|
|
$this->assertEquals('GMT+03:00', $formatter->format(0));
|
|
}
|
|
|
|
public function testFormatWithGmtTimeZoneAndMinutesOffset()
|
|
{
|
|
$formatter = $this->getDefaultDateFormatter('zzzz');
|
|
|
|
$formatter->setTimeZone('GMT+00:30');
|
|
|
|
$this->assertEquals('GMT+00:30', $formatter->format(0));
|
|
}
|
|
|
|
public function testFormatWithNonStandardTimezone()
|
|
{
|
|
$formatter = $this->getDefaultDateFormatter('zzzz');
|
|
|
|
$formatter->setTimeZone('Pacific/Fiji');
|
|
|
|
$this->assertEquals('Fiji Standard Time', $formatter->format(0));
|
|
}
|
|
|
|
public function testFormatWithConstructorTimezone()
|
|
{
|
|
$formatter = $this->getDateFormatter('en', IntlDateFormatter::MEDIUM, IntlDateFormatter::SHORT, 'UTC');
|
|
$formatter->setPattern('yyyy-MM-dd HH:mm:ss');
|
|
|
|
$this->assertEquals(
|
|
$this->getDateTime(0, 'UTC')->format('Y-m-d H:i:s'),
|
|
$formatter->format(0)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @requires PHP 5.5.10
|
|
*/
|
|
public function testFormatWithDateTimeZoneGmt()
|
|
{
|
|
$formatter = $this->getDateFormatter('en', IntlDateFormatter::MEDIUM, IntlDateFormatter::SHORT, new \DateTimeZone('GMT'), IntlDateFormatter::GREGORIAN, 'zzz');
|
|
|
|
$this->assertEquals('GMT', $formatter->format(0));
|
|
}
|
|
|
|
public function testFormatWithDateTimeZoneGmtOffset()
|
|
{
|
|
if (\defined('HHVM_VERSION_ID') || \PHP_VERSION_ID <= 50509) {
|
|
$this->markTestSkipped('DateTimeZone GMT offsets are supported since 5.5.10. See https://github.com/facebook/hhvm/issues/5875 for HHVM.');
|
|
}
|
|
|
|
$formatter = $this->getDateFormatter('en', IntlDateFormatter::MEDIUM, IntlDateFormatter::SHORT, new \DateTimeZone('GMT+03:00'), IntlDateFormatter::GREGORIAN, 'zzzz');
|
|
|
|
$this->assertEquals('GMT+03:00', $formatter->format(0));
|
|
}
|
|
|
|
public function testFormatWithIntlTimeZone()
|
|
{
|
|
if (!\extension_loaded('intl')) {
|
|
$this->markTestSkipped('Extension intl is required.');
|
|
}
|
|
|
|
$formatter = $this->getDateFormatter('en', IntlDateFormatter::MEDIUM, IntlDateFormatter::SHORT, \IntlTimeZone::createTimeZone('GMT+03:00'), IntlDateFormatter::GREGORIAN, 'zzzz');
|
|
|
|
$this->assertEquals('GMT+03:00', $formatter->format(0));
|
|
}
|
|
|
|
public function testFormatWithTimezoneFromPhp()
|
|
{
|
|
$tz = date_default_timezone_get();
|
|
date_default_timezone_set('Europe/London');
|
|
|
|
$formatter = $this->getDateFormatter('en', IntlDateFormatter::MEDIUM, IntlDateFormatter::SHORT);
|
|
$formatter->setPattern('yyyy-MM-dd HH:mm:ss');
|
|
|
|
$this->assertEquals(
|
|
$this->getDateTime(0, 'Europe/London')->format('Y-m-d H:i:s'),
|
|
$formatter->format(0)
|
|
);
|
|
|
|
$this->assertEquals('Europe/London', date_default_timezone_get());
|
|
|
|
// Restores TZ.
|
|
date_default_timezone_set($tz);
|
|
}
|
|
|
|
/**
|
|
* @dataProvider dateAndTimeTypeProvider
|
|
*/
|
|
public function testDateAndTimeType($timestamp, $datetype, $timetype, $expected)
|
|
{
|
|
$formatter = $this->getDateFormatter('en', $datetype, $timetype, 'UTC');
|
|
$this->assertSame($expected, $formatter->format($timestamp));
|
|
}
|
|
|
|
public function dateAndTimeTypeProvider()
|
|
{
|
|
return [
|
|
[0, IntlDateFormatter::FULL, IntlDateFormatter::NONE, 'Thursday, January 1, 1970'],
|
|
[0, IntlDateFormatter::LONG, IntlDateFormatter::NONE, 'January 1, 1970'],
|
|
[0, IntlDateFormatter::MEDIUM, IntlDateFormatter::NONE, 'Jan 1, 1970'],
|
|
[0, IntlDateFormatter::SHORT, IntlDateFormatter::NONE, '1/1/70'],
|
|
[0, IntlDateFormatter::NONE, IntlDateFormatter::FULL, '12:00:00 AM Coordinated Universal Time'],
|
|
[0, IntlDateFormatter::NONE, IntlDateFormatter::LONG, '12:00:00 AM UTC'],
|
|
[0, IntlDateFormatter::NONE, IntlDateFormatter::MEDIUM, '12:00:00 AM'],
|
|
[0, IntlDateFormatter::NONE, IntlDateFormatter::SHORT, '12:00 AM'],
|
|
];
|
|
}
|
|
|
|
public function testGetCalendar()
|
|
{
|
|
$formatter = $this->getDefaultDateFormatter();
|
|
$this->assertEquals(IntlDateFormatter::GREGORIAN, $formatter->getCalendar());
|
|
}
|
|
|
|
public function testGetDateType()
|
|
{
|
|
$formatter = $this->getDateFormatter('en', IntlDateFormatter::FULL, IntlDateFormatter::NONE);
|
|
$this->assertEquals(IntlDateFormatter::FULL, $formatter->getDateType());
|
|
}
|
|
|
|
public function testGetLocale()
|
|
{
|
|
$formatter = $this->getDefaultDateFormatter();
|
|
$this->assertEquals('en', $formatter->getLocale());
|
|
}
|
|
|
|
public function testGetPattern()
|
|
{
|
|
$formatter = $this->getDateFormatter('en', IntlDateFormatter::FULL, IntlDateFormatter::NONE, 'UTC', IntlDateFormatter::GREGORIAN, 'yyyy-MM-dd');
|
|
$this->assertEquals('yyyy-MM-dd', $formatter->getPattern());
|
|
}
|
|
|
|
public function testGetTimeType()
|
|
{
|
|
$formatter = $this->getDateFormatter('en', IntlDateFormatter::NONE, IntlDateFormatter::FULL);
|
|
$this->assertEquals(IntlDateFormatter::FULL, $formatter->getTimeType());
|
|
}
|
|
|
|
/**
|
|
* @dataProvider parseProvider
|
|
*/
|
|
public function testParse($pattern, $value, $expected)
|
|
{
|
|
$errorCode = IntlGlobals::U_ZERO_ERROR;
|
|
$errorMessage = 'U_ZERO_ERROR';
|
|
|
|
$formatter = $this->getDefaultDateFormatter($pattern);
|
|
$this->assertSame($expected, $formatter->parse($value));
|
|
$this->assertIsIntlSuccess($formatter, $errorMessage, $errorCode);
|
|
}
|
|
|
|
public function parseProvider()
|
|
{
|
|
return array_merge(
|
|
$this->parseYearProvider(),
|
|
$this->parseQuarterProvider(),
|
|
$this->parseMonthProvider(),
|
|
$this->parseStandaloneMonthProvider(),
|
|
$this->parseDayProvider(),
|
|
$this->parseDayOfWeekProvider(),
|
|
$this->parseDayOfYearProvider(),
|
|
$this->parseHour12ClockOneBasedProvider(),
|
|
$this->parseHour12ClockZeroBasedProvider(),
|
|
$this->parseHour24ClockOneBasedProvider(),
|
|
$this->parseHour24ClockZeroBasedProvider(),
|
|
$this->parseMinuteProvider(),
|
|
$this->parseSecondProvider(),
|
|
$this->parseTimezoneProvider(),
|
|
$this->parseAmPmProvider(),
|
|
$this->parseStandaloneAmPmProvider(),
|
|
$this->parseRegexMetaCharsProvider(),
|
|
$this->parseQuoteCharsProvider(),
|
|
$this->parseDashSlashProvider()
|
|
);
|
|
}
|
|
|
|
public function parseYearProvider()
|
|
{
|
|
return [
|
|
['y-M-d', '1970-1-1', 0],
|
|
['yy-M-d', '70-1-1', 0],
|
|
];
|
|
}
|
|
|
|
public function parseQuarterProvider()
|
|
{
|
|
return [
|
|
['Q', '1', 0],
|
|
['QQ', '01', 0],
|
|
['QQQ', 'Q1', 0],
|
|
['QQQQ', '1st quarter', 0],
|
|
['QQQQQ', '1st quarter', 0],
|
|
|
|
['Q', '2', 7776000],
|
|
['QQ', '02', 7776000],
|
|
['QQQ', 'Q2', 7776000],
|
|
['QQQQ', '2nd quarter', 7776000],
|
|
['QQQQQ', '2nd quarter', 7776000],
|
|
|
|
['q', '1', 0],
|
|
['qq', '01', 0],
|
|
['qqq', 'Q1', 0],
|
|
['qqqq', '1st quarter', 0],
|
|
['qqqqq', '1st quarter', 0],
|
|
];
|
|
}
|
|
|
|
public function parseMonthProvider()
|
|
{
|
|
return [
|
|
['y-M-d', '1970-1-1', 0],
|
|
['y-MM-d', '1970-1-1', 0],
|
|
['y-MMM-d', '1970-Jan-1', 0],
|
|
['y-MMMM-d', '1970-January-1', 0],
|
|
];
|
|
}
|
|
|
|
public function parseStandaloneMonthProvider()
|
|
{
|
|
return [
|
|
['y-L-d', '1970-1-1', 0],
|
|
['y-LLL-d', '1970-Jan-1', 0],
|
|
['y-LLLL-d', '1970-January-1', 0],
|
|
];
|
|
}
|
|
|
|
public function parseDayProvider()
|
|
{
|
|
return [
|
|
['y-M-d', '1970-1-1', 0],
|
|
['y-M-dd', '1970-1-1', 0],
|
|
['y-M-dd', '1970-1-01', 0],
|
|
['y-M-ddd', '1970-1-001', 0],
|
|
];
|
|
}
|
|
|
|
public function parseDayOfWeekProvider()
|
|
{
|
|
return [
|
|
['E', 'Thu', 0],
|
|
['EE', 'Thu', 0],
|
|
['EEE', 'Thu', 0],
|
|
['EEEE', 'Thursday', 0],
|
|
['EEEEE', 'T', 432000],
|
|
['EEEEEE', 'Th', 0],
|
|
];
|
|
}
|
|
|
|
public function parseDayOfYearProvider()
|
|
{
|
|
return [
|
|
['D', '1', 0],
|
|
['D', '2', 86400],
|
|
];
|
|
}
|
|
|
|
public function parseHour12ClockOneBasedProvider()
|
|
{
|
|
return [
|
|
// 12 hours (1-12)
|
|
['y-M-d h', '1970-1-1 1', 3600],
|
|
['y-M-d h', '1970-1-1 10', 36000],
|
|
['y-M-d hh', '1970-1-1 11', 39600],
|
|
['y-M-d hh', '1970-1-1 12', 0],
|
|
['y-M-d hh a', '1970-1-1 0 AM', 0],
|
|
['y-M-d hh a', '1970-1-1 1 AM', 3600],
|
|
['y-M-d hh a', '1970-1-1 10 AM', 36000],
|
|
['y-M-d hh a', '1970-1-1 11 AM', 39600],
|
|
['y-M-d hh a', '1970-1-1 12 AM', 0],
|
|
['y-M-d hh a', '1970-1-1 23 AM', 82800],
|
|
['y-M-d hh a', '1970-1-1 24 AM', 86400],
|
|
['y-M-d hh a', '1970-1-1 0 PM', 43200],
|
|
['y-M-d hh a', '1970-1-1 1 PM', 46800],
|
|
['y-M-d hh a', '1970-1-1 10 PM', 79200],
|
|
['y-M-d hh a', '1970-1-1 11 PM', 82800],
|
|
['y-M-d hh a', '1970-1-1 12 PM', 43200],
|
|
['y-M-d hh a', '1970-1-1 23 PM', 126000],
|
|
['y-M-d hh a', '1970-1-1 24 PM', 129600],
|
|
];
|
|
}
|
|
|
|
public function parseHour12ClockZeroBasedProvider()
|
|
{
|
|
return [
|
|
// 12 hours (0-11)
|
|
['y-M-d K', '1970-1-1 1', 3600],
|
|
['y-M-d K', '1970-1-1 10', 36000],
|
|
['y-M-d KK', '1970-1-1 11', 39600],
|
|
['y-M-d KK', '1970-1-1 12', 43200],
|
|
['y-M-d KK a', '1970-1-1 0 AM', 0],
|
|
['y-M-d KK a', '1970-1-1 1 AM', 3600],
|
|
['y-M-d KK a', '1970-1-1 10 AM', 36000],
|
|
['y-M-d KK a', '1970-1-1 11 AM', 39600],
|
|
['y-M-d KK a', '1970-1-1 12 AM', 43200],
|
|
['y-M-d KK a', '1970-1-1 23 AM', 82800],
|
|
['y-M-d KK a', '1970-1-1 24 AM', 86400],
|
|
['y-M-d KK a', '1970-1-1 0 PM', 43200],
|
|
['y-M-d KK a', '1970-1-1 1 PM', 46800],
|
|
['y-M-d KK a', '1970-1-1 10 PM', 79200],
|
|
['y-M-d KK a', '1970-1-1 11 PM', 82800],
|
|
['y-M-d KK a', '1970-1-1 12 PM', 86400],
|
|
['y-M-d KK a', '1970-1-1 23 PM', 126000],
|
|
['y-M-d KK a', '1970-1-1 24 PM', 129600],
|
|
];
|
|
}
|
|
|
|
public function parseHour24ClockOneBasedProvider()
|
|
{
|
|
return [
|
|
// 24 hours (1-24)
|
|
['y-M-d k', '1970-1-1 1', 3600],
|
|
['y-M-d k', '1970-1-1 10', 36000],
|
|
['y-M-d kk', '1970-1-1 11', 39600],
|
|
['y-M-d kk', '1970-1-1 12', 43200],
|
|
['y-M-d kk', '1970-1-1 23', 82800],
|
|
['y-M-d kk', '1970-1-1 24', 0],
|
|
['y-M-d kk a', '1970-1-1 0 AM', 0],
|
|
['y-M-d kk a', '1970-1-1 1 AM', 0],
|
|
['y-M-d kk a', '1970-1-1 10 AM', 0],
|
|
['y-M-d kk a', '1970-1-1 11 AM', 0],
|
|
['y-M-d kk a', '1970-1-1 12 AM', 0],
|
|
['y-M-d kk a', '1970-1-1 23 AM', 0],
|
|
['y-M-d kk a', '1970-1-1 24 AM', 0],
|
|
['y-M-d kk a', '1970-1-1 0 PM', 43200],
|
|
['y-M-d kk a', '1970-1-1 1 PM', 43200],
|
|
['y-M-d kk a', '1970-1-1 10 PM', 43200],
|
|
['y-M-d kk a', '1970-1-1 11 PM', 43200],
|
|
['y-M-d kk a', '1970-1-1 12 PM', 43200],
|
|
['y-M-d kk a', '1970-1-1 23 PM', 43200],
|
|
['y-M-d kk a', '1970-1-1 24 PM', 43200],
|
|
];
|
|
}
|
|
|
|
public function parseHour24ClockZeroBasedProvider()
|
|
{
|
|
return [
|
|
// 24 hours (0-23)
|
|
['y-M-d H', '1970-1-1 0', 0],
|
|
['y-M-d H', '1970-1-1 1', 3600],
|
|
['y-M-d H', '1970-1-1 10', 36000],
|
|
['y-M-d HH', '1970-1-1 11', 39600],
|
|
['y-M-d HH', '1970-1-1 12', 43200],
|
|
['y-M-d HH', '1970-1-1 23', 82800],
|
|
['y-M-d HH a', '1970-1-1 0 AM', 0],
|
|
['y-M-d HH a', '1970-1-1 1 AM', 0],
|
|
['y-M-d HH a', '1970-1-1 10 AM', 0],
|
|
['y-M-d HH a', '1970-1-1 11 AM', 0],
|
|
['y-M-d HH a', '1970-1-1 12 AM', 0],
|
|
['y-M-d HH a', '1970-1-1 23 AM', 0],
|
|
['y-M-d HH a', '1970-1-1 24 AM', 0],
|
|
['y-M-d HH a', '1970-1-1 0 PM', 43200],
|
|
['y-M-d HH a', '1970-1-1 1 PM', 43200],
|
|
['y-M-d HH a', '1970-1-1 10 PM', 43200],
|
|
['y-M-d HH a', '1970-1-1 11 PM', 43200],
|
|
['y-M-d HH a', '1970-1-1 12 PM', 43200],
|
|
['y-M-d HH a', '1970-1-1 23 PM', 43200],
|
|
['y-M-d HH a', '1970-1-1 24 PM', 43200],
|
|
];
|
|
}
|
|
|
|
public function parseMinuteProvider()
|
|
{
|
|
return [
|
|
['y-M-d HH:m', '1970-1-1 0:1', 60],
|
|
['y-M-d HH:mm', '1970-1-1 0:10', 600],
|
|
];
|
|
}
|
|
|
|
public function parseSecondProvider()
|
|
{
|
|
return [
|
|
['y-M-d HH:mm:s', '1970-1-1 00:01:1', 61],
|
|
['y-M-d HH:mm:ss', '1970-1-1 00:01:10', 70],
|
|
];
|
|
}
|
|
|
|
public function parseTimezoneProvider()
|
|
{
|
|
return [
|
|
['y-M-d HH:mm:ss zzzz', '1970-1-1 00:00:00 GMT-03:00', 10800],
|
|
['y-M-d HH:mm:ss zzzz', '1970-1-1 00:00:00 GMT-04:00', 14400],
|
|
['y-M-d HH:mm:ss zzzz', '1970-1-1 00:00:00 GMT-00:00', 0],
|
|
['y-M-d HH:mm:ss zzzz', '1970-1-1 00:00:00 GMT+03:00', -10800],
|
|
['y-M-d HH:mm:ss zzzz', '1970-1-1 00:00:00 GMT+04:00', -14400],
|
|
['y-M-d HH:mm:ss zzzz', '1970-1-1 00:00:00 GMT-0300', 10800],
|
|
['y-M-d HH:mm:ss zzzz', '1970-1-1 00:00:00 GMT+0300', -10800],
|
|
|
|
// a previous timezone parsing should not change the timezone for the next parsing
|
|
['y-M-d HH:mm:ss', '1970-1-1 00:00:00', 0],
|
|
];
|
|
}
|
|
|
|
public function parseAmPmProvider()
|
|
{
|
|
return [
|
|
// AM/PM (already covered by hours tests)
|
|
['y-M-d HH:mm:ss a', '1970-1-1 00:00:00 AM', 0],
|
|
['y-M-d HH:mm:ss a', '1970-1-1 00:00:00 PM', 43200],
|
|
];
|
|
}
|
|
|
|
public function parseStandaloneAmPmProvider()
|
|
{
|
|
return [
|
|
['a', 'AM', 0],
|
|
['a', 'PM', 43200],
|
|
];
|
|
}
|
|
|
|
public function parseRegexMetaCharsProvider()
|
|
{
|
|
return [
|
|
// regexp meta chars in the pattern string
|
|
['y[M-d', '1970[1-1', 0],
|
|
['y[M/d', '1970[1/1', 0],
|
|
];
|
|
}
|
|
|
|
public function parseQuoteCharsProvider()
|
|
{
|
|
return [
|
|
["'M'", 'M', 0],
|
|
["'yy'", 'yy', 0],
|
|
["'''yy'", "'yy", 0],
|
|
["''y", "'1970", 0],
|
|
["H 'o'' clock'", "0 o' clock", 0],
|
|
];
|
|
}
|
|
|
|
public function parseDashSlashProvider()
|
|
{
|
|
return [
|
|
['y-M-d', '1970/1/1', 0],
|
|
['yy-M-d', '70/1/1', 0],
|
|
['y/M/d', '1970-1-1', 0],
|
|
['yy/M/d', '70-1-1', 0],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @dataProvider parseErrorProvider
|
|
*/
|
|
public function testParseError($pattern, $value)
|
|
{
|
|
$errorCode = IntlGlobals::U_PARSE_ERROR;
|
|
$errorMessage = 'Date parsing failed: U_PARSE_ERROR';
|
|
|
|
$formatter = $this->getDefaultDateFormatter($pattern);
|
|
$this->assertFalse($formatter->parse($value));
|
|
$this->assertIsIntlFailure($formatter, $errorMessage, $errorCode);
|
|
}
|
|
|
|
public function parseErrorProvider()
|
|
{
|
|
return [
|
|
// 1 char month
|
|
['y-MMMMM-d', '1970-J-1'],
|
|
['y-MMMMM-d', '1970-S-1'],
|
|
|
|
// standalone 1 char month
|
|
['y-LLLLL-d', '1970-J-1'],
|
|
['y-LLLLL-d', '1970-S-1'],
|
|
];
|
|
}
|
|
|
|
/*
|
|
* https://github.com/symfony/symfony/issues/4242
|
|
*/
|
|
public function testParseAfterError()
|
|
{
|
|
$this->testParseError('y-MMMMM-d', '1970-J-1');
|
|
$this->testParse('y-M-d', '1970-1-1', 0);
|
|
}
|
|
|
|
public function testParseWithNullPositionValue()
|
|
{
|
|
$position = null;
|
|
$formatter = $this->getDefaultDateFormatter('y');
|
|
$this->assertSame(0, $formatter->parse('1970', $position));
|
|
// Since $position is not supported by the Symfony implementation, the following won't work.
|
|
// The intl implementation works this way since 60.2.
|
|
// $this->assertSame(4, $position);
|
|
}
|
|
|
|
public function testSetPattern()
|
|
{
|
|
$formatter = $this->getDefaultDateFormatter();
|
|
$formatter->setPattern('yyyy-MM-dd');
|
|
$this->assertEquals('yyyy-MM-dd', $formatter->getPattern());
|
|
}
|
|
|
|
/**
|
|
* @dataProvider setTimeZoneIdProvider
|
|
*/
|
|
public function testSetTimeZoneId($timeZoneId, $expectedTimeZoneId)
|
|
{
|
|
$formatter = $this->getDefaultDateFormatter();
|
|
|
|
$formatter->setTimeZone($timeZoneId);
|
|
|
|
$this->assertEquals($expectedTimeZoneId, $formatter->getTimeZoneId());
|
|
}
|
|
|
|
public function setTimeZoneIdProvider()
|
|
{
|
|
return [
|
|
['UTC', 'UTC'],
|
|
['GMT', 'GMT'],
|
|
['GMT-03:00', 'GMT-03:00'],
|
|
['Europe/Zurich', 'Europe/Zurich'],
|
|
[null, date_default_timezone_get()],
|
|
['Foo/Bar', 'UTC'],
|
|
['GMT+00:AA', 'UTC'],
|
|
['GMT+00AA', 'UTC'],
|
|
];
|
|
}
|
|
|
|
protected function getDefaultDateFormatter($pattern = null)
|
|
{
|
|
return $this->getDateFormatter('en', IntlDateFormatter::MEDIUM, IntlDateFormatter::SHORT, 'UTC', IntlDateFormatter::GREGORIAN, $pattern);
|
|
}
|
|
|
|
protected function getDateTime($timestamp, $timeZone)
|
|
{
|
|
$dateTime = new \DateTime();
|
|
$dateTime->setTimestamp(null === $timestamp ? time() : $timestamp);
|
|
$dateTime->setTimezone(new \DateTimeZone($timeZone ?: getenv('TZ') ?: 'UTC'));
|
|
|
|
return $dateTime;
|
|
}
|
|
|
|
protected function assertIsIntlFailure($formatter, $errorMessage, $errorCode)
|
|
{
|
|
$this->assertSame($errorMessage, $this->getIntlErrorMessage());
|
|
$this->assertSame($errorCode, $this->getIntlErrorCode());
|
|
$this->assertTrue($this->isIntlFailure($this->getIntlErrorCode()));
|
|
$this->assertSame($errorMessage, $formatter->getErrorMessage());
|
|
$this->assertSame($errorCode, $formatter->getErrorCode());
|
|
$this->assertTrue($this->isIntlFailure($formatter->getErrorCode()));
|
|
}
|
|
|
|
protected function assertIsIntlSuccess($formatter, $errorMessage, $errorCode)
|
|
{
|
|
/* @var IntlDateFormatter $formatter */
|
|
$this->assertSame($errorMessage, $this->getIntlErrorMessage());
|
|
$this->assertSame($errorCode, $this->getIntlErrorCode());
|
|
$this->assertFalse($this->isIntlFailure($this->getIntlErrorCode()));
|
|
$this->assertSame($errorMessage, $formatter->getErrorMessage());
|
|
$this->assertSame($errorCode, $formatter->getErrorCode());
|
|
$this->assertFalse($this->isIntlFailure($formatter->getErrorCode()));
|
|
}
|
|
|
|
/**
|
|
* @param $locale
|
|
* @param $datetype
|
|
* @param $timetype
|
|
* @param null $timezone
|
|
* @param int $calendar
|
|
* @param null $pattern
|
|
*
|
|
* @return mixed
|
|
*/
|
|
abstract protected function getDateFormatter($locale, $datetype, $timetype, $timezone = null, $calendar = IntlDateFormatter::GREGORIAN, $pattern = null);
|
|
|
|
/**
|
|
* @return string
|
|
*/
|
|
abstract protected function getIntlErrorMessage();
|
|
|
|
/**
|
|
* @return int
|
|
*/
|
|
abstract protected function getIntlErrorCode();
|
|
|
|
/**
|
|
* @param int $errorCode
|
|
*
|
|
* @return bool
|
|
*/
|
|
abstract protected function isIntlFailure($errorCode);
|
|
}
|