DateTest.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511
  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\Date;
  17. use Cake\I18n\FrozenDate;
  18. use Cake\TestSuite\TestCase;
  19. use DateTimeZone;
  20. /**
  21. * DateTest class
  22. */
  23. class DateTest extends TestCase
  24. {
  25. /**
  26. * Backup the locale property
  27. *
  28. * @var string
  29. */
  30. protected $locale;
  31. /**
  32. * setup
  33. *
  34. * @return void
  35. */
  36. public function setUp()
  37. {
  38. parent::setUp();
  39. $this->locale = Date::$defaultLocale;
  40. }
  41. /**
  42. * Teardown
  43. *
  44. * @return void
  45. */
  46. public function tearDown()
  47. {
  48. parent::tearDown();
  49. Date::$defaultLocale = $this->locale;
  50. FrozenDate::$defaultLocale = $this->locale;
  51. date_default_timezone_set('UTC');
  52. }
  53. /**
  54. * Provider for ensuring that Date and FrozenDate work the same way.
  55. *
  56. * @return void
  57. */
  58. public static function classNameProvider()
  59. {
  60. return ['mutable' => ['Cake\I18n\Date'], 'immutable' => ['Cake\I18n\FrozenDate']];
  61. }
  62. /**
  63. * Ensure that instances can be built from other objects.
  64. *
  65. * @dataProvider classNameProvider
  66. * @return void
  67. */
  68. public function testConstructFromAnotherInstance($class)
  69. {
  70. $time = '2015-01-22';
  71. $frozen = new FrozenDate($time, 'America/Chicago');
  72. $subject = new $class($frozen);
  73. $this->assertEquals($time, $subject->format('Y-m-d'), 'frozen date construction');
  74. $mut = new Date($time, 'America/Chicago');
  75. $subject = new $class($mut);
  76. $this->assertEquals($time, $subject->format('Y-m-d'), 'mutable date construction');
  77. }
  78. /**
  79. * test formatting dates taking in account preferred i18n locale file
  80. *
  81. * @dataProvider classNameProvider
  82. * @return void
  83. */
  84. public function testI18nFormat($class)
  85. {
  86. $time = new $class('Thu Jan 14 13:59:28 2010');
  87. $result = $time->i18nFormat();
  88. $expected = '1/14/10';
  89. $this->assertEquals($expected, $result);
  90. $format = [\IntlDateFormatter::NONE, \IntlDateFormatter::SHORT];
  91. $result = $time->i18nFormat($format);
  92. $expected = '12:00 AM';
  93. $this->assertEquals($expected, $result);
  94. $result = $time->i18nFormat('HH:mm:ss', 'Australia/Sydney');
  95. $expected = '00:00:00';
  96. $this->assertEquals($expected, $result);
  97. $class::$defaultLocale = 'fr-FR';
  98. $result = $time->i18nFormat(\IntlDateFormatter::FULL);
  99. $result = str_replace(' à', '', $result);
  100. $expected = 'jeudi 14 janvier 2010 00:00:00 UTC';
  101. $this->assertEquals($expected, $result);
  102. $result = $time->i18nFormat(\IntlDateFormatter::FULL, null, 'es-ES');
  103. $this->assertContains('14 de enero de 2010', $result, 'Default locale should not be used');
  104. }
  105. /**
  106. * test __toString
  107. *
  108. * @dataProvider classNameProvider
  109. * @return void
  110. */
  111. public function testToString($class)
  112. {
  113. $date = new $class('2015-11-06 11:32:45');
  114. $this->assertEquals('11/6/15', (string)$date);
  115. }
  116. /**
  117. * test nice()
  118. *
  119. * @dataProvider classNameProvider
  120. * @return void
  121. */
  122. public function testNice($class)
  123. {
  124. $date = new $class('2015-11-06 11:32:45');
  125. $this->assertEquals('Nov 6, 2015', $date->nice());
  126. $this->assertEquals('Nov 6, 2015', $date->nice(new DateTimeZone('America/New_York')));
  127. $this->assertEquals('6 nov. 2015', $date->nice(null, 'fr-FR'));
  128. }
  129. /**
  130. * test jsonSerialize()
  131. *
  132. * @dataProvider classNameProvider
  133. * @return void
  134. */
  135. public function testJsonSerialize($class)
  136. {
  137. if (version_compare(INTL_ICU_VERSION, '50.0', '<')) {
  138. $this->markTestSkipped('ICU 5x is needed');
  139. }
  140. $date = new $class('2015-11-06 11:32:45');
  141. $this->assertEquals('"2015-11-06T00:00:00+00:00"', json_encode($date));
  142. }
  143. /**
  144. * test parseDate()
  145. *
  146. * @dataProvider classNameProvider
  147. * @return void
  148. */
  149. public function testParseDate($class)
  150. {
  151. $date = $class::parseDate('11/6/15');
  152. $this->assertEquals('2015-11-06 00:00:00', $date->format('Y-m-d H:i:s'));
  153. $class::$defaultLocale = 'fr-FR';
  154. $date = $class::parseDate('13 10, 2015');
  155. $this->assertEquals('2015-10-13 00:00:00', $date->format('Y-m-d H:i:s'));
  156. }
  157. /**
  158. * test parseDateTime()
  159. *
  160. * @dataProvider classNameProvider
  161. * @return void
  162. */
  163. public function testParseDateTime($class)
  164. {
  165. $date = $class::parseDate('11/6/15 12:33:12');
  166. $this->assertEquals('2015-11-06 00:00:00', $date->format('Y-m-d H:i:s'));
  167. $class::$defaultLocale = 'fr-FR';
  168. $date = $class::parseDate('13 10, 2015 12:54:12');
  169. $this->assertEquals('2015-10-13 00:00:00', $date->format('Y-m-d H:i:s'));
  170. }
  171. /**
  172. * provider for timeAgoInWords() tests
  173. *
  174. * @return array
  175. */
  176. public static function timeAgoProvider()
  177. {
  178. return [
  179. ['-12 seconds', 'today'],
  180. ['-12 minutes', 'today'],
  181. ['-2 hours', 'today'],
  182. ['-1 day', '1 day ago'],
  183. ['-2 days', '2 days ago'],
  184. ['-1 week', '1 week ago'],
  185. ['-2 weeks -2 days', '2 weeks, 2 days ago'],
  186. ['+1 second', 'today'],
  187. ['+1 minute, +10 seconds', 'today'],
  188. ['+1 week', '1 week'],
  189. ['+1 week 1 day', '1 week, 1 day'],
  190. ['+2 weeks 2 day', '2 weeks, 2 days'],
  191. ['2007-9-24', 'on 9/24/07'],
  192. ['now', 'today'],
  193. ];
  194. }
  195. /**
  196. * testTimeAgoInWords method
  197. *
  198. * @dataProvider timeAgoProvider
  199. * @return void
  200. */
  201. public function testTimeAgoInWords($input, $expected)
  202. {
  203. $date = new Date($input);
  204. $result = $date->timeAgoInWords();
  205. $this->assertEquals($expected, $result);
  206. }
  207. /**
  208. * testTimeAgoInWords with Frozen Date
  209. *
  210. * @dataProvider timeAgoProvider
  211. * @return void
  212. */
  213. public function testTimeAgoInWordsFrozenDate($input, $expected)
  214. {
  215. $date = new FrozenDate($input);
  216. $result = $date->timeAgoInWords();
  217. $this->assertEquals($expected, $result);
  218. }
  219. /**
  220. * test the timezone option for timeAgoInWords
  221. *
  222. * @dataProvider classNameProvider
  223. * @return void
  224. */
  225. public function testTimeAgoInWordsTimezone($class)
  226. {
  227. $date = new $class('1990-07-31 20:33:00 UTC');
  228. $result = $date->timeAgoInWords(
  229. [
  230. 'timezone' => 'America/Vancouver',
  231. 'end' => '+1month',
  232. 'format' => 'dd-MM-YYYY'
  233. ]
  234. );
  235. $this->assertEquals('on 31-07-1990', $result);
  236. }
  237. /**
  238. * provider for timeAgo with an end date.
  239. *
  240. * @return void
  241. */
  242. public function timeAgoEndProvider()
  243. {
  244. return [
  245. [
  246. '+4 months +2 weeks +3 days',
  247. '4 months, 2 weeks, 3 days',
  248. '8 years'
  249. ],
  250. [
  251. '+4 months +2 weeks +1 day',
  252. '4 months, 2 weeks, 1 day',
  253. '8 years'
  254. ],
  255. [
  256. '+3 months +2 weeks',
  257. '3 months, 2 weeks',
  258. '8 years'
  259. ],
  260. [
  261. '+3 months +2 weeks +1 day',
  262. '3 months, 2 weeks, 1 day',
  263. '8 years'
  264. ],
  265. [
  266. '+1 months +1 week +1 day',
  267. '1 month, 1 week, 1 day',
  268. '8 years'
  269. ],
  270. [
  271. '+2 months +2 days',
  272. '2 months, 2 days',
  273. '+2 months +2 days'
  274. ],
  275. [
  276. '+2 months +12 days',
  277. '2 months, 1 week, 5 days',
  278. '3 months'
  279. ],
  280. ];
  281. }
  282. /**
  283. * test the end option for timeAgoInWords
  284. *
  285. * @dataProvider timeAgoEndProvider
  286. * @return void
  287. */
  288. public function testTimeAgoInWordsEnd($input, $expected, $end)
  289. {
  290. $time = new Date($input);
  291. $result = $time->timeAgoInWords(['end' => $end]);
  292. $this->assertEquals($expected, $result);
  293. }
  294. /**
  295. * test the end option for timeAgoInWords
  296. *
  297. * @dataProvider timeAgoEndProvider
  298. * @return void
  299. */
  300. public function testTimeAgoInWordsEndFrozenDate($input, $expected, $end)
  301. {
  302. $time = new FrozenDate($input);
  303. $result = $time->timeAgoInWords(['end' => $end]);
  304. $this->assertEquals($expected, $result);
  305. }
  306. /**
  307. * test the custom string options for timeAgoInWords
  308. *
  309. * @dataProvider classNameProvider
  310. * @return void
  311. */
  312. public function testTimeAgoInWordsCustomStrings($class)
  313. {
  314. $date = new $class('-8 years -4 months -2 weeks -3 days');
  315. $result = $date->timeAgoInWords([
  316. 'relativeString' => 'at least %s ago',
  317. 'accuracy' => ['year' => 'year'],
  318. 'end' => '+10 years'
  319. ]);
  320. $expected = 'at least 8 years ago';
  321. $this->assertEquals($expected, $result);
  322. $date = new $class('+4 months +2 weeks +3 days');
  323. $result = $date->timeAgoInWords([
  324. 'absoluteString' => 'exactly on %s',
  325. 'accuracy' => ['year' => 'year'],
  326. 'end' => '+2 months'
  327. ]);
  328. $expected = 'exactly on ' . date('n/j/y', strtotime('+4 months +2 weeks +3 days'));
  329. $this->assertEquals($expected, $result);
  330. }
  331. /**
  332. * Test the accuracy option for timeAgoInWords()
  333. *
  334. * @dataProvider classNameProvider
  335. * @return void
  336. */
  337. public function testDateAgoInWordsAccuracy($class)
  338. {
  339. $date = new $class('+8 years +4 months +2 weeks +3 days');
  340. $result = $date->timeAgoInWords([
  341. 'accuracy' => ['year' => 'year'],
  342. 'end' => '+10 years'
  343. ]);
  344. $expected = '8 years';
  345. $this->assertEquals($expected, $result);
  346. $date = new $class('+8 years +4 months +2 weeks +3 days');
  347. $result = $date->timeAgoInWords([
  348. 'accuracy' => ['year' => 'month'],
  349. 'end' => '+10 years'
  350. ]);
  351. $expected = '8 years, 4 months';
  352. $this->assertEquals($expected, $result);
  353. $date = new $class('+8 years +4 months +2 weeks +3 days');
  354. $result = $date->timeAgoInWords([
  355. 'accuracy' => ['year' => 'week'],
  356. 'end' => '+10 years'
  357. ]);
  358. $expected = '8 years, 4 months, 2 weeks';
  359. $this->assertEquals($expected, $result);
  360. $date = new $class('+8 years +4 months +2 weeks +3 days');
  361. $result = $date->timeAgoInWords([
  362. 'accuracy' => ['year' => 'day'],
  363. 'end' => '+10 years'
  364. ]);
  365. $expected = '8 years, 4 months, 2 weeks, 3 days';
  366. $this->assertEquals($expected, $result);
  367. $date = new $class('+1 years +5 weeks');
  368. $result = $date->timeAgoInWords([
  369. 'accuracy' => ['year' => 'year'],
  370. 'end' => '+10 years'
  371. ]);
  372. $expected = '1 year';
  373. $this->assertEquals($expected, $result);
  374. $date = new $class('+23 hours');
  375. $result = $date->timeAgoInWords([
  376. 'accuracy' => 'day'
  377. ]);
  378. $expected = 'today';
  379. $this->assertEquals($expected, $result);
  380. }
  381. /**
  382. * Test the format option of timeAgoInWords()
  383. *
  384. * @dataProvider classNameProvider
  385. * @return void
  386. */
  387. public function testDateAgoInWordsWithFormat($class)
  388. {
  389. $date = new $class('2007-9-25');
  390. $result = $date->timeAgoInWords(['format' => 'yyyy-MM-dd']);
  391. $this->assertEquals('on 2007-09-25', $result);
  392. $date = new $class('2007-9-25');
  393. $result = $date->timeAgoInWords(['format' => 'yyyy-MM-dd']);
  394. $this->assertEquals('on 2007-09-25', $result);
  395. $date = new $class('+2 weeks +2 days');
  396. $result = $date->timeAgoInWords(['format' => 'yyyy-MM-dd']);
  397. $this->assertRegExp('/^2 weeks, [1|2] day(s)?$/', $result);
  398. $date = new $class('+2 months +2 days');
  399. $result = $date->timeAgoInWords(['end' => '1 month', 'format' => 'yyyy-MM-dd']);
  400. $this->assertEquals('on ' . date('Y-m-d', strtotime('+2 months +2 days')), $result);
  401. }
  402. /**
  403. * test timeAgoInWords() with negative values.
  404. *
  405. * @dataProvider classNameProvider
  406. * @return void
  407. */
  408. public function testDateAgoInWordsNegativeValues($class)
  409. {
  410. $date = new $class('-2 months -2 days');
  411. $result = $date->timeAgoInWords(['end' => '3 month']);
  412. $this->assertEquals('2 months, 2 days ago', $result);
  413. $date = new $class('-2 months -2 days');
  414. $result = $date->timeAgoInWords(['end' => '3 month']);
  415. $this->assertEquals('2 months, 2 days ago', $result);
  416. $date = new $class('-2 months -2 days');
  417. $result = $date->timeAgoInWords(['end' => '1 month', 'format' => 'yyyy-MM-dd']);
  418. $this->assertEquals('on ' . date('Y-m-d', strtotime('-2 months -2 days')), $result);
  419. $date = new $class('-2 years -5 months -2 days');
  420. $result = $date->timeAgoInWords(['end' => '3 years']);
  421. $this->assertEquals('2 years, 5 months, 2 days ago', $result);
  422. $date = new $class('-2 weeks -2 days');
  423. $result = $date->timeAgoInWords(['format' => 'yyyy-MM-dd']);
  424. $this->assertEquals('2 weeks, 2 days ago', $result);
  425. $date = new $class('-3 years -12 months');
  426. $result = $date->timeAgoInWords();
  427. $expected = 'on ' . $date->format('n/j/y');
  428. $this->assertEquals($expected, $result);
  429. $date = new $class('-1 month -1 week -6 days');
  430. $result = $date->timeAgoInWords(
  431. ['end' => '1 year', 'accuracy' => ['month' => 'month']]
  432. );
  433. $this->assertEquals('1 month ago', $result);
  434. $date = new $class('-1 years -2 weeks -3 days');
  435. $result = $date->timeAgoInWords(
  436. ['accuracy' => ['year' => 'year']]
  437. );
  438. $expected = 'on ' . $date->format('n/j/y');
  439. $this->assertEquals($expected, $result);
  440. $date = new $class('-13 months -5 days');
  441. $result = $date->timeAgoInWords(['end' => '2 years']);
  442. $this->assertEquals('1 year, 1 month, 5 days ago', $result);
  443. $date = new $class('-23 hours');
  444. $result = $date->timeAgoInWords(['accuracy' => 'day']);
  445. $this->assertEquals('today', $result);
  446. }
  447. /**
  448. * Tests that parsing a date in a timezone other than UTC
  449. * will not alter the date
  450. *
  451. * @dataProvider classNameProvider
  452. * @return void
  453. */
  454. public function testParseDateDifferentTimezone($class)
  455. {
  456. date_default_timezone_set('Europe/Paris');
  457. $result = $class::parseDate('25-02-2016', 'd-M-y');
  458. $this->assertEquals('25-02-2016', $result->format('d-m-Y'));
  459. }
  460. }