TimeTest.php 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860
  1. <?php
  2. /**
  3. * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
  4. * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  5. *
  6. * Licensed under The MIT License
  7. * For full copyright and license information, please see the LICENSE.txt
  8. * Redistributions of files must retain the above copyright notice
  9. *
  10. * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  11. * @link http://cakephp.org CakePHP(tm) Project
  12. * @since 1.2.0
  13. * @license http://www.opensource.org/licenses/mit-license.php MIT License
  14. */
  15. namespace Cake\Test\TestCase\I18n;
  16. use Cake\I18n\FrozenTime;
  17. use Cake\I18n\I18n;
  18. use Cake\I18n\Time;
  19. use Cake\TestSuite\TestCase;
  20. /**
  21. * TimeTest class
  22. *
  23. */
  24. class TimeTest extends TestCase
  25. {
  26. /**
  27. * setUp method
  28. *
  29. * @return void
  30. */
  31. public function setUp()
  32. {
  33. parent::setUp();
  34. $this->now = Time::getTestNow();
  35. $this->frozenNow = FrozenTime::getTestNow();
  36. $this->locale = Time::$defaultLocale;
  37. Time::$defaultLocale = 'en_US';
  38. FrozenTime::$defaultLocale = 'en_US';
  39. }
  40. /**
  41. * tearDown method
  42. *
  43. * @return void
  44. */
  45. public function tearDown()
  46. {
  47. parent::tearDown();
  48. Time::setTestNow($this->now);
  49. Time::$defaultLocale = $this->locale;
  50. Time::resetToStringFormat();
  51. FrozenTime::setTestNow($this->frozenNow);
  52. FrozenTime::$defaultLocale = $this->locale;
  53. FrozenTime::resetToStringFormat();
  54. date_default_timezone_set('UTC');
  55. I18n::locale(I18n::DEFAULT_LOCALE);
  56. }
  57. /**
  58. * Restored the original system timezone
  59. *
  60. * @return void
  61. */
  62. protected function _restoreSystemTimezone()
  63. {
  64. date_default_timezone_set($this->_systemTimezoneIdentifier);
  65. }
  66. /**
  67. * Provider for ensuring that Time and FrozenTime work the same way.
  68. *
  69. * @return void
  70. */
  71. public static function classNameProvider()
  72. {
  73. return ['mutable' => ['Cake\I18n\Time'], 'immutable' => ['Cake\I18n\FrozenTime']];
  74. }
  75. /**
  76. * Ensure that instances can be built from other objects.
  77. *
  78. * @dataProvider classNameProvider
  79. * @return void
  80. */
  81. public function testConstructFromAnotherInstance($class)
  82. {
  83. $time = '2015-01-22 10:33:44';
  84. $frozen = new FrozenTime($time, 'America/Chicago');
  85. $subject = new $class($frozen);
  86. $this->assertEquals($time, $subject->format('Y-m-d H:i:s'), 'frozen time construction');
  87. $mut = new Time($time, 'America/Chicago');
  88. $subject = new $class($mut);
  89. $this->assertEquals($time, $subject->format('Y-m-d H:i:s'), 'mutable time construction');
  90. }
  91. /**
  92. * provider for timeAgoInWords() tests
  93. *
  94. * @return array
  95. */
  96. public static function timeAgoProvider()
  97. {
  98. return [
  99. ['-12 seconds', '12 seconds ago'],
  100. ['-12 minutes', '12 minutes ago'],
  101. ['-2 hours', '2 hours ago'],
  102. ['-1 day', '1 day ago'],
  103. ['-2 days', '2 days ago'],
  104. ['-2 days -3 hours', '2 days, 3 hours ago'],
  105. ['-1 week', '1 week ago'],
  106. ['-2 weeks -2 days', '2 weeks, 2 days ago'],
  107. ['+1 week', '1 week'],
  108. ['+1 week 1 day', '1 week, 1 day'],
  109. ['+2 weeks 2 day', '2 weeks, 2 days'],
  110. ['2007-9-24', 'on 9/24/07'],
  111. ['now', 'just now'],
  112. ];
  113. }
  114. /**
  115. * testTimeAgoInWords method
  116. *
  117. * @dataProvider timeAgoProvider
  118. * @return void
  119. */
  120. public function testTimeAgoInWords($input, $expected)
  121. {
  122. $time = new Time($input);
  123. $result = $time->timeAgoInWords();
  124. $this->assertEquals($expected, $result);
  125. }
  126. /**
  127. * testTimeAgoInWords method
  128. *
  129. * @dataProvider timeAgoProvider
  130. * @return void
  131. */
  132. public function testTimeAgoInWordsFrozenTime($input, $expected)
  133. {
  134. $time = new FrozenTime($input);
  135. $result = $time->timeAgoInWords();
  136. $this->assertEquals($expected, $result);
  137. }
  138. /**
  139. * provider for timeAgo with an end date.
  140. *
  141. * @return void
  142. */
  143. public function timeAgoEndProvider()
  144. {
  145. return [
  146. [
  147. '+4 months +2 weeks +3 days',
  148. '4 months, 2 weeks, 3 days',
  149. '8 years'
  150. ],
  151. [
  152. '+4 months +2 weeks +1 day',
  153. '4 months, 2 weeks, 1 day',
  154. '8 years'
  155. ],
  156. [
  157. '+3 months +2 weeks',
  158. '3 months, 2 weeks',
  159. '8 years'
  160. ],
  161. [
  162. '+3 months +2 weeks +1 day',
  163. '3 months, 2 weeks, 1 day',
  164. '8 years'
  165. ],
  166. [
  167. '+1 months +1 week +1 day',
  168. '1 month, 1 week, 1 day',
  169. '8 years'
  170. ],
  171. [
  172. '+2 months +2 days',
  173. '2 months, 2 days',
  174. '+2 months +2 days'
  175. ],
  176. [
  177. '+2 months +12 days',
  178. '2 months, 1 week, 5 days',
  179. '3 months'
  180. ],
  181. ];
  182. }
  183. /**
  184. * test the timezone option for timeAgoInWords
  185. *
  186. * @dataProvider classNameProvider
  187. * @return void
  188. */
  189. public function testTimeAgoInWordsTimezone($class)
  190. {
  191. $time = new FrozenTime('1990-07-31 20:33:00 UTC');
  192. $result = $time->timeAgoInWords(
  193. [
  194. 'timezone' => 'America/Vancouver',
  195. 'end' => '+1month',
  196. 'format' => 'dd-MM-YYYY HH:mm:ss'
  197. ]
  198. );
  199. $this->assertEquals('on 31-07-1990 13:33:00', $result);
  200. }
  201. /**
  202. * test the end option for timeAgoInWords
  203. *
  204. * @dataProvider timeAgoEndProvider
  205. * @return void
  206. */
  207. public function testTimeAgoInWordsEnd($input, $expected, $end)
  208. {
  209. $time = new Time($input);
  210. $result = $time->timeAgoInWords(['end' => $end]);
  211. $this->assertEquals($expected, $result);
  212. }
  213. /**
  214. * test the custom string options for timeAgoInWords
  215. *
  216. * @dataProvider classNameProvider
  217. * @return void
  218. */
  219. public function testTimeAgoInWordsCustomStrings($class)
  220. {
  221. $time = new $class('-8 years -4 months -2 weeks -3 days');
  222. $result = $time->timeAgoInWords([
  223. 'relativeString' => 'at least %s ago',
  224. 'accuracy' => ['year' => 'year'],
  225. 'end' => '+10 years'
  226. ]);
  227. $expected = 'at least 8 years ago';
  228. $this->assertEquals($expected, $result);
  229. $time = new $class('+4 months +2 weeks +3 days');
  230. $result = $time->timeAgoInWords([
  231. 'absoluteString' => 'exactly on %s',
  232. 'accuracy' => ['year' => 'year'],
  233. 'end' => '+2 months'
  234. ]);
  235. $expected = 'exactly on ' . date('n/j/y', strtotime('+4 months +2 weeks +3 days'));
  236. $this->assertEquals($expected, $result);
  237. }
  238. /**
  239. * Test the accuracy option for timeAgoInWords()
  240. *
  241. * @dataProvider classNameProvider
  242. * @return void
  243. */
  244. public function testTimeAgoInWordsAccuracy($class)
  245. {
  246. $time = new $class('+8 years +4 months +2 weeks +3 days');
  247. $result = $time->timeAgoInWords([
  248. 'accuracy' => ['year' => 'year'],
  249. 'end' => '+10 years'
  250. ]);
  251. $expected = '8 years';
  252. $this->assertEquals($expected, $result);
  253. $time = new $class('+8 years +4 months +2 weeks +3 days');
  254. $result = $time->timeAgoInWords([
  255. 'accuracy' => ['year' => 'month'],
  256. 'end' => '+10 years'
  257. ]);
  258. $expected = '8 years, 4 months';
  259. $this->assertEquals($expected, $result);
  260. $time = new $class('+8 years +4 months +2 weeks +3 days');
  261. $result = $time->timeAgoInWords([
  262. 'accuracy' => ['year' => 'week'],
  263. 'end' => '+10 years'
  264. ]);
  265. $expected = '8 years, 4 months, 2 weeks';
  266. $this->assertEquals($expected, $result);
  267. $time = new $class('+8 years +4 months +2 weeks +3 days');
  268. $result = $time->timeAgoInWords([
  269. 'accuracy' => ['year' => 'day'],
  270. 'end' => '+10 years'
  271. ]);
  272. $expected = '8 years, 4 months, 2 weeks, 3 days';
  273. $this->assertEquals($expected, $result);
  274. $time = new $class('+1 years +5 weeks');
  275. $result = $time->timeAgoInWords([
  276. 'accuracy' => ['year' => 'year'],
  277. 'end' => '+10 years'
  278. ]);
  279. $expected = '1 year';
  280. $this->assertEquals($expected, $result);
  281. $time = new $class('+58 minutes');
  282. $result = $time->timeAgoInWords([
  283. 'accuracy' => 'hour'
  284. ]);
  285. $expected = 'in about an hour';
  286. $this->assertEquals($expected, $result);
  287. $time = new $class('+23 hours');
  288. $result = $time->timeAgoInWords([
  289. 'accuracy' => 'day'
  290. ]);
  291. $expected = 'in about a day';
  292. $this->assertEquals($expected, $result);
  293. $time = new $class('+20 days');
  294. $result = $time->timeAgoInWords(['accuracy' => 'month']);
  295. $this->assertEquals('in about a month', $result);
  296. }
  297. /**
  298. * Test the format option of timeAgoInWords()
  299. *
  300. * @dataProvider classNameProvider
  301. * @return void
  302. */
  303. public function testTimeAgoInWordsWithFormat($class)
  304. {
  305. $time = new $class('2007-9-25');
  306. $result = $time->timeAgoInWords(['format' => 'yyyy-MM-dd']);
  307. $this->assertEquals('on 2007-09-25', $result);
  308. $time = new $class('+2 weeks +2 days');
  309. $result = $time->timeAgoInWords(['format' => 'yyyy-MM-dd']);
  310. $this->assertRegExp('/^2 weeks, [1|2] day(s)?$/', $result);
  311. $time = new $class('+2 months +2 days');
  312. $result = $time->timeAgoInWords(['end' => '1 month', 'format' => 'yyyy-MM-dd']);
  313. $this->assertEquals('on ' . date('Y-m-d', strtotime('+2 months +2 days')), $result);
  314. }
  315. /**
  316. * test timeAgoInWords() with negative values.
  317. *
  318. * @dataProvider classNameProvider
  319. * @return void
  320. */
  321. public function testTimeAgoInWordsNegativeValues($class)
  322. {
  323. $time = new $class('-2 months -2 days');
  324. $result = $time->timeAgoInWords(['end' => '3 month']);
  325. $this->assertEquals('2 months, 2 days ago', $result);
  326. $time = new $class('-2 months -2 days');
  327. $result = $time->timeAgoInWords(['end' => '3 month']);
  328. $this->assertEquals('2 months, 2 days ago', $result);
  329. $time = new $class('-2 months -2 days');
  330. $result = $time->timeAgoInWords(['end' => '1 month', 'format' => 'yyyy-MM-dd']);
  331. $this->assertEquals('on ' . date('Y-m-d', strtotime('-2 months -2 days')), $result);
  332. $time = new $class('-2 years -5 months -2 days');
  333. $result = $time->timeAgoInWords(['end' => '3 years']);
  334. $this->assertEquals('2 years, 5 months, 2 days ago', $result);
  335. $time = new $class('-2 weeks -2 days');
  336. $result = $time->timeAgoInWords(['format' => 'yyyy-MM-dd']);
  337. $this->assertEquals('2 weeks, 2 days ago', $result);
  338. $time = new $class('-3 years -12 months');
  339. $result = $time->timeAgoInWords();
  340. $expected = 'on ' . $time->format('n/j/y');
  341. $this->assertEquals($expected, $result);
  342. $time = new $class('-1 month -1 week -6 days');
  343. $result = $time->timeAgoInWords(
  344. ['end' => '1 year', 'accuracy' => ['month' => 'month']]
  345. );
  346. $this->assertEquals('1 month ago', $result);
  347. $time = new $class('-1 years -2 weeks -3 days');
  348. $result = $time->timeAgoInWords(
  349. ['accuracy' => ['year' => 'year']]
  350. );
  351. $expected = 'on ' . $time->format('n/j/y');
  352. $this->assertEquals($expected, $result);
  353. $time = new $class('-13 months -5 days');
  354. $result = $time->timeAgoInWords(['end' => '2 years']);
  355. $this->assertEquals('1 year, 1 month, 5 days ago', $result);
  356. $time = new $class('-58 minutes');
  357. $result = $time->timeAgoInWords(['accuracy' => 'hour']);
  358. $this->assertEquals('about an hour ago', $result);
  359. $time = new $class('-23 hours');
  360. $result = $time->timeAgoInWords(['accuracy' => 'day']);
  361. $this->assertEquals('about a day ago', $result);
  362. $time = new $class('-20 days');
  363. $result = $time->timeAgoInWords(['accuracy' => 'month']);
  364. $this->assertEquals('about a month ago', $result);
  365. }
  366. /**
  367. * testNice method
  368. *
  369. * @dataProvider classNameProvider
  370. * @return void
  371. */
  372. public function testNice($class)
  373. {
  374. $time = new $class('2014-04-20 20:00', 'UTC');
  375. $this->assertTimeFormat('Apr 20, 2014, 8:00 PM', $time->nice());
  376. $result = $time->nice('America/New_York');
  377. $this->assertTimeFormat('Apr 20, 2014, 4:00 PM', $result);
  378. $this->assertEquals('UTC', $time->getTimezone()->getName());
  379. $this->assertTimeFormat('20 avr. 2014 20:00', $time->nice(null, 'fr-FR'));
  380. $this->assertTimeFormat('20 avr. 2014 16:00', $time->nice('America/New_York', 'fr-FR'));
  381. }
  382. /**
  383. * test formatting dates taking in account preferred i18n locale file
  384. *
  385. * @dataProvider classNameProvider
  386. * @return void
  387. */
  388. public function testI18nFormat($class)
  389. {
  390. $time = new $class('Thu Jan 14 13:59:28 2010');
  391. $result = $time->i18nFormat();
  392. $expected = '1/14/10, 1:59 PM';
  393. $this->assertTimeFormat($expected, $result);
  394. $result = $time->i18nFormat(\IntlDateFormatter::FULL, null, 'es-ES');
  395. $expected = 'jueves, 14 de enero de 2010, 13:59:28 (GMT)';
  396. $this->assertTimeFormat($expected, $result);
  397. $format = [\IntlDateFormatter::NONE, \IntlDateFormatter::SHORT];
  398. $result = $time->i18nFormat($format);
  399. $expected = '1:59 PM';
  400. $this->assertTimeFormat($expected, $result);
  401. $result = $time->i18nFormat('HH:mm:ss', 'Australia/Sydney');
  402. $expected = '00:59:28';
  403. $this->assertTimeFormat($expected, $result);
  404. $class::$defaultLocale = 'fr-FR';
  405. $result = $time->i18nFormat(\IntlDateFormatter::FULL);
  406. $expected = 'jeudi 14 janvier 2010 13:59:28 UTC';
  407. $this->assertTimeFormat($expected, $result);
  408. $result = $time->i18nFormat(\IntlDateFormatter::FULL, null, 'es-ES');
  409. $expected = 'jueves, 14 de enero de 2010, 13:59:28 (GMT)';
  410. $this->assertTimeFormat($expected, $result, 'Default locale should not be used');
  411. $result = $time->i18nFormat(\IntlDateFormatter::FULL, null, 'fa-SA');
  412. $expected = 'پنجشنبه ۱۴ ژانویهٔ ۲۰۱۰، ساعت ۱۳:۵۹:۲۸ (GMT)';
  413. $this->assertTimeFormat($expected, $result, 'fa-SA locale should be used');
  414. $result = $time->i18nFormat(\IntlDateFormatter::FULL, null, 'en-IR@calendar=persian');
  415. $expected = 'Thursday, Dey 24, 1388 at 1:59:28 PM GMT';
  416. $this->assertTimeFormat($expected, $result);
  417. $result = $time->i18nFormat(\IntlDateFormatter::FULL, null, 'ps-IR@calendar=persian');
  418. $expected = 'پنجشنبه د ۱۳۸۸ د مرغومی ۲۴ ۱۳:۵۹:۲۸ (GMT)';
  419. $this->assertTimeFormat($expected, $result);
  420. $result = $time->i18nFormat(\IntlDateFormatter::FULL, null, 'en-KW@calendar=islamic');
  421. $expected = 'Thursday, Muharram 29, 1431 at 1:59:28 PM GMT';
  422. $this->assertTimeFormat($expected, $result);
  423. $result = $time->i18nFormat(\IntlDateFormatter::FULL, 'Asia/Tokyo', 'ja-JP@calendar=japanese');
  424. $expected = '平成22年1月14日木曜日 22時59分28秒 日本標準時';
  425. $this->assertTimeFormat($expected, $result);
  426. $result = $time->i18nFormat(\IntlDateFormatter::FULL, 'Asia/Tokyo', 'ja-JP@calendar=japanese');
  427. $expected = '平成22年1月14日木曜日 22時59分28秒 日本標準時';
  428. $this->assertTimeFormat($expected, $result);
  429. }
  430. /**
  431. * test formatting dates with offset style timezone
  432. *
  433. * @dataProvider classNameProvider
  434. * @see https://github.com/facebook/hhvm/issues/3637
  435. * @return void
  436. */
  437. public function testI18nFormatWithOffsetTimezone($class)
  438. {
  439. $time = new $class('2014-01-01T00:00:00+00');
  440. $result = $time->i18nFormat(\IntlDateFormatter::FULL);
  441. $expected = 'Wednesday January 1 2014 12:00:00 AM GMT';
  442. $this->assertTimeFormat($expected, $result);
  443. $time = new $class('2014-01-01T00:00:00+09');
  444. $result = $time->i18nFormat(\IntlDateFormatter::FULL);
  445. $expected = 'Wednesday January 1 2014 12:00:00 AM GMT+09:00';
  446. $this->assertTimeFormat($expected, $result);
  447. $time = new $class('2014-01-01T00:00:00-01:30');
  448. $result = $time->i18nFormat(\IntlDateFormatter::FULL);
  449. $expected = 'Wednesday January 1 2014 12:00:00 AM GMT-01:30';
  450. $this->assertTimeFormat($expected, $result);
  451. }
  452. /**
  453. * testListTimezones
  454. *
  455. * @dataProvider classNameProvider
  456. * @return void
  457. */
  458. public function testListTimezones($class)
  459. {
  460. $return = $class::listTimezones();
  461. $this->assertTrue(isset($return['Asia']['Asia/Bangkok']));
  462. $this->assertEquals('Bangkok', $return['Asia']['Asia/Bangkok']);
  463. $this->assertTrue(isset($return['America']['America/Argentina/Buenos_Aires']));
  464. $this->assertEquals('Argentina/Buenos_Aires', $return['America']['America/Argentina/Buenos_Aires']);
  465. $this->assertTrue(isset($return['UTC']['UTC']));
  466. $this->assertFalse(isset($return['Cuba']));
  467. $this->assertFalse(isset($return['US']));
  468. $return = $class::listTimezones('#^Asia/#');
  469. $this->assertTrue(isset($return['Asia']['Asia/Bangkok']));
  470. $this->assertFalse(isset($return['Pacific']));
  471. $return = $class::listTimezones(null, null, ['abbr' => true]);
  472. $this->assertTrue(isset($return['Asia']['Asia/Jakarta']));
  473. $this->assertEquals('Jakarta - WIB', $return['Asia']['Asia/Jakarta']);
  474. $this->assertEquals('Regina - CST', $return['America']['America/Regina']);
  475. $return = $class::listTimezones(null, null, [
  476. 'abbr' => true,
  477. 'before' => ' (',
  478. 'after' => ')',
  479. ]);
  480. $this->assertEquals('Jayapura (WIT)', $return['Asia']['Asia/Jayapura']);
  481. $this->assertEquals('Regina (CST)', $return['America']['America/Regina']);
  482. $return = $class::listTimezones('#^(America|Pacific)/#', null, false);
  483. $this->assertTrue(isset($return['America/Argentina/Buenos_Aires']));
  484. $this->assertTrue(isset($return['Pacific/Tahiti']));
  485. $return = $class::listTimezones(\DateTimeZone::ASIA);
  486. $this->assertTrue(isset($return['Asia']['Asia/Bangkok']));
  487. $this->assertFalse(isset($return['Pacific']));
  488. $return = $class::listTimezones(\DateTimeZone::PER_COUNTRY, 'US', false);
  489. $this->assertTrue(isset($return['Pacific/Honolulu']));
  490. $this->assertFalse(isset($return['Asia/Bangkok']));
  491. }
  492. /**
  493. * Tests that __toString uses the i18n formatter
  494. *
  495. * @dataProvider classNameProvider
  496. * @return void
  497. */
  498. public function testToString($class)
  499. {
  500. $time = new $class('2014-04-20 22:10');
  501. $class::$defaultLocale = 'fr-FR';
  502. $class::setToStringFormat(\IntlDateFormatter::FULL);
  503. $this->assertTimeFormat('dimanche 20 avril 2014 22:10:00 UTC', (string)$time);
  504. }
  505. /**
  506. * Data provider for invalid values.
  507. *
  508. * @return array
  509. */
  510. public function invalidDataProvider()
  511. {
  512. return [
  513. [null],
  514. [false],
  515. [''],
  516. ];
  517. }
  518. /**
  519. * Test that invalid datetime values do not trigger errors.
  520. *
  521. * @dataProvider invalidDataProvider
  522. * @return void
  523. */
  524. public function testToStringInvalid($value)
  525. {
  526. $time = new Time($value);
  527. $this->assertInternalType('string', (string)$time);
  528. $this->assertNotEmpty((string)$time);
  529. }
  530. /**
  531. * Test that invalid datetime values do not trigger errors.
  532. *
  533. * @dataProvider invalidDataProvider
  534. * @return void
  535. */
  536. public function testToStringInvalidFrozen($value)
  537. {
  538. $time = new FrozenTime($value);
  539. $this->assertInternalType('string', (string)$time);
  540. $this->assertNotEmpty((string)$time);
  541. }
  542. /**
  543. * These invalid values are not invalid on windows :(
  544. *
  545. * @dataProvider classNameProvider
  546. * @return void
  547. */
  548. public function testToStringInvalidZeros($class)
  549. {
  550. $this->skipIf(DS === '\\', 'All zeros are valid on windows.');
  551. $this->skipIf(PHP_INT_SIZE === 4, 'IntlDateFormatter throws exceptions on 32-bit systems');
  552. $time = new $class('0000-00-00');
  553. $this->assertInternalType('string', (string)$time);
  554. $this->assertNotEmpty((string)$time);
  555. $time = new $class('0000-00-00 00:00:00');
  556. $this->assertInternalType('string', (string)$time);
  557. $this->assertNotEmpty((string)$time);
  558. }
  559. /**
  560. * Tests diffForHumans
  561. *
  562. * @dataProvider classNameProvider
  563. * @return void
  564. */
  565. public function testDiffForHumans($class)
  566. {
  567. $time = new $class('2014-04-20 10:10:10');
  568. $other = new $class('2014-04-27 10:10:10');
  569. $this->assertEquals('1 week before', $time->diffForHumans($other));
  570. $other = new $class('2014-04-21 09:10:10');
  571. $this->assertEquals('23 hours before', $time->diffForHumans($other));
  572. $other = new $class('2014-04-13 09:10:10');
  573. $this->assertEquals('1 week after', $time->diffForHumans($other));
  574. $other = new $class('2014-04-06 09:10:10');
  575. $this->assertEquals('2 weeks after', $time->diffForHumans($other));
  576. $other = new $class('2014-04-21 10:10:10');
  577. $this->assertEquals('1 day before', $time->diffForHumans($other));
  578. $other = new $class('2014-04-22 10:10:10');
  579. $this->assertEquals('2 days before', $time->diffForHumans($other));
  580. $other = new $class('2014-04-20 10:11:10');
  581. $this->assertEquals('1 minute before', $time->diffForHumans($other));
  582. $other = new $class('2014-04-20 10:12:10');
  583. $this->assertEquals('2 minutes before', $time->diffForHumans($other));
  584. $other = new $class('2014-04-20 10:10:09');
  585. $this->assertEquals('1 second after', $time->diffForHumans($other));
  586. $other = new $class('2014-04-20 10:10:08');
  587. $this->assertEquals('2 seconds after', $time->diffForHumans($other));
  588. }
  589. /**
  590. * Tests diffForHumans absolute
  591. *
  592. * @dataProvider classNameProvider
  593. * @return void
  594. */
  595. public function testDiffForHumansAbsolute($class)
  596. {
  597. $class::setTestNow(new $class('2015-12-12 10:10:10'));
  598. $time = new $class('2014-04-20 10:10:10');
  599. $this->assertEquals('1 year', $time->diffForHumans(null, ['absolute' => true]));
  600. $other = new $class('2014-04-27 10:10:10');
  601. $this->assertEquals('1 week', $time->diffForHumans($other, ['absolute' => true]));
  602. $time = new $class('2016-04-20 10:10:10');
  603. $this->assertEquals('4 months', $time->diffForHumans(null, ['absolute' => true]));
  604. }
  605. /**
  606. * Tests diffForHumans with now
  607. *
  608. * @dataProvider classNameProvider
  609. * @return void
  610. */
  611. public function testDiffForHumansNow($class)
  612. {
  613. $class::setTestNow(new $class('2015-12-12 10:10:10'));
  614. $time = new $class('2014-04-20 10:10:10');
  615. $this->assertEquals('1 year ago', $time->diffForHumans());
  616. $time = new $class('2016-04-20 10:10:10');
  617. $this->assertEquals('4 months from now', $time->diffForHumans());
  618. }
  619. /**
  620. * Tests encoding a Time object as json
  621. *
  622. * @dataProvider classNameProvider
  623. * @return void
  624. */
  625. public function testJsonEnconde($class)
  626. {
  627. $time = new $class('2014-04-20 10:10:10');
  628. $this->assertEquals('"2014-04-20T10:10:10+00:00"', json_encode($time));
  629. $class::setJsonEncodeFormat('yyyy-MM-dd HH:mm:ss');
  630. $this->assertEquals('"2014-04-20 10:10:10"', json_encode($time));
  631. }
  632. /**
  633. * Tests debugInfo
  634. *
  635. * @dataProvider classNameProvider
  636. * @return void
  637. */
  638. public function testDebugInfo($class)
  639. {
  640. $time = new $class('2014-04-20 10:10:10');
  641. $expected = [
  642. 'time' => '2014-04-20T10:10:10+00:00',
  643. 'timezone' => 'UTC',
  644. 'fixedNowTime' => $class::getTestNow()->toIso8601String()
  645. ];
  646. $this->assertEquals($expected, $time->__debugInfo());
  647. }
  648. /**
  649. * Tests parsing a string into a Time object based on the locale format.
  650. *
  651. * @dataProvider classNameProvider
  652. * @return void
  653. */
  654. public function testParseDateTime($class)
  655. {
  656. $time = $class::parseDateTime('01/01/1970 00:00am');
  657. $this->assertNotNull($time);
  658. $this->assertEquals('1970-01-01 00:00', $time->format('Y-m-d H:i'));
  659. $time = $class::parseDateTime('10/13/2013 12:54am');
  660. $this->assertNotNull($time);
  661. $this->assertEquals('2013-10-13 00:54', $time->format('Y-m-d H:i'));
  662. $class::$defaultLocale = 'fr-FR';
  663. $time = $class::parseDateTime('13 10, 2013 12:54');
  664. $this->assertNotNull($time);
  665. $this->assertEquals('2013-10-13 12:54', $time->format('Y-m-d H:i'));
  666. $time = $class::parseDateTime('13 foo 10 2013 12:54');
  667. $this->assertNull($time);
  668. }
  669. /**
  670. * Tests parsing a string into a Time object based on the locale format.
  671. *
  672. * @dataProvider classNameProvider
  673. * @return void
  674. */
  675. public function testParseDate($class)
  676. {
  677. $time = $class::parseDate('10/13/2013 12:54am');
  678. $this->assertNotNull($time);
  679. $this->assertEquals('2013-10-13 00:00', $time->format('Y-m-d H:i'));
  680. $time = $class::parseDate('10/13/2013');
  681. $this->assertNotNull($time);
  682. $this->assertEquals('2013-10-13 00:00', $time->format('Y-m-d H:i'));
  683. $class::$defaultLocale = 'fr-FR';
  684. $time = $class::parseDate('13 10, 2013 12:54');
  685. $this->assertNotNull($time);
  686. $this->assertEquals('2013-10-13 00:00', $time->format('Y-m-d H:i'));
  687. $time = $class::parseDate('13 foo 10 2013 12:54');
  688. $this->assertNull($time);
  689. $time = $class::parseDate('13 10, 2013', 'dd M, y');
  690. $this->assertNotNull($time);
  691. $this->assertEquals('2013-10-13', $time->format('Y-m-d'));
  692. }
  693. /**
  694. * Tests parsing times using the parseTime function
  695. *
  696. * @dataProvider classNameProvider
  697. * @return void
  698. */
  699. public function testParseTime($class)
  700. {
  701. $time = $class::parseTime('12:54am');
  702. $this->assertNotNull($time);
  703. $this->assertEquals('00:54:00', $time->format('H:i:s'));
  704. $class::$defaultLocale = 'fr-FR';
  705. $time = $class::parseTime('23:54');
  706. $this->assertNotNull($time);
  707. $this->assertEquals('23:54:00', $time->format('H:i:s'));
  708. $time = $class::parseTime('31c2:54');
  709. $this->assertNull($time);
  710. }
  711. /**
  712. * Tests that timeAgoInWords when using a russian locale does not break things
  713. *
  714. * @dataProvider classNameProvider
  715. * @return void
  716. */
  717. public function testRussianTimeAgoInWords($class)
  718. {
  719. I18n::locale('ru_RU');
  720. $time = new $class('5 days ago');
  721. $result = $time->timeAgoInWords();
  722. $this->assertEquals('5 days ago', $result);
  723. }
  724. /**
  725. * Tests that parsing a date respects de default timezone in PHP.
  726. *
  727. * @dataProvider classNameProvider
  728. * @return void
  729. */
  730. public function testParseDateDifferentTimezone($class)
  731. {
  732. date_default_timezone_set('Europe/Paris');
  733. $class::$defaultLocale = 'fr-FR';
  734. $result = $class::parseDate('12/03/2015');
  735. $this->assertEquals('2015-03-12', $result->format('Y-m-d'));
  736. $this->assertEquals(new \DateTimeZone('Europe/Paris'), $result->tz);
  737. }
  738. /**
  739. * Custom assert to allow for variation in the version of the intl library, where
  740. * some translations contain a few extra commas.
  741. *
  742. * @param string $expected
  743. * @param string $result
  744. * @return void
  745. */
  746. public function assertTimeFormat($expected, $result, $message = "")
  747. {
  748. $expected = str_replace([',', '(', ')', ' at', ' م.', ' ه‍.ش.', ' AP', ' AH', ' SAKA', 'à '], '', $expected);
  749. $expected = str_replace([' '], ' ', $expected);
  750. $result = str_replace([',', '(', ')', ' at', ' م.', ' ه‍.ش.', ' AP', ' AH', ' SAKA', 'à '], '', $result);
  751. $result = str_replace(['گرینویچ'], 'GMT', $result);
  752. $result = str_replace([' '], ' ', $result);
  753. return $this->assertSame($expected, $result, $message);
  754. }
  755. }