StubIntlDateFormatterTest.php 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Tests\Component\Locale\Stub;
  11. require_once __DIR__.'/../TestCase.php';
  12. use Symfony\Component\Locale\Locale;
  13. use Symfony\Component\Locale\Stub\StubIntl;
  14. use Symfony\Component\Locale\Stub\StubIntlDateFormatter;
  15. use Symfony\Tests\Component\Locale\TestCase as LocaleTestCase;
  16. class StubIntlDateFormatterTest extends LocaleTestCase
  17. {
  18. /**
  19. * @expectedException Symfony\Component\Locale\Exception\MethodArgumentValueNotImplementedException
  20. */
  21. public function testConstructorWithUnsupportedLocale()
  22. {
  23. $formatter = new StubIntlDateFormatter('pt_BR', StubIntlDateFormatter::MEDIUM, StubIntlDateFormatter::SHORT);
  24. }
  25. public function testConstructor()
  26. {
  27. $formatter = new StubIntlDateFormatter('en', StubIntlDateFormatter::MEDIUM, StubIntlDateFormatter::SHORT, 'UTC', StubIntlDateFormatter::GREGORIAN, 'y-M-d');
  28. $this->assertEquals('y-M-d', $formatter->getPattern());
  29. }
  30. /**
  31. * When a time zone is not specified, it uses the system default however it returns null in the getter method
  32. * @covers Symfony\Component\Locale\Stub\StubIntlDateFormatter::getTimeZoneId
  33. * @covers Symfony\Component\Locale\Stub\StubIntlDateFormatter::setTimeZoneId
  34. * @see StubIntlDateFormatterTest::testDefaultTimeZoneIntl()
  35. */
  36. public function testConstructorDefaultTimeZoneStub()
  37. {
  38. $formatter = new StubIntlDateFormatter('en', StubIntlDateFormatter::MEDIUM, StubIntlDateFormatter::SHORT);
  39. $this->assertNull($formatter->getTimeZoneId());
  40. }
  41. public function testConstructorDefaultTimeZoneIntl()
  42. {
  43. $this->skipIfIntlExtensionIsNotLoaded();
  44. $formatter = new \IntlDateFormatter('en', StubIntlDateFormatter::MEDIUM, StubIntlDateFormatter::SHORT);
  45. $this->assertNull($formatter->getTimeZoneId());
  46. }
  47. public function testFormatWithUnsupportedTimestampArgument()
  48. {
  49. $formatter = $this->createStubFormatter();
  50. $localtime = array(
  51. 'tm_sec' => 59,
  52. 'tm_min' => 3,
  53. 'tm_hour' => 15,
  54. 'tm_mday' => 15,
  55. 'tm_mon' => 3,
  56. 'tm_year' => 112,
  57. 'tm_wday' => 0,
  58. 'tm_yday' => 105,
  59. 'tm_isdst' => 0
  60. );
  61. try {
  62. $formatter->format($localtime);
  63. } catch (\Exception $e) {
  64. $this->assertInstanceOf('Symfony\Component\Locale\Exception\MethodArgumentValueNotImplementedException', $e);
  65. if ($this->isGreaterOrEqualThanPhpVersion('5.3.4')) {
  66. $this->assertStringEndsWith('Only integer unix timestamps and DateTime objects are supported. Please install the \'intl\' extension for full localization capabilities.', $e->getMessage());
  67. } else {
  68. $this->assertStringEndsWith('Only integer unix timestamps are supported. Please install the \'intl\' extension for full localization capabilities.', $e->getMessage());
  69. }
  70. }
  71. }
  72. /**
  73. * @dataProvider formatProvider
  74. */
  75. public function testFormatStub($pattern, $timestamp, $expected)
  76. {
  77. $errorCode = StubIntl::U_ZERO_ERROR;
  78. $errorMessage = 'U_ZERO_ERROR';
  79. $formatter = $this->createStubFormatter($pattern);
  80. $this->assertSame($expected, $formatter->format($timestamp));
  81. $this->assertSame($errorMessage, StubIntl::getErrorMessage());
  82. $this->assertSame($errorCode, StubIntl::getErrorCode());
  83. $this->assertFalse(StubIntl::isFailure(StubIntl::getErrorCode()));
  84. $this->assertSame($errorMessage, $formatter->getErrorMessage());
  85. $this->assertSame($errorCode, $formatter->getErrorCode());
  86. $this->assertFalse(StubIntl::isFailure($formatter->getErrorCode()));
  87. }
  88. /**
  89. * @dataProvider formatProvider
  90. */
  91. public function testFormatIntl($pattern, $timestamp, $expected)
  92. {
  93. $this->skipIfIntlExtensionIsNotLoaded();
  94. $this->skipIfICUVersionIsTooOld();
  95. $errorCode = StubIntl::U_ZERO_ERROR;
  96. $errorMessage = 'U_ZERO_ERROR';
  97. $formatter = $this->createIntlFormatter($pattern);
  98. $this->assertSame($expected, $formatter->format($timestamp));
  99. $this->assertSame($errorMessage, intl_get_error_message());
  100. $this->assertSame($errorCode, intl_get_error_code());
  101. $this->assertFalse(intl_is_failure(intl_get_error_code()));
  102. }
  103. public function formatProvider()
  104. {
  105. $formatData = array(
  106. /* general */
  107. array('y-M-d', 0, '1970-1-1'),
  108. array("yyyy.MM.dd 'at' HH:mm:ss zzz", 0, '1970.01.01 at 00:00:00 GMT+00:00'),
  109. array("EEE, MMM d, ''yy", 0, "Thu, Jan 1, '70"),
  110. array('h:mm a', 0, '12:00 AM'),
  111. array('K:mm a, z', 0, '0:00 AM, GMT+00:00'),
  112. array('yyyyy.MMMM.dd hh:mm aaa', 0, '01970.January.01 12:00 AM'),
  113. /* escaping */
  114. array("'M'", 0, 'M'),
  115. array("'yy'", 0, 'yy'),
  116. array("'''yy'", 0, "'yy"),
  117. array("''y", 0, "'1970"),
  118. array("''yy", 0, "'70"),
  119. array("H 'o'' clock'", 0, "0 o' clock"),
  120. /* month */
  121. array('M', 0, '1'),
  122. array('MM', 0, '01'),
  123. array('MMM', 0, 'Jan'),
  124. array('MMMM', 0, 'January'),
  125. array('MMMMM', 0, 'J'),
  126. array('MMMMMM', 0, '000001'),
  127. array('L', 0, '1'),
  128. array('LL', 0, '01'),
  129. array('LLL', 0, 'Jan'),
  130. array('LLLL', 0, 'January'),
  131. array('LLLLL', 0, 'J'),
  132. array('LLLLLL', 0, '000001'),
  133. /* year */
  134. array('y', 0, '1970'),
  135. array('yy', 0, '70'),
  136. array('yyy', 0, '1970'),
  137. array('yyyy', 0, '1970'),
  138. array('yyyyy', 0, '01970'),
  139. array('yyyyyy', 0, '001970'),
  140. /* day */
  141. array('d', 0, '1'),
  142. array('dd', 0, '01'),
  143. array('ddd', 0, '001'),
  144. /* quarter */
  145. array('Q', 0, '1'),
  146. array('QQ', 0, '01'),
  147. array('QQQ', 0, 'Q1'),
  148. array('QQQQ', 0, '1st quarter'),
  149. array('QQQQQ', 0, '1st quarter'),
  150. array('q', 0, '1'),
  151. array('qq', 0, '01'),
  152. array('qqq', 0, 'Q1'),
  153. array('qqqq', 0, '1st quarter'),
  154. array('qqqqq', 0, '1st quarter'),
  155. // 4 months
  156. array('Q', 7776000, '2'),
  157. array('QQ', 7776000, '02'),
  158. array('QQQ', 7776000, 'Q2'),
  159. array('QQQQ', 7776000, '2nd quarter'),
  160. // 7 months
  161. array('QQQQ', 15638400, '3rd quarter'),
  162. // 10 months
  163. array('QQQQ', 23587200, '4th quarter'),
  164. /* 12-hour (1-12) */
  165. array('h', 0, '12'),
  166. array('hh', 0, '12'),
  167. array('hhh', 0, '012'),
  168. array('h', 1, '12'),
  169. array('h', 3600, '1'),
  170. array('h', 43200, '12'), // 12 hours
  171. /* day of year */
  172. array('D', 0, '1'),
  173. array('D', 86400, '2'), // 1 day
  174. array('D', 31536000, '1'), // 1 year
  175. array('D', 31622400, '2'), // 1 year + 1 day
  176. /* day of week */
  177. array('E', 0, 'Thu'),
  178. array('EE', 0, 'Thu'),
  179. array('EEE', 0, 'Thu'),
  180. array('EEEE', 0, 'Thursday'),
  181. array('EEEEE', 0, 'T'),
  182. array('EEEEEE', 0, 'Thu'),
  183. array('E', 1296540000, 'Tue'), // 2011-02-01
  184. array('E', 1296950400, 'Sun'), // 2011-02-06
  185. /* am/pm marker */
  186. array('a', 0, 'AM'),
  187. array('aa', 0, 'AM'),
  188. array('aaa', 0, 'AM'),
  189. array('aaaa', 0, 'AM'),
  190. // 12 hours
  191. array('a', 43200, 'PM'),
  192. array('aa', 43200, 'PM'),
  193. array('aaa', 43200, 'PM'),
  194. array('aaaa', 43200, 'PM'),
  195. /* 24-hour (0-23) */
  196. array('H', 0, '0'),
  197. array('HH', 0, '00'),
  198. array('HHH', 0, '000'),
  199. array('H', 1, '0'),
  200. array('H', 3600, '1'),
  201. array('H', 43200, '12'),
  202. array('H', 46800, '13'),
  203. /* 24-hour (1-24) */
  204. array('k', 0, '24'),
  205. array('kk', 0, '24'),
  206. array('kkk', 0, '024'),
  207. array('k', 1, '24'),
  208. array('k', 3600, '1'),
  209. array('k', 43200, '12'),
  210. array('k', 46800, '13'),
  211. /* 12-hour (0-11) */
  212. array('K', 0, '0'),
  213. array('KK', 0, '00'),
  214. array('KKK', 0, '000'),
  215. array('K', 1, '0'),
  216. array('K', 3600, '1'),
  217. array('K', 43200, '0'), // 12 hours
  218. /* minute */
  219. array('m', 0, '0'),
  220. array('mm', 0, '00'),
  221. array('mmm', 0, '000'),
  222. array('m', 1, '0'),
  223. array('m', 60, '1'),
  224. array('m', 120, '2'),
  225. array('m', 180, '3'),
  226. array('m', 3600, '0'),
  227. array('m', 3660, '1'),
  228. array('m', 43200, '0'), // 12 hours
  229. /* second */
  230. array('s', 0, '0'),
  231. array('ss', 0, '00'),
  232. array('sss', 0, '000'),
  233. array('s', 1, '1'),
  234. array('s', 2, '2'),
  235. array('s', 5, '5'),
  236. array('s', 30, '30'),
  237. array('s', 59, '59'),
  238. array('s', 60, '0'),
  239. array('s', 120, '0'),
  240. array('s', 180, '0'),
  241. array('s', 3600, '0'),
  242. array('s', 3601, '1'),
  243. array('s', 3630, '30'),
  244. array('s', 43200, '0'), // 12 hours
  245. /* timezone */
  246. array('z', 0, 'GMT+00:00'),
  247. array('zz', 0, 'GMT+00:00'),
  248. array('zzz', 0, 'GMT+00:00'),
  249. array('zzzz', 0, 'GMT+00:00'),
  250. array('zzzzz', 0, 'GMT+00:00'),
  251. );
  252. // As of PHP 5.3.4, IntlDateFormatter::format() accepts DateTime instances
  253. if ($this->isGreaterOrEqualThanPhpVersion('5.3.4')) {
  254. $dateTime = new \DateTime('@0');
  255. /* general, DateTime */
  256. $formatData[] = array('y-M-d', $dateTime, '1970-1-1');
  257. $formatData[] = array("yyyy.MM.dd 'at' HH:mm:ss zzz", $dateTime, '1970.01.01 at 00:00:00 GMT+00:00');
  258. $formatData[] = array("EEE, MMM d, ''yy", $dateTime, "Thu, Jan 1, '70");
  259. $formatData[] = array('h:mm a', $dateTime, '12:00 AM');
  260. $formatData[] = array('K:mm a, z', $dateTime, '0:00 AM, GMT+00:00');
  261. $formatData[] = array('yyyyy.MMMM.dd hh:mm aaa', $dateTime, '01970.January.01 12:00 AM');
  262. }
  263. return $formatData;
  264. }
  265. /**
  266. * @dataProvider formatErrorProvider
  267. */
  268. public function testFormatIllegalArgumentErrorStub($pattern, $timestamp, $errorMessage)
  269. {
  270. $errorCode = StubIntl::U_ILLEGAL_ARGUMENT_ERROR;
  271. $formatter = $this->createStubFormatter($pattern);
  272. $this->assertFalse($formatter->format($timestamp));
  273. $this->assertSame($errorMessage, StubIntl::getErrorMessage());
  274. $this->assertSame($errorCode, StubIntl::getErrorCode());
  275. $this->assertTrue(StubIntl::isFailure(StubIntl::getErrorCode()));
  276. $this->assertSame($errorMessage, $formatter->getErrorMessage());
  277. $this->assertSame($errorCode, $formatter->getErrorCode());
  278. $this->assertTrue(StubIntl::isFailure($formatter->getErrorCode()));
  279. }
  280. /**
  281. * @dataProvider formatErrorProvider
  282. */
  283. public function testFormatIllegalArgumentErrorIntl($pattern, $timestamp, $errorMessage)
  284. {
  285. $this->skipIfIntlExtensionIsNotLoaded();
  286. $this->skipIfICUVersionIsTooOld();
  287. $errorCode = StubIntl::U_ILLEGAL_ARGUMENT_ERROR;
  288. $formatter = $this->createIntlFormatter($pattern);
  289. $this->assertFalse($formatter->format($timestamp));
  290. $this->assertSame($errorMessage, intl_get_error_message());
  291. $this->assertSame($errorCode, intl_get_error_code());
  292. $this->assertTrue(intl_is_failure(intl_get_error_code()));
  293. }
  294. public function formatErrorProvider()
  295. {
  296. $message = 'datefmt_format: takes either an array or an integer timestamp value : U_ILLEGAL_ARGUMENT_ERROR';
  297. if ($this->isGreaterOrEqualThanPhpVersion('5.3.4')) {
  298. $message = 'datefmt_format: takes either an array or an integer timestamp value or a DateTime object: U_ILLEGAL_ARGUMENT_ERROR';
  299. }
  300. return array(
  301. array('y-M-d', '0', $message),
  302. array('y-M-d', 'foobar', $message),
  303. );
  304. }
  305. /**
  306. * @dataProvider formatWithTimezoneProvider
  307. */
  308. public function testFormatWithTimezoneStub($timestamp, $timezone, $expected)
  309. {
  310. $pattern = 'yyyy-MM-dd HH:mm:ss';
  311. $formatter = new StubIntlDateFormatter('en', StubIntlDateFormatter::MEDIUM, StubIntlDateFormatter::SHORT, $timezone, StubIntlDateFormatter::GREGORIAN, $pattern);
  312. $this->assertSame($expected, $formatter->format($timestamp));
  313. }
  314. /**
  315. * @dataProvider formatWithTimezoneProvider
  316. */
  317. public function testFormatWithTimezoneIntl($timestamp, $timezone, $expected)
  318. {
  319. $this->skipIfIntlExtensionIsNotLoaded();
  320. $pattern = 'yyyy-MM-dd HH:mm:ss';
  321. $formatter = new \IntlDateFormatter('en', \IntlDateFormatter::MEDIUM, \IntlDateFormatter::SHORT, $timezone, \IntlDateFormatter::GREGORIAN, $pattern);
  322. $this->assertSame($expected, $formatter->format($timestamp));
  323. }
  324. public function formatWithTimezoneProvider()
  325. {
  326. return array(
  327. array(0, 'UTC', '1970-01-01 00:00:00'),
  328. array(0, 'GMT', '1970-01-01 00:00:00'),
  329. array(0, 'GMT-03:00', '1969-12-31 21:00:00'),
  330. array(0, 'GMT+03:00', '1970-01-01 03:00:00'),
  331. array(0, 'Europe/Zurich', '1970-01-01 01:00:00'),
  332. array(0, 'Europe/Paris', '1970-01-01 01:00:00'),
  333. array(0, 'Africa/Cairo', '1970-01-01 02:00:00'),
  334. array(0, 'Africa/Casablanca', '1970-01-01 00:00:00'),
  335. array(0, 'Africa/Djibouti', '1970-01-01 03:00:00'),
  336. array(0, 'Africa/Johannesburg', '1970-01-01 02:00:00'),
  337. array(0, 'America/Antigua', '1969-12-31 20:00:00'),
  338. array(0, 'America/Toronto', '1969-12-31 19:00:00'),
  339. array(0, 'America/Vancouver', '1969-12-31 16:00:00'),
  340. array(0, 'Asia/Aqtau', '1970-01-01 05:00:00'),
  341. array(0, 'Asia/Bangkok', '1970-01-01 07:00:00'),
  342. array(0, 'Asia/Dubai', '1970-01-01 04:00:00'),
  343. array(0, 'Australia/Brisbane', '1970-01-01 10:00:00'),
  344. array(0, 'Australia/Eucla', '1970-01-01 08:45:00'),
  345. array(0, 'Australia/Melbourne', '1970-01-01 10:00:00'),
  346. array(0, 'Europe/Berlin', '1970-01-01 01:00:00'),
  347. array(0, 'Europe/Dublin', '1970-01-01 01:00:00'),
  348. array(0, 'Europe/Warsaw', '1970-01-01 01:00:00'),
  349. array(0, 'Pacific/Fiji', '1970-01-01 12:00:00'),
  350. // When time zone not exists, uses UTC by default
  351. array(0, 'Foo/Bar', '1970-01-01 00:00:00'),
  352. array(0, 'UTC+04:30', '1970-01-01 00:00:00'),
  353. array(0, 'UTC+04:AA', '1970-01-01 00:00:00'),
  354. );
  355. }
  356. /**
  357. * @expectedException Symfony\Component\Locale\Exception\NotImplementedException
  358. */
  359. public function testFormatWithTimezoneFormatOptionAndDifferentThanUtcStub()
  360. {
  361. $formatter = $this->createStubFormatter('zzzz');
  362. $formatter->setTimeZoneId('Pacific/Fiji');
  363. $formatter->format(0);
  364. }
  365. public function testFormatWithTimezoneFormatOptionAndDifferentThanUtcIntl()
  366. {
  367. $this->skipIfIntlExtensionIsNotLoaded();
  368. $formatter = $this->createIntlFormatter('zzzz');
  369. $formatter->setTimeZoneId('Pacific/Fiji');
  370. $this->assertEquals('Fiji Time', $formatter->format(0));
  371. }
  372. public function testFormatWithGmtTimezoneStub()
  373. {
  374. $formatter = $this->createStubFormatter('zzzz');
  375. $formatter->setTimeZoneId('GMT+03:00');
  376. $this->assertEquals('GMT+03:00', $formatter->format(0));
  377. }
  378. public function testFormatWithGmtTimezoneIntl()
  379. {
  380. $this->skipIfIntlExtensionIsNotLoaded();
  381. $formatter = $this->createIntlFormatter('zzzz');
  382. $formatter->setTimeZoneId('GMT+03:00');
  383. $this->assertEquals('GMT+03:00', $formatter->format(0));
  384. }
  385. public function testFormatWithDefaultTimezoneStub()
  386. {
  387. $formatter = new StubIntlDateFormatter('en', StubIntlDateFormatter::MEDIUM, StubIntlDateFormatter::SHORT);
  388. $formatter->setPattern('yyyy-MM-dd HH:mm:ss');
  389. $this->assertEquals(
  390. $this->createDateTime(0)->format('Y-m-d H:i:s'),
  391. $formatter->format(0)
  392. );
  393. }
  394. public function testFormatWithDefaultTimezoneIntl()
  395. {
  396. $this->skipIfIntlExtensionIsNotLoaded();
  397. $this->skipIfICUVersionIsTooOld();
  398. $formatter = new \IntlDateFormatter('en', StubIntlDateFormatter::MEDIUM, StubIntlDateFormatter::SHORT);
  399. $formatter->setPattern('yyyy-MM-dd HH:mm:ss');
  400. $this->assertEquals(
  401. $this->createDateTime(0)->format('Y-m-d H:i:s'),
  402. $formatter->format(0)
  403. );
  404. }
  405. public function testFormatWithDefaultTimezoneStubShouldUseTheTzEnvironmentVariableWhenAvailable()
  406. {
  407. $tz = getenv('TZ');
  408. putenv('TZ=Europe/London');
  409. $formatter = new StubIntlDateFormatter('en', StubIntlDateFormatter::MEDIUM, StubIntlDateFormatter::SHORT);
  410. $formatter->setPattern('yyyy-MM-dd HH:mm:ss');
  411. $this->assertEquals(
  412. $this->createDateTime(0)->format('Y-m-d H:i:s'),
  413. $formatter->format(0)
  414. );
  415. $this->assertEquals('Europe/London', getenv('TZ'));
  416. // Restores TZ.
  417. putenv('TZ='.$tz);
  418. }
  419. /**
  420. * It seems IntlDateFormatter caches the timezone id when not explicitely set via constructor or by the
  421. * setTimeZoneId() method. Since testFormatWithDefaultTimezoneIntl() runs using the default environment
  422. * time zone, this test would use it too if not running in a separated process.
  423. *
  424. * @runInSeparateProcess
  425. */
  426. public function testFormatWithDefaultTimezoneIntlShouldUseTheTzEnvironmentVariableWhenAvailable()
  427. {
  428. $this->skipIfIntlExtensionIsNotLoaded();
  429. $this->skipIfICUVersionIsTooOld();
  430. $tz = getenv('TZ');
  431. putenv('TZ=Europe/Paris');
  432. $formatter = new \IntlDateFormatter('en', StubIntlDateFormatter::MEDIUM, StubIntlDateFormatter::SHORT);
  433. $formatter->setPattern('yyyy-MM-dd HH:mm:ss');
  434. $this->assertEquals('Europe/Paris', getenv('TZ'));
  435. $this->assertEquals(
  436. $this->createDateTime(0)->format('Y-m-d H:i:s'),
  437. $formatter->format(0)
  438. );
  439. // Restores TZ.
  440. putenv('TZ='.$tz);
  441. }
  442. /**
  443. * @expectedException Symfony\Component\Locale\Exception\NotImplementedException
  444. */
  445. public function testFormatWithUnimplementedCharsStub()
  446. {
  447. $pattern = 'Y';
  448. $formatter = new StubIntlDateFormatter('en', StubIntlDateFormatter::MEDIUM, StubIntlDateFormatter::SHORT, 'UTC', StubIntlDateFormatter::GREGORIAN, $pattern);
  449. $formatter->format(0);
  450. }
  451. /**
  452. * @expectedException Symfony\Component\Locale\Exception\NotImplementedException
  453. */
  454. public function testFormatWithNonIntegerTimestamp()
  455. {
  456. $formatter = $this->createStubFormatter();
  457. $formatter->format(array());
  458. }
  459. /**
  460. * @dataProvider dateAndTimeTypeProvider
  461. */
  462. public function testDateAndTimeTypeStub($timestamp, $datetype, $timetype, $expected)
  463. {
  464. $formatter = new StubIntlDateFormatter('en', $datetype, $timetype, 'UTC');
  465. $this->assertSame($expected, $formatter->format($timestamp));
  466. }
  467. /**
  468. * @dataProvider dateAndTimeTypeProvider
  469. */
  470. public function testDateAndTimeTypeIntl($timestamp, $datetype, $timetype, $expected)
  471. {
  472. $this->skipIfIntlExtensionIsNotLoaded();
  473. $formatter = new \IntlDateFormatter('en', $datetype, $timetype, 'UTC');
  474. $this->assertSame($expected, $formatter->format($timestamp));
  475. }
  476. public function dateAndTimeTypeProvider()
  477. {
  478. return array(
  479. array(0, StubIntlDateFormatter::FULL, StubIntlDateFormatter::NONE, 'Thursday, January 1, 1970'),
  480. array(0, StubIntlDateFormatter::LONG, StubIntlDateFormatter::NONE, 'January 1, 1970'),
  481. array(0, StubIntlDateFormatter::MEDIUM, StubIntlDateFormatter::NONE, 'Jan 1, 1970'),
  482. array(0, StubIntlDateFormatter::SHORT, StubIntlDateFormatter::NONE, '1/1/70'),
  483. array(0, StubIntlDateFormatter::NONE, StubIntlDateFormatter::FULL, '12:00:00 AM GMT+00:00'),
  484. array(0, StubIntlDateFormatter::NONE, StubIntlDateFormatter::LONG, '12:00:00 AM GMT+00:00'),
  485. array(0, StubIntlDateFormatter::NONE, StubIntlDateFormatter::MEDIUM, '12:00:00 AM'),
  486. array(0, StubIntlDateFormatter::NONE, StubIntlDateFormatter::SHORT, '12:00 AM'),
  487. );
  488. }
  489. public function testGetCalendar()
  490. {
  491. $formatter = $this->createStubFormatter();
  492. $this->assertEquals(StubIntlDateFormatter::GREGORIAN, $formatter->getCalendar());
  493. }
  494. public function testGetDateType()
  495. {
  496. $formatter = new StubIntlDateFormatter('en', StubIntlDateFormatter::FULL, StubIntlDateFormatter::NONE);
  497. $this->assertEquals(StubIntlDateFormatter::FULL, $formatter->getDateType());
  498. }
  499. public function testGetErrorCode()
  500. {
  501. $formatter = $this->createStubFormatter();
  502. $this->assertEquals(StubIntl::getErrorCode(), $formatter->getErrorCode());
  503. }
  504. public function testGetErrorMessage()
  505. {
  506. $formatter = $this->createStubFormatter();
  507. $this->assertEquals(StubIntl::getErrorMessage(), $formatter->getErrorMessage());
  508. }
  509. public function testGetLocale()
  510. {
  511. $formatter = $this->createStubFormatter();
  512. $this->assertEquals('en', $formatter->getLocale());
  513. }
  514. public function testGetPattern()
  515. {
  516. $formatter = new StubIntlDateFormatter('en', StubIntlDateFormatter::FULL, StubIntlDateFormatter::NONE, 'UTC', StubIntlDateFormatter::GREGORIAN, 'yyyy-MM-dd');
  517. $this->assertEquals('yyyy-MM-dd', $formatter->getPattern());
  518. }
  519. public function testGetTimeType()
  520. {
  521. $formatter = new StubIntlDateFormatter('en', StubIntlDateFormatter::NONE, StubIntlDateFormatter::FULL);
  522. $this->assertEquals(StubIntlDateFormatter::FULL, $formatter->getTimeType());
  523. }
  524. /**
  525. * @expectedException Symfony\Component\Locale\Exception\MethodNotImplementedException
  526. */
  527. public function testIsLenient()
  528. {
  529. $formatter = $this->createStubFormatter();
  530. $formatter->isLenient();
  531. }
  532. /**
  533. * @expectedException Symfony\Component\Locale\Exception\MethodNotImplementedException
  534. */
  535. public function testLocaltime()
  536. {
  537. $formatter = $this->createStubFormatter();
  538. $formatter->localtime('Wednesday, December 31, 1969 4:00:00 PM PT');
  539. }
  540. /**
  541. * @dataProvider parseProvider
  542. */
  543. public function testParseIntl($pattern, $value, $expected)
  544. {
  545. $errorCode = StubIntl::U_ZERO_ERROR;
  546. $errorMessage = 'U_ZERO_ERROR';
  547. $this->skipIfIntlExtensionIsNotLoaded();
  548. $formatter = $this->createIntlFormatter($pattern);
  549. $this->assertSame($expected, $formatter->parse($value));
  550. $this->assertSame($errorMessage, intl_get_error_message());
  551. $this->assertSame($errorCode, intl_get_error_code());
  552. $this->assertFalse(intl_is_failure(intl_get_error_code()));
  553. }
  554. /**
  555. * @dataProvider parseProvider
  556. */
  557. public function testParseStub($pattern, $value, $expected)
  558. {
  559. $errorCode = StubIntl::U_ZERO_ERROR;
  560. $errorMessage = 'U_ZERO_ERROR';
  561. $formatter = $this->createStubFormatter($pattern);
  562. $this->assertSame($expected, $formatter->parse($value));
  563. $this->assertSame($errorMessage, StubIntl::getErrorMessage());
  564. $this->assertSame($errorCode, StubIntl::getErrorCode());
  565. $this->assertFalse(StubIntl::isFailure(StubIntl::getErrorCode()));
  566. $this->assertSame($errorMessage, $formatter->getErrorMessage());
  567. $this->assertSame($errorCode, $formatter->getErrorCode());
  568. $this->assertFalse(StubIntl::isFailure($formatter->getErrorCode()));
  569. }
  570. public function parseProvider()
  571. {
  572. return array(
  573. // years
  574. array('y-M-d', '1970-1-1', 0),
  575. array('yy-M-d', '70-1-1', 0),
  576. // months
  577. array('y-M-d', '1970-1-1', 0),
  578. array('y-MMM-d', '1970-Jan-1', 0),
  579. array('y-MMMM-d', '1970-January-1', 0),
  580. // standalone months
  581. array('y-L-d', '1970-1-1', 0),
  582. array('y-LLL-d', '1970-Jan-1', 0),
  583. array('y-LLLL-d', '1970-January-1', 0),
  584. // days
  585. array('y-M-d', '1970-1-1', 0),
  586. array('y-M-dd', '1970-1-01', 0),
  587. array('y-M-ddd', '1970-1-001', 0),
  588. // 12 hours (1-12)
  589. array('y-M-d h', '1970-1-1 1', 3600),
  590. array('y-M-d h', '1970-1-1 10', 36000),
  591. array('y-M-d hh', '1970-1-1 11', 39600),
  592. array('y-M-d hh', '1970-1-1 12', 0),
  593. array('y-M-d hh a', '1970-1-1 0 AM', 0),
  594. array('y-M-d hh a', '1970-1-1 1 AM', 3600),
  595. array('y-M-d hh a', '1970-1-1 10 AM', 36000),
  596. array('y-M-d hh a', '1970-1-1 11 AM', 39600),
  597. array('y-M-d hh a', '1970-1-1 12 AM', 0),
  598. array('y-M-d hh a', '1970-1-1 23 AM', 82800),
  599. array('y-M-d hh a', '1970-1-1 24 AM', 86400),
  600. array('y-M-d hh a', '1970-1-1 0 PM', 43200),
  601. array('y-M-d hh a', '1970-1-1 1 PM', 46800),
  602. array('y-M-d hh a', '1970-1-1 10 PM', 79200),
  603. array('y-M-d hh a', '1970-1-1 11 PM', 82800),
  604. array('y-M-d hh a', '1970-1-1 12 PM', 43200),
  605. array('y-M-d hh a', '1970-1-1 23 PM', 126000),
  606. array('y-M-d hh a', '1970-1-1 24 PM', 129600),
  607. // 12 hours (0-11)
  608. array('y-M-d K', '1970-1-1 1', 3600),
  609. array('y-M-d K', '1970-1-1 10', 36000),
  610. array('y-M-d KK', '1970-1-1 11', 39600),
  611. array('y-M-d KK', '1970-1-1 12', 43200),
  612. array('y-M-d KK a', '1970-1-1 0 AM', 0),
  613. array('y-M-d KK a', '1970-1-1 1 AM', 3600),
  614. array('y-M-d KK a', '1970-1-1 10 AM', 36000),
  615. array('y-M-d KK a', '1970-1-1 11 AM', 39600),
  616. array('y-M-d KK a', '1970-1-1 12 AM', 43200),
  617. array('y-M-d KK a', '1970-1-1 23 AM', 82800),
  618. array('y-M-d KK a', '1970-1-1 24 AM', 86400),
  619. array('y-M-d KK a', '1970-1-1 0 PM', 43200),
  620. array('y-M-d KK a', '1970-1-1 1 PM', 46800),
  621. array('y-M-d KK a', '1970-1-1 10 PM', 79200),
  622. array('y-M-d KK a', '1970-1-1 11 PM', 82800),
  623. array('y-M-d KK a', '1970-1-1 12 PM', 86400),
  624. array('y-M-d KK a', '1970-1-1 23 PM', 126000),
  625. array('y-M-d KK a', '1970-1-1 24 PM', 129600),
  626. // 24 hours (0-23)
  627. array('y-M-d H', '1970-1-1 0', 0),
  628. array('y-M-d H', '1970-1-1 1', 3600),
  629. array('y-M-d H', '1970-1-1 10', 36000),
  630. array('y-M-d HH', '1970-1-1 11', 39600),
  631. array('y-M-d HH', '1970-1-1 12', 43200),
  632. array('y-M-d HH', '1970-1-1 23', 82800),
  633. array('y-M-d HH a', '1970-1-1 0 AM', 0),
  634. array('y-M-d HH a', '1970-1-1 1 AM', 0),
  635. array('y-M-d HH a', '1970-1-1 10 AM', 0),
  636. array('y-M-d HH a', '1970-1-1 11 AM', 0),
  637. array('y-M-d HH a', '1970-1-1 12 AM', 0),
  638. array('y-M-d HH a', '1970-1-1 23 AM', 0),
  639. array('y-M-d HH a', '1970-1-1 24 AM', 0),
  640. array('y-M-d HH a', '1970-1-1 0 PM', 43200),
  641. array('y-M-d HH a', '1970-1-1 1 PM', 43200),
  642. array('y-M-d HH a', '1970-1-1 10 PM', 43200),
  643. array('y-M-d HH a', '1970-1-1 11 PM', 43200),
  644. array('y-M-d HH a', '1970-1-1 12 PM', 43200),
  645. array('y-M-d HH a', '1970-1-1 23 PM', 43200),
  646. array('y-M-d HH a', '1970-1-1 24 PM', 43200),
  647. // 24 hours (1-24)
  648. array('y-M-d k', '1970-1-1 1', 3600),
  649. array('y-M-d k', '1970-1-1 10', 36000),
  650. array('y-M-d kk', '1970-1-1 11', 39600),
  651. array('y-M-d kk', '1970-1-1 12', 43200),
  652. array('y-M-d kk', '1970-1-1 23', 82800),
  653. array('y-M-d kk', '1970-1-1 24', 0),
  654. array('y-M-d kk a', '1970-1-1 0 AM', 0),
  655. array('y-M-d kk a', '1970-1-1 1 AM', 0),
  656. array('y-M-d kk a', '1970-1-1 10 AM', 0),
  657. array('y-M-d kk a', '1970-1-1 11 AM', 0),
  658. array('y-M-d kk a', '1970-1-1 12 AM', 0),
  659. array('y-M-d kk a', '1970-1-1 23 AM', 0),
  660. array('y-M-d kk a', '1970-1-1 24 AM', 0),
  661. array('y-M-d kk a', '1970-1-1 0 PM', 43200),
  662. array('y-M-d kk a', '1970-1-1 1 PM', 43200),
  663. array('y-M-d kk a', '1970-1-1 10 PM', 43200),
  664. array('y-M-d kk a', '1970-1-1 11 PM', 43200),
  665. array('y-M-d kk a', '1970-1-1 12 PM', 43200),
  666. array('y-M-d kk a', '1970-1-1 23 PM', 43200),
  667. array('y-M-d kk a', '1970-1-1 24 PM', 43200),
  668. // minutes
  669. array('y-M-d HH:m', '1970-1-1 0:1', 60),
  670. array('y-M-d HH:mm', '1970-1-1 0:10', 600),
  671. // seconds
  672. array('y-M-d HH:mm:s', '1970-1-1 00:01:1', 61),
  673. array('y-M-d HH:mm:ss', '1970-1-1 00:01:10', 70),
  674. // timezone
  675. array('y-M-d HH:mm:ss zzzz', '1970-1-1 00:00:00 GMT-03:00', 10800),
  676. array('y-M-d HH:mm:ss zzzz', '1970-1-1 00:00:00 GMT-04:00', 14400),
  677. array('y-M-d HH:mm:ss zzzz', '1970-1-1 00:00:00 GMT-00:00', 0),
  678. array('y-M-d HH:mm:ss zzzz', '1970-1-1 00:00:00 GMT+03:00', -10800),
  679. array('y-M-d HH:mm:ss zzzz', '1970-1-1 00:00:00 GMT+04:00', -14400),
  680. array('y-M-d HH:mm:ss zzzz', '1970-1-1 00:00:00 GMT-0300', 10800),
  681. array('y-M-d HH:mm:ss zzzz', '1970-1-1 00:00:00 GMT+0300', -10800),
  682. // a previous timezoned parsing should not change the timezone for the next parsing
  683. array('y-M-d HH:mm:ss', '1970-1-1 00:00:00', 0),
  684. // AM/PM (already covered by hours tests)
  685. array('y-M-d HH:mm:ss a', '1970-1-1 00:00:00 AM', 0),
  686. array('y-M-d HH:mm:ss a', '1970-1-1 00:00:00 PM', 43200),
  687. // regExp metachars in the pattern string
  688. array('y[M-d', '1970[1-1', 0),
  689. array('y[M/d', '1970[1/1', 0),
  690. // quote characters
  691. array("'M'", 'M', 0),
  692. array("'yy'", 'yy', 0),
  693. array("'''yy'", "'yy", 0),
  694. array("''y", "'1970", 0),
  695. array("H 'o'' clock'", "0 o' clock", 0),
  696. );
  697. }
  698. /**
  699. * @dataProvider parseErrorProvider
  700. */
  701. public function testParseErrorIntl($pattern, $value)
  702. {
  703. $errorCode = StubIntl::U_PARSE_ERROR;
  704. $errorMessage = 'Date parsing failed: U_PARSE_ERROR';
  705. $this->skipIfIntlExtensionIsNotLoaded();
  706. $formatter = $this->createIntlFormatter($pattern);
  707. $this->assertFalse($formatter->parse($value));
  708. $this->assertSame($errorMessage, intl_get_error_message());
  709. $this->assertSame($errorCode, intl_get_error_code());
  710. $this->assertTrue(intl_is_failure(intl_get_error_code()));
  711. }
  712. /**
  713. * @dataProvider parseErrorProvider
  714. */
  715. public function testParseErrorStub($pattern, $value)
  716. {
  717. $errorCode = StubIntl::U_PARSE_ERROR;
  718. $errorMessage = 'Date parsing failed: U_PARSE_ERROR';
  719. $formatter = $this->createStubFormatter($pattern);
  720. $this->assertFalse($formatter->parse($value));
  721. $this->assertSame($errorMessage, StubIntl::getErrorMessage());
  722. $this->assertSame($errorCode, StubIntl::getErrorCode());
  723. $this->assertTrue(StubIntl::isFailure(StubIntl::getErrorCode()));
  724. $this->assertSame($errorMessage, $formatter->getErrorMessage());
  725. $this->assertSame($errorCode, $formatter->getErrorCode());
  726. $this->assertTrue(StubIntl::isFailure($formatter->getErrorCode()));
  727. }
  728. public function parseErrorProvider()
  729. {
  730. return array(
  731. array('y-M-d', '1970/1/1'),
  732. array('yy-M-d', '70/1/1'),
  733. // 1 char month
  734. array('y-MMMMM-d', '1970-J-1'),
  735. array('y-MMMMM-d', '1970-S-1'),
  736. // standalone 1 char month
  737. array('y-LLLLL-d', '1970-J-1'),
  738. array('y-LLLLL-d', '1970-S-1'),
  739. );
  740. }
  741. /**
  742. * Just to document the differences between the stub and the intl implementations. The intl can parse
  743. * any of the tested formats alone. The stub does not implement them as it would be needed to add more
  744. * abstraction, passing more context to the transformers objects. Any of the formats are ignored alone
  745. * or with date/time data (years, months, days, hours, minutes and seconds).
  746. *
  747. * Also in intl, format like 'ss E' for '10 2' (2nd day of year + 10 seconds) are added, then we have
  748. * 86,400 seconds (24h * 60min * 60s) + 10 seconds
  749. *
  750. * @dataProvider parseDifferences()
  751. */
  752. public function testParseDifferencesStub($pattern, $value, $stubExpected, $intlExpected)
  753. {
  754. $formatter = $this->createStubFormatter($pattern);
  755. $this->assertSame($stubExpected, $formatter->parse($value));
  756. }
  757. /**
  758. * @dataProvider parseDifferences()
  759. */
  760. public function testParseDifferencesIntl($pattern, $value, $stubExpected, $intlExpected)
  761. {
  762. $this->skipIfIntlExtensionIsNotLoaded();
  763. $this->skipIfICUVersionIsTooOld();
  764. $formatter = $this->createIntlFormatter($pattern);
  765. $this->assertSame($intlExpected, $formatter->parse($value));
  766. }
  767. public function parseDifferences()
  768. {
  769. return array(
  770. // AM/PM, ignored if alone
  771. array('a', 'AM', 0, 0),
  772. array('a', 'PM', 0, 43200),
  773. // day of week
  774. array('E', 'Thu', 0, 0),
  775. array('EE', 'Thu', 0, 0),
  776. array('EEE', 'Thu', 0, 0),
  777. array('EEEE', 'Thursday', 0, 0),
  778. array('EEEEE', 'T', 0, 432000),
  779. array('EEEEEE', 'Thu', 0, 0),
  780. // day of year
  781. array('D', '1', 0, 0),
  782. array('D', '2', 0, 86400),
  783. // quarter
  784. array('Q', '1', 0, 0),
  785. array('QQ', '01', 0, 0),
  786. array('QQQ', 'Q1', 0, 0),
  787. array('QQQQ', '1st quarter', 0, 0),
  788. array('QQQQQ', '1st quarter', 0, 0),
  789. array('Q', '2', 0, 7776000),
  790. array('QQ', '02', 0, 7776000),
  791. array('QQQ', 'Q2', 0, 7776000),
  792. array('QQQQ', '2nd quarter', 0, 7776000),
  793. array('QQQQQ', '2nd quarter', 0, 7776000),
  794. array('q', '1', 0, 0),
  795. array('qq', '01', 0, 0),
  796. array('qqq', 'Q1', 0, 0),
  797. array('qqqq', '1st quarter', 0, 0),
  798. array('qqqqq', '1st quarter', 0, 0),
  799. );
  800. }
  801. public function testParseWithNullPositionValueStub()
  802. {
  803. $position = null;
  804. $formatter = $this->createStubFormatter('y');
  805. $this->assertSame(0, $formatter->parse('1970', $position));
  806. $this->assertNull($position);
  807. }
  808. /**
  809. * @expectedException Symfony\Component\Locale\Exception\MethodArgumentNotImplementedException
  810. */
  811. public function testParseWithNotNullPositionValueStub()
  812. {
  813. $position = 0;
  814. $formatter = $this->createStubFormatter('y');
  815. $this->assertSame(0, $formatter->parse('1970', $position));
  816. }
  817. /**
  818. * @expectedException Symfony\Component\Locale\Exception\MethodNotImplementedException
  819. */
  820. public function testSetCalendar()
  821. {
  822. $formatter = $this->createStubFormatter();
  823. $formatter->setCalendar(StubIntlDateFormatter::GREGORIAN);
  824. }
  825. /**
  826. * @expectedException Symfony\Component\Locale\Exception\MethodArgumentValueNotImplementedException
  827. */
  828. public function testSetLenient()
  829. {
  830. $formatter = $this->createStubFormatter();
  831. $formatter->setLenient(true);
  832. }
  833. public function testSetPattern()
  834. {
  835. $formatter = $this->createStubFormatter();
  836. $formatter->setPattern('yyyy-MM-dd');
  837. $this->assertEquals('yyyy-MM-dd', $formatter->getPattern());
  838. }
  839. /**
  840. * @covers Symfony\Component\Locale\Stub\StubIntlDateFormatter::getTimeZoneId
  841. * @dataProvider setTimeZoneIdProvider()
  842. */
  843. public function testSetTimeZoneIdStub($timeZoneId)
  844. {
  845. $formatter = $this->createStubFormatter();
  846. $formatter->setTimeZoneId($timeZoneId);
  847. $this->assertEquals($timeZoneId, $formatter->getTimeZoneId());
  848. }
  849. /**
  850. * @dataProvider setTimeZoneIdProvider()
  851. */
  852. public function testSetTimeZoneIdIntl($timeZoneId)
  853. {
  854. $this->skipIfIntlExtensionIsNotLoaded();
  855. $formatter = $this->createIntlFormatter();
  856. $formatter->setTimeZoneId($timeZoneId);
  857. $this->assertEquals($timeZoneId, $formatter->getTimeZoneId());
  858. }
  859. public function setTimeZoneIdProvider()
  860. {
  861. return array(
  862. array('UTC'),
  863. array('GMT'),
  864. array('GMT-03:00'),
  865. array('GMT-0300'),
  866. array('Europe/Zurich'),
  867. // When time zone not exists, uses UTC by default
  868. array('Foo/Bar'),
  869. array('GMT+00:AA'),
  870. array('GMT+00AA'),
  871. );
  872. }
  873. /**
  874. * @expectedException Symfony\Component\Locale\Exception\NotImplementedException
  875. */
  876. public function testSetTimeZoneIdWithGmtTimeZoneWithMinutesOffsetStub()
  877. {
  878. $formatter = $this->createStubFormatter();
  879. $formatter->setTimeZoneId('GMT+00:30');
  880. }
  881. public function testSetTimeZoneIdWithGmtTimeZoneWithMinutesOffsetIntl()
  882. {
  883. $this->skipIfIntlExtensionIsNotLoaded();
  884. $formatter = $this->createIntlFormatter();
  885. $formatter->setTimeZoneId('GMT+00:30');
  886. $this->assertEquals('GMT+00:30', $formatter->getTimeZoneId());
  887. }
  888. public function testStaticCreate()
  889. {
  890. $formatter = StubIntlDateFormatter::create('en', StubIntlDateFormatter::MEDIUM, StubIntlDateFormatter::SHORT);
  891. $this->assertInstanceOf('Symfony\Component\Locale\Stub\StubIntlDateFormatter', $formatter);
  892. }
  893. protected function createStubFormatter($pattern = null)
  894. {
  895. return new StubIntlDateFormatter('en', StubIntlDateFormatter::MEDIUM, StubIntlDateFormatter::SHORT, 'UTC', StubIntlDateFormatter::GREGORIAN, $pattern);
  896. }
  897. protected function createIntlFormatter($pattern = null)
  898. {
  899. return new \IntlDateFormatter('en', \IntlDateFormatter::MEDIUM, \IntlDateFormatter::SHORT, 'UTC', \IntlDateFormatter::GREGORIAN, $pattern);
  900. }
  901. protected function createDateTime($timestamp = null)
  902. {
  903. $timeZone = getenv('TZ') ?: 'UTC';
  904. $dateTime = new \DateTime();
  905. $dateTime->setTimestamp(null === $timestamp ? time() : $timestamp);
  906. $dateTime->setTimeZone(new \DateTimeZone($timeZone));
  907. return $dateTime;
  908. }
  909. }