TestingAidsTest.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * This file is part of the Carbon package.
  5. *
  6. * (c) Brian Nesbitt <brian@nesbot.com>
  7. *
  8. * For the full copyright and license information, please view the LICENSE
  9. * file that was distributed with this source code.
  10. */
  11. namespace Tests\Carbon;
  12. use Carbon\Carbon;
  13. use DateTimeZone;
  14. use Exception;
  15. use InvalidArgumentException;
  16. use stdClass;
  17. use Tests\AbstractTestCase;
  18. class TestingAidsTest extends AbstractTestCase
  19. {
  20. public function testTestingAidsWithTestNowNotSet()
  21. {
  22. Carbon::setTestNow();
  23. $this->assertFalse(Carbon::hasTestNow());
  24. $this->assertNull(Carbon::getTestNow());
  25. }
  26. public function testTestingAidsWithTestNowSet()
  27. {
  28. Carbon::setTestNow($yesterday = Carbon::yesterday());
  29. $this->assertTrue(Carbon::hasTestNow());
  30. $this->assertSame($yesterday, Carbon::getTestNow());
  31. }
  32. public function testTestingAidsWithTestNowSetToString()
  33. {
  34. Carbon::setTestNow('2016-11-23');
  35. $this->assertTrue(Carbon::hasTestNow());
  36. $this->assertEquals(Carbon::getTestNow(), Carbon::parse('2016-11-23'));
  37. }
  38. public function testConstructorWithTestValueSet()
  39. {
  40. Carbon::setTestNow($yesterday = Carbon::yesterday());
  41. $this->assertEquals($yesterday, new Carbon());
  42. $this->assertEquals($yesterday, new Carbon(null));
  43. $this->assertEquals($yesterday, new Carbon(''));
  44. $this->assertEquals($yesterday, new Carbon('now'));
  45. }
  46. public function testNowWithTestValueSet()
  47. {
  48. Carbon::setTestNow($yesterday = Carbon::yesterday());
  49. $this->assertEquals($yesterday, Carbon::now());
  50. }
  51. public function testParseWithTestValueSet()
  52. {
  53. $testNow = Carbon::yesterday();
  54. $this->wrapWithTestNow(function () use ($testNow) {
  55. $this->assertEquals($testNow, Carbon::parse());
  56. $this->assertEquals($testNow, Carbon::parse(null));
  57. $this->assertEquals($testNow, Carbon::parse(''));
  58. $this->assertEquals($testNow, Carbon::parse('now'));
  59. }, $testNow);
  60. }
  61. public function testNowWithClosureValue()
  62. {
  63. $mockedNow = Carbon::parse('2019-09-21 12:34:56.123456');
  64. $delta = 0;
  65. Carbon::setTestNow(function (Carbon $now) use (&$mockedNow, &$delta) {
  66. $this->assertInstanceOfCarbon($now);
  67. return $mockedNow->copy()->tz($now->tz)->addMicroseconds($delta);
  68. });
  69. $this->assertSame('2019-09-21 12:34:56.123456', Carbon::now()->format('Y-m-d H:i:s.u'));
  70. $this->assertSame('2019-09-21 00:00:00.000000', Carbon::today()->format('Y-m-d H:i:s.u'));
  71. $this->assertSame('2019-09-22 00:00:00.000000', Carbon::create('tomorrow')->format('Y-m-d H:i:s.u'));
  72. $this->assertSame('2018-06-15 12:34:00.000000', Carbon::create(2018, 6, 15, null, null)->format('Y-m-d H:i:s.u'));
  73. $delta = 11111111;
  74. $date = Carbon::now();
  75. $this->assertSame('America/Toronto', $date->tzName);
  76. $this->assertSame('2019-09-21 12:35:07.234567', $date->format('Y-m-d H:i:s.u'));
  77. $date = Carbon::today();
  78. $this->assertSame('America/Toronto', $date->tzName);
  79. $this->assertSame('2019-09-21 00:00:00.000000', $date->format('Y-m-d H:i:s.u'));
  80. $date = Carbon::create('tomorrow');
  81. $this->assertSame('America/Toronto', $date->tzName);
  82. $this->assertSame('2019-09-22 00:00:00.000000', $date->format('Y-m-d H:i:s.u'));
  83. $date = Carbon::create(2018, 6, 15, null, null);
  84. $this->assertSame('America/Toronto', $date->tzName);
  85. $this->assertSame('2018-06-15 12:35:00.000000', $date->format('Y-m-d H:i:s.u'));
  86. date_default_timezone_set('UTC');
  87. $date = Carbon::now();
  88. $this->assertSame('UTC', $date->tzName);
  89. $this->assertSame('2019-09-21 16:35:07.234567', $date->format('Y-m-d H:i:s.u'));
  90. $date = Carbon::today();
  91. $this->assertSame('UTC', $date->tzName);
  92. $this->assertSame('2019-09-21 00:00:00.000000', $date->format('Y-m-d H:i:s.u'));
  93. $date = Carbon::create('tomorrow');
  94. $this->assertSame('UTC', $date->tzName);
  95. $this->assertSame('2019-09-22 00:00:00.000000', $date->format('Y-m-d H:i:s.u'));
  96. $date = Carbon::create(2018, 6, 15, null, null);
  97. $this->assertSame('UTC', $date->tzName);
  98. $this->assertSame('2018-06-15 16:35:00.000000', $date->format('Y-m-d H:i:s.u'));
  99. date_default_timezone_set('America/Toronto');
  100. }
  101. public function testParseRelativeWithTestValueSet()
  102. {
  103. $testNow = Carbon::parse('2013-09-01 05:15:05');
  104. $this->wrapWithTestNow(function () {
  105. $this->assertSame('2013-09-01 05:10:05', Carbon::parse('5 minutes ago')->toDateTimeString());
  106. $this->assertSame('2013-08-25 05:15:05', Carbon::parse('1 week ago')->toDateTimeString());
  107. $this->assertSame('2013-09-02 00:00:00', Carbon::parse('tomorrow')->toDateTimeString());
  108. $this->assertSame('2013-09-01 00:00:00', Carbon::parse('today')->toDateTimeString());
  109. $this->assertSame('2013-08-31 00:00:00', Carbon::parse('yesterday')->toDateTimeString());
  110. $this->assertSame('2013-09-02 05:15:05', Carbon::parse('+1 day')->toDateTimeString());
  111. $this->assertSame('2013-08-31 05:15:05', Carbon::parse('-1 day')->toDateTimeString());
  112. $this->assertSame('2013-09-02 00:00:00', Carbon::parse('next monday')->toDateTimeString());
  113. $this->assertSame('2013-09-03 00:00:00', Carbon::parse('next tuesday')->toDateTimeString());
  114. $this->assertSame('2013-09-04 00:00:00', Carbon::parse('next wednesday')->toDateTimeString());
  115. $this->assertSame('2013-09-05 00:00:00', Carbon::parse('next thursday')->toDateTimeString());
  116. $this->assertSame('2013-09-06 00:00:00', Carbon::parse('next friday')->toDateTimeString());
  117. $this->assertSame('2013-09-07 00:00:00', Carbon::parse('next saturday')->toDateTimeString());
  118. $this->assertSame('2013-09-08 00:00:00', Carbon::parse('next sunday')->toDateTimeString());
  119. $this->assertSame('2013-08-26 00:00:00', Carbon::parse('last monday')->toDateTimeString());
  120. $this->assertSame('2013-08-27 00:00:00', Carbon::parse('last tuesday')->toDateTimeString());
  121. $this->assertSame('2013-08-28 00:00:00', Carbon::parse('last wednesday')->toDateTimeString());
  122. $this->assertSame('2013-08-29 00:00:00', Carbon::parse('last thursday')->toDateTimeString());
  123. $this->assertSame('2013-08-30 00:00:00', Carbon::parse('last friday')->toDateTimeString());
  124. $this->assertSame('2013-08-31 00:00:00', Carbon::parse('last saturday')->toDateTimeString());
  125. $this->assertSame('2013-08-25 00:00:00', Carbon::parse('last sunday')->toDateTimeString());
  126. $this->assertSame('2013-09-02 00:00:00', Carbon::parse('this monday')->toDateTimeString());
  127. $this->assertSame('2013-09-03 00:00:00', Carbon::parse('this tuesday')->toDateTimeString());
  128. $this->assertSame('2013-09-04 00:00:00', Carbon::parse('this wednesday')->toDateTimeString());
  129. $this->assertSame('2013-09-05 00:00:00', Carbon::parse('this thursday')->toDateTimeString());
  130. $this->assertSame('2013-09-06 00:00:00', Carbon::parse('this friday')->toDateTimeString());
  131. $this->assertSame('2013-09-07 00:00:00', Carbon::parse('this saturday')->toDateTimeString());
  132. $this->assertSame('2013-09-01 00:00:00', Carbon::parse('this sunday')->toDateTimeString());
  133. $this->assertSame('2013-10-01 05:15:05', Carbon::parse('first day of next month')->toDateTimeString());
  134. $this->assertSame('2013-09-30 05:15:05', Carbon::parse('last day of this month')->toDateTimeString());
  135. }, $testNow);
  136. }
  137. public function testHasRelativeKeywords()
  138. {
  139. $this->assertFalse(Carbon::hasRelativeKeywords('sunday 2015-02-23'));
  140. $this->assertTrue(Carbon::hasRelativeKeywords('today +2014 days'));
  141. $this->assertTrue(Carbon::hasRelativeKeywords('next sunday -3600 seconds'));
  142. $this->assertTrue(Carbon::hasRelativeKeywords('last day of this month'));
  143. $this->assertFalse(Carbon::hasRelativeKeywords('last day of december 2015'));
  144. $this->assertTrue(Carbon::hasRelativeKeywords('first sunday of next month'));
  145. $this->assertFalse(Carbon::hasRelativeKeywords('first sunday of January 2017'));
  146. }
  147. public function testParseRelativeWithMinusSignsInDate()
  148. {
  149. $testNow = Carbon::parse('2013-09-01 05:15:05');
  150. $this->wrapWithTestNow(function () {
  151. $this->assertSame('2000-01-03 00:00:00', Carbon::parse('2000-1-3')->toDateTimeString());
  152. $this->assertSame('2000-10-10 00:00:00', Carbon::parse('2000-10-10')->toDateTimeString());
  153. }, $testNow);
  154. $this->assertSame('2000-01-03 00:00:00', Carbon::parse('2000-1-3')->toDateTimeString());
  155. $this->assertSame('2000-10-10 00:00:00', Carbon::parse('2000-10-10')->toDateTimeString());
  156. }
  157. public function testTimeZoneWithTestValueSet()
  158. {
  159. $testNow = Carbon::parse('2013-07-01 12:00:00', 'America/New_York');
  160. $this->wrapWithTestNow(function () {
  161. $this->assertSame('2013-07-01T12:00:00-04:00', Carbon::parse('now')->toIso8601String());
  162. $this->assertSame('2013-07-01T11:00:00-05:00', Carbon::parse('now', 'America/Mexico_City')->toIso8601String());
  163. $this->assertSame('2013-07-01T09:00:00-07:00', Carbon::parse('now', 'America/Vancouver')->toIso8601String());
  164. }, $testNow);
  165. }
  166. public function testSetTestNowAndTimezoneWithBadTimezone(): void
  167. {
  168. $this->expectExceptionObject(new InvalidArgumentException(
  169. "Timezone ID '-05:00' is invalid, did you mean 'America/Chicago'?\n".
  170. "It must be one of the IDs from DateTimeZone::listIdentifiers(),\n".
  171. 'For the record, hours/minutes offset are relevant only for a particular moment, but not as a default timezone.'
  172. ));
  173. Carbon::setTestNowAndTimezone(Carbon::parse('2018-05-06T12:00:00-05:00'));
  174. }
  175. public function testSetTestNowAndTimezoneWithNull(): void
  176. {
  177. Carbon::setTestNowAndTimezone();
  178. Carbon::setTestNowAndTimezone(); // replay-able with no effect
  179. foreach ([null, 'UTC', 'Asia/Tokyo'] as $originalTimezone) {
  180. $originalTimezone
  181. ? date_default_timezone_set($originalTimezone)
  182. : ($originalTimezone = date_default_timezone_get());
  183. Carbon::setTestNowAndTimezone('2013-09-01 05:10:15 America/Vancouver', 'America/Vancouver');
  184. $this->assertSame('America/Vancouver', date_default_timezone_get());
  185. $this->assertSame('America/Vancouver', Carbon::now()->tzName);
  186. Carbon::setTestNowAndTimezone();
  187. $this->assertFalse(Carbon::hasTestNow());
  188. $this->assertSame($originalTimezone, date_default_timezone_get());
  189. $this->assertSame($originalTimezone, Carbon::now()->tzName);
  190. }
  191. }
  192. public function testCreateFromPartialFormat()
  193. {
  194. Carbon::setTestNowAndTimezone('2013-09-01 05:10:15 America/Vancouver', 'America/Vancouver');
  195. // Simple partial time.
  196. $this->assertSame('2018-05-06T05:10:15-07:00', Carbon::createFromFormat('Y-m-d', '2018-05-06')->toIso8601String());
  197. $this->assertSame('2013-09-01T10:20:30-07:00', Carbon::createFromFormat('H:i:s', '10:20:30')->toIso8601String());
  198. // Custom timezone.
  199. $this->assertSame('2013-09-01T10:20:00+03:00', Carbon::createFromFormat('H:i e', '10:20 Europe/Kiev')->toIso8601String());
  200. $this->assertSame('2013-09-01T10:20:00+01:00', Carbon::createFromFormat('H:i', '10:20', 'Europe/London')->toIso8601String());
  201. $this->assertSame('2013-09-01T11:30:00+07:00', Carbon::createFromFormat('H:i:s e', '11:30:00+07:00')->toIso8601String());
  202. $this->assertSame('2013-09-01T11:30:00+05:00', Carbon::createFromFormat('H:i:s', '11:30:00', '+05:00')->toIso8601String());
  203. // Escaped timezone.
  204. $this->assertSame('2013-09-01T05:10:15-07:00', Carbon::createFromFormat('\e', 'e')->toIso8601String());
  205. // Weird format, naive modify would fail here.
  206. $this->assertSame('2005-08-09T05:10:15-07:00', Carbon::createFromFormat('l jS \of F Y', 'Tuesday 9th of August 2005')->toIso8601String());
  207. $this->assertSame('2013-09-01T00:12:13-07:00', Carbon::createFromFormat('i:s', '12:13')->toIso8601String());
  208. $this->assertSame('2018-09-05T05:10:15-07:00', Carbon::createFromFormat('Y/d', '2018/5')->toIso8601String());
  209. // Resetting to epoch.
  210. $this->assertSame('2018-05-06T00:00:00-07:00', Carbon::createFromFormat('!Y-m-d', '2018-05-06')->toIso8601String());
  211. $this->assertSame('1970-01-01T10:20:30-08:00', Carbon::createFromFormat('Y-m-d! H:i:s', '2018-05-06 10:20:30')->toIso8601String());
  212. $this->assertSame('2018-05-06T00:00:00-07:00', Carbon::createFromFormat('Y-m-d|', '2018-05-06')->toIso8601String());
  213. $this->assertSame('1970-01-01T10:20:30-08:00', Carbon::createFromFormat('|H:i:s', '10:20:30')->toIso8601String());
  214. $kyiv = $this->firstValidTimezoneAmong(['Europe/Kyiv', 'Europe/Kiev'])->getName();
  215. // Resetting to epoch (timezone fun).
  216. $this->assertSame('1970-01-01T00:00:00-08:00', Carbon::createFromFormat('|', '')->toIso8601String());
  217. $this->assertSame('1970-01-01T00:00:00+03:00', Carbon::createFromFormat('e|', $kyiv)->toIso8601String());
  218. $this->assertSame('1970-01-01T00:00:00+01:00', Carbon::createFromFormat('|', '', 'Europe/London')->toIso8601String());
  219. $this->assertSame('1970-01-01T00:00:00-08:00', Carbon::createFromFormat('!', '')->toIso8601String());
  220. $this->assertSame('1970-01-01T00:00:00+03:00', Carbon::createFromFormat('!e', $kyiv)->toIso8601String());
  221. $this->assertSame('1970-01-01T00:00:00+01:00', Carbon::createFromFormat('!', '', 'Europe/London')->toIso8601String());
  222. $this->assertSame('1970-01-01T00:00:00-08:00', Carbon::createFromFormat('e!', $kyiv)->toIso8601String());
  223. // Escaped epoch resets.
  224. $this->assertSame('2013-09-01T05:10:15-07:00', Carbon::createFromFormat('\|', '|')->toIso8601String());
  225. $this->assertSame('2013-09-01T05:10:15-07:00', Carbon::createFromFormat('\!', '!')->toIso8601String());
  226. $this->assertSame('2013-09-01T05:10:15+03:00', Carbon::createFromFormat('e \!', $kyiv.' !')->toIso8601String());
  227. }
  228. public function testCreateFromPartialFormatWithMicroseconds()
  229. {
  230. Carbon::setTestNowAndTimezone(Carbon::parse('2013-09-01 05:10:15.123456', 'America/Vancouver'));
  231. $this->assertSame('2018-05-06 05:10:15.123456', Carbon::createFromFormat('Y-m-d', '2018-05-06')->format('Y-m-d H:i:s.u'));
  232. $this->assertSame('2013-09-01 10:20:30.654321', Carbon::createFromFormat('H:i:s.u', '10:20:30.654321')->format('Y-m-d H:i:s.u'));
  233. }
  234. public function testCreateFromDateTimeInterface()
  235. {
  236. Carbon::setTestNowAndTimezone(date_create('2013-09-01 05:10:15.123456', new DateTimeZone('America/Vancouver')));
  237. $this->assertSame('2018-05-06 05:10:15.123456', Carbon::createFromFormat('Y-m-d', '2018-05-06')->format('Y-m-d H:i:s.u'));
  238. $this->assertSame('2013-09-01 10:20:30.654321', Carbon::createFromFormat('H:i:s.u', '10:20:30.654321')->format('Y-m-d H:i:s.u'));
  239. }
  240. public function testSetTestNow()
  241. {
  242. Carbon::setTestNow(null);
  243. $n1 = Carbon::now();
  244. $n2 = Carbon::now();
  245. $this->assertTrue($n2 > $n1);
  246. Carbon::setTestNow('2013-09-01 10:20:30.654321');
  247. $n1 = Carbon::now();
  248. $n2 = Carbon::now();
  249. $this->assertFalse($n2 > $n1);
  250. Carbon::setTestNow(false);
  251. $n1 = Carbon::now();
  252. $n2 = Carbon::now();
  253. $this->assertTrue($n2 > $n1);
  254. }
  255. public function testWithTestNow()
  256. {
  257. $self = $this;
  258. $testNow = '2020-09-16 10:20:00';
  259. $object = new stdClass();
  260. $result = Carbon::withTestNow($testNow, static function () use ($self, $testNow, $object) {
  261. $currentTime = Carbon::now();
  262. $self->assertSame($testNow, $currentTime->format('Y-m-d H:i:s'));
  263. return $object;
  264. });
  265. $this->assertSame($object, $result);
  266. $currentTime = Carbon::now();
  267. $this->assertNotSame($testNow, $currentTime->format('Y-m-d H:i:s'));
  268. }
  269. public function testWithTestNowWithException()
  270. {
  271. $testNow = '2020-09-16 10:20:00';
  272. try {
  273. Carbon::withTestNow($testNow, static function () {
  274. throw new Exception();
  275. });
  276. } catch (Exception $e) {
  277. // ignore
  278. }
  279. $currentTime = Carbon::now();
  280. $this->assertNotSame($testNow, $currentTime->format('Y-m-d H:i:s'));
  281. }
  282. public function testWithModifyReturningDateTime()
  283. {
  284. Carbon::setTestNowAndTimezone(new class('2000-01-01 00:00 UTC') extends Carbon {
  285. public function modify($modify)
  286. {
  287. return $this->toDateTimeImmutable()->modify($modify);
  288. }
  289. });
  290. $currentTime = new Carbon('tomorrow');
  291. $this->assertSame('2000-01-02 00:00:00 UTC', $currentTime->format('Y-m-d H:i:s e'));
  292. }
  293. }