ModifyTest.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  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 Closure;
  14. use DateMalformedStringException;
  15. use InvalidArgumentException;
  16. use Tests\AbstractTestCase;
  17. class ModifyTest extends AbstractTestCase
  18. {
  19. public function testSimpleModify()
  20. {
  21. $a = new Carbon('2014-03-30 00:00:00');
  22. $b = $a->copy();
  23. $b->addHours(24);
  24. $this->assertSame(24, $a->diffInHours($b));
  25. }
  26. public function testTimezoneModify()
  27. {
  28. // For daylight saving time reason 2014-03-30 0h59 is immediately followed by 2h00
  29. $a = new Carbon('2014-03-30 00:00:00', 'Europe/London');
  30. $b = $a->copy();
  31. $b->addHours(24);
  32. $this->assertSame(24, $a->diffInHours($b));
  33. $this->assertSame(24, $a->diffInHours($b, false));
  34. $this->assertSame(24, $b->diffInHours($a));
  35. $this->assertSame(-24, $b->diffInHours($a, false));
  36. $this->assertSame(-23, $b->diffInRealHours($a, false));
  37. $this->assertSame(-23 * 60, $b->diffInRealMinutes($a, false));
  38. $this->assertSame(-23 * 60 * 60, $b->diffInRealSeconds($a, false));
  39. $this->assertSame(-24 * 60 * 60 * 1000, $b->diffInMilliseconds($a, false));
  40. $this->assertSame(-23 * 60 * 60 * 1000, $b->diffInRealMilliseconds($a, false));
  41. $this->assertSame(-23 * 60 * 60 * 1000000, $b->diffInRealMicroseconds($a, false));
  42. $this->assertSame(-24 * 60 * 60 * 1000000, $b->diffInMicroseconds($a, false));
  43. $a = new Carbon('2014-03-30 00:00:00', 'Europe/London');
  44. $b = $a->copy();
  45. $b->addRealHours(24);
  46. $this->assertSame(-24, $b->diffInRealHours($a, false));
  47. $this->assertSame(-24 * 60, $b->diffInRealMinutes($a, false));
  48. $this->assertSame(-24 * 60 * 60, $b->diffInRealSeconds($a, false));
  49. $this->assertSame(-25 * 60 * 60 * 1000, $b->diffInMilliseconds($a, false));
  50. $this->assertSame(-24 * 60 * 60 * 1000, $b->diffInRealMilliseconds($a, false));
  51. $this->assertSame(-24 * 60 * 60 * 1000000, $b->diffInRealMicroseconds($a, false));
  52. $this->assertSame(-25 * 60 * 60 * 1000000, $b->diffInMicroseconds($a, false));
  53. $this->assertSame(-25, $b->diffInHours($a, false));
  54. $b->subRealHours(24);
  55. $this->assertSame(0, $b->diffInRealHours($a, false));
  56. $this->assertSame(0, $b->diffInHours($a, false));
  57. $a = new Carbon('2014-03-30 00:59:00', 'Europe/London');
  58. $a->addRealHour();
  59. $this->assertSame('02:59', $a->format('H:i'));
  60. $a->subRealHour();
  61. $this->assertSame('00:59', $a->format('H:i'));
  62. $a = new Carbon('2014-03-30 00:59:00', 'Europe/London');
  63. $a->addRealMinutes(2);
  64. $this->assertSame('02:01', $a->format('H:i'));
  65. $a->subRealMinutes(2);
  66. $this->assertSame('00:59', $a->format('H:i'));
  67. $a = new Carbon('2014-03-30 00:59:30', 'Europe/London');
  68. $a->addRealMinute();
  69. $this->assertSame('02:00:30', $a->format('H:i:s'));
  70. $a->subRealMinute();
  71. $this->assertSame('00:59:30', $a->format('H:i:s'));
  72. $a = new Carbon('2014-03-30 00:59:30', 'Europe/London');
  73. $a->addRealSeconds(40);
  74. $this->assertSame('02:00:10', $a->format('H:i:s'));
  75. $a->subRealSeconds(40);
  76. $this->assertSame('00:59:30', $a->format('H:i:s'));
  77. $a = new Carbon('2014-03-30 00:59:59', 'Europe/London');
  78. $a->addRealSecond();
  79. $this->assertSame('02:00:00', $a->format('H:i:s'));
  80. $a->subRealSecond();
  81. $this->assertSame('00:59:59', $a->format('H:i:s'));
  82. $a = new Carbon('2014-03-30 00:59:59.990000', 'Europe/London');
  83. $a->addRealMilliseconds(20);
  84. $this->assertSame('02:00:00.010000', $a->format('H:i:s.u'));
  85. $a->subRealMilliseconds(20);
  86. $this->assertSame('00:59:59.990000', $a->format('H:i:s.u'));
  87. $a = new Carbon('2014-03-30 00:59:59.999990', 'Europe/London');
  88. $a->addRealMicroseconds(20);
  89. $this->assertSame('02:00:00.000010', $a->format('H:i:s.u'));
  90. $a->subRealMicroseconds(20);
  91. $this->assertSame('00:59:59.999990', $a->format('H:i:s.u'));
  92. $a = new Carbon('2014-03-30 00:59:59.999999', 'Europe/London');
  93. $a->addRealMicrosecond();
  94. $this->assertSame('02:00:00.000000', $a->format('H:i:s.u'));
  95. $a->subRealMicrosecond();
  96. $this->assertSame('00:59:59.999999', $a->format('H:i:s.u'));
  97. $a = new Carbon('2014-03-30 00:00:00', 'Europe/London');
  98. $b = $a->copy();
  99. $b->addRealDay();
  100. $this->assertSame(-24, $b->diffInRealHours($a, false));
  101. $this->assertSame(-24 * 60, $b->diffInRealMinutes($a, false));
  102. $this->assertSame(-24 * 60 * 60, $b->diffInRealSeconds($a, false));
  103. $this->assertSame(-24 * 60 * 60 * 1000, $b->diffInRealMilliseconds($a, false));
  104. $this->assertSame(-24 * 60 * 60 * 1000000, $b->diffInRealMicroseconds($a, false));
  105. $this->assertSame(-25 * 60 * 60 * 1000000, $b->diffInMicroseconds($a, false));
  106. $this->assertSame(-25, $b->diffInHours($a, false));
  107. $a = new Carbon('2014-03-30 00:00:00', 'Europe/London');
  108. $b = $a->copy();
  109. $b->addRealWeeks(1 / 7);
  110. $this->assertSame(-24, $b->diffInRealHours($a, false));
  111. $this->assertSame(-24 * 60, $b->diffInRealMinutes($a, false));
  112. $this->assertSame(-24 * 60 * 60, $b->diffInRealSeconds($a, false));
  113. $this->assertSame(-24 * 60 * 60 * 1000, $b->diffInRealMilliseconds($a, false));
  114. $this->assertSame(-24 * 60 * 60 * 1000000, $b->diffInRealMicroseconds($a, false));
  115. $this->assertSame(-25 * 60 * 60 * 1000000, $b->diffInMicroseconds($a, false));
  116. $this->assertSame(-25, $b->diffInHours($a, false));
  117. $a = new Carbon('2014-03-30 00:00:00', 'Europe/London');
  118. $b = $a->copy();
  119. $b->addRealMonths(1 / 30);
  120. $this->assertSame(-24, $b->diffInRealHours($a, false));
  121. $this->assertSame(-24 * 60, $b->diffInRealMinutes($a, false));
  122. $this->assertSame(-24 * 60 * 60, $b->diffInRealSeconds($a, false));
  123. $this->assertSame(-24 * 60 * 60 * 1000, $b->diffInRealMilliseconds($a, false));
  124. $this->assertSame(-24 * 60 * 60 * 1000000, $b->diffInRealMicroseconds($a, false));
  125. $this->assertSame(-25 * 60 * 60 * 1000000, $b->diffInMicroseconds($a, false));
  126. $this->assertSame(-25, $b->diffInHours($a, false));
  127. $a = new Carbon('2014-03-30 00:00:00', 'Europe/London');
  128. $b = $a->copy();
  129. $b->addRealQuarters(1 / 90);
  130. $this->assertSame(-24, $b->diffInRealHours($a, false));
  131. $this->assertSame(-24 * 60, $b->diffInRealMinutes($a, false));
  132. $this->assertSame(-24 * 60 * 60, $b->diffInRealSeconds($a, false));
  133. $this->assertSame(-24 * 60 * 60 * 1000, $b->diffInRealMilliseconds($a, false));
  134. $this->assertSame(-24 * 60 * 60 * 1000000, $b->diffInRealMicroseconds($a, false));
  135. $this->assertSame(-25 * 60 * 60 * 1000000, $b->diffInMicroseconds($a, false));
  136. $this->assertSame(-25, $b->diffInHours($a, false));
  137. $a = new Carbon('2014-03-30 00:00:00', 'Europe/London');
  138. $b = $a->copy();
  139. $b->addRealYears(1 / 365);
  140. $this->assertSame(-24, $b->diffInRealHours($a, false));
  141. $this->assertSame(-24 * 60, $b->diffInRealMinutes($a, false));
  142. $this->assertSame(-24 * 60 * 60, $b->diffInRealSeconds($a, false));
  143. $this->assertSame(-24 * 60 * 60 * 1000, $b->diffInRealMilliseconds($a, false));
  144. $this->assertSame(-24 * 60 * 60 * 1000000, $b->diffInRealMicroseconds($a, false));
  145. $this->assertSame(-25 * 60 * 60 * 1000000, $b->diffInMicroseconds($a, false));
  146. $this->assertSame(-25, $b->diffInHours($a, false));
  147. $a = new Carbon('2014-03-30 00:00:00', 'Europe/London');
  148. $b = $a->copy();
  149. $b->addRealDecades(1 / 3650);
  150. $this->assertSame(-24, $b->diffInRealHours($a, false));
  151. $this->assertSame(-24 * 60, $b->diffInRealMinutes($a, false));
  152. $this->assertSame(-24 * 60 * 60, $b->diffInRealSeconds($a, false));
  153. $this->assertSame(-24 * 60 * 60 * 1000, $b->diffInRealMilliseconds($a, false));
  154. $this->assertSame(-24 * 60 * 60 * 1000000, $b->diffInRealMicroseconds($a, false));
  155. $this->assertSame(-25 * 60 * 60 * 1000000, $b->diffInMicroseconds($a, false));
  156. $this->assertSame(-25, $b->diffInHours($a, false));
  157. $a = new Carbon('2014-03-30 00:00:00', 'Europe/London');
  158. $b = $a->copy();
  159. $b->addRealCenturies(1 / 36500);
  160. $this->assertSame(-24, $b->diffInRealHours($a, false));
  161. $this->assertSame(-24 * 60, $b->diffInRealMinutes($a, false));
  162. $this->assertSame(-24 * 60 * 60, $b->diffInRealSeconds($a, false));
  163. $this->assertSame(-24 * 60 * 60 * 1000, $b->diffInRealMilliseconds($a, false));
  164. $this->assertSame(-24 * 60 * 60 * 1000000, $b->diffInRealMicroseconds($a, false));
  165. $this->assertSame(-25 * 60 * 60 * 1000000, $b->diffInMicroseconds($a, false));
  166. $this->assertSame(-25, $b->diffInHours($a, false));
  167. $a = new Carbon('2014-03-30 00:00:00', 'Europe/London');
  168. $b = $a->copy();
  169. $b->addRealMillennia(1 / 365000);
  170. $this->assertSame(-24, $b->diffInRealHours($a, false));
  171. $this->assertSame(-24 * 60, $b->diffInRealMinutes($a, false));
  172. $this->assertSame(-24 * 60 * 60, $b->diffInRealSeconds($a, false));
  173. $this->assertSame(-24 * 60 * 60 * 1000, $b->diffInRealMilliseconds($a, false));
  174. $this->assertSame(-24 * 60 * 60 * 1000000, $b->diffInRealMicroseconds($a, false));
  175. $this->assertSame(-25 * 60 * 60 * 1000000, $b->diffInMicroseconds($a, false));
  176. $this->assertSame(-25, $b->diffInHours($a, false));
  177. }
  178. public function testAddRealUnitException()
  179. {
  180. $this->expectExceptionObject(new InvalidArgumentException(
  181. 'Invalid unit for real timestamp add/sub: \'foobar\''
  182. ));
  183. (new Carbon('2014-03-30 00:00:00'))->addRealUnit('foobar');
  184. }
  185. public function testAddRealMicrosecondWithLowFloatPrecision()
  186. {
  187. $precision = ini_set('precision', '9');
  188. $a = new Carbon('2014-03-30 00:59:59.999999', 'Europe/London');
  189. $a->addRealMicrosecond();
  190. $this->assertSame('02:00:00.000000', $a->format('H:i:s.u'));
  191. ini_set('precision', $precision);
  192. }
  193. public function testNextAndPrevious()
  194. {
  195. Carbon::setTestNow('2019-06-02 13:27:09.816752');
  196. $this->assertSame('2019-06-02 14:00:00', Carbon::now()->next('2pm')->format('Y-m-d H:i:s'));
  197. $this->assertSame('2019-06-01 14:00:00', Carbon::now()->previous('2pm')->format('Y-m-d H:i:s'));
  198. $this->assertSame('2019-06-02 14:00:00', Carbon::now()->next('14h')->format('Y-m-d H:i:s'));
  199. $this->assertSame('2019-06-01 14:00:00', Carbon::now()->previous('14h')->format('Y-m-d H:i:s'));
  200. $this->assertSame('2019-06-03 09:00:00', Carbon::now()->next('9am')->format('Y-m-d H:i:s'));
  201. $this->assertSame('2019-06-02 09:00:00', Carbon::now()->previous('9am')->format('Y-m-d H:i:s'));
  202. $this->assertSame('2019-06-02 14:00:00', Carbon::parse('next 2pm')->format('Y-m-d H:i:s'));
  203. $this->assertSame('2019-06-01 14:00:00', Carbon::parse('previous 2pm')->format('Y-m-d H:i:s'));
  204. $this->assertSame('2019-06-02 14:00:00', Carbon::parse('next 14h')->format('Y-m-d H:i:s'));
  205. $this->assertSame('2019-06-01 14:00:00', Carbon::parse('previous 14h')->format('Y-m-d H:i:s'));
  206. $this->assertSame('2019-06-03 09:00:00', Carbon::parse('next 9am')->format('Y-m-d H:i:s'));
  207. $this->assertSame('2019-06-02 09:00:00', Carbon::parse('previous 9am')->format('Y-m-d H:i:s'));
  208. $this->assertSame(
  209. '2019-06-04 00:00:00',
  210. Carbon::parse('after tomorrow')->format('Y-m-d H:i:s')
  211. );
  212. $this->assertSame(
  213. '2000-01-27 00:00:00',
  214. Carbon::parse('2000-01-25')->change('after tomorrow')->format('Y-m-d H:i:s')
  215. );
  216. $this->assertSame(
  217. '2019-05-31 00:00:00',
  218. Carbon::parse('before yesterday')->format('Y-m-d H:i:s')
  219. );
  220. $this->assertSame(
  221. '2000-01-23 00:00:00',
  222. Carbon::parse('2000-01-25')->change('before yesterday')->format('Y-m-d H:i:s')
  223. );
  224. }
  225. public function testInvalidModifier(): void
  226. {
  227. $this->checkInvalid('invalid', static function () {
  228. return @Carbon::parse('2000-01-25')->change('invalid');
  229. });
  230. $this->checkInvalid('next invalid', static function () {
  231. return @Carbon::now()->next('invalid');
  232. });
  233. $this->checkInvalid('last invalid', static function () {
  234. return @Carbon::now()->previous('invalid');
  235. });
  236. }
  237. private function checkInvalid(string $message, Closure $callback): void
  238. {
  239. if (PHP_VERSION < 8.3) {
  240. $this->assertFalse($callback());
  241. return;
  242. }
  243. try {
  244. $callback();
  245. } catch (DateMalformedStringException $exception) {
  246. $this->assertStringContainsString("Failed to parse time string ($message)", $exception->getMessage());
  247. return;
  248. }
  249. $this->fail('This should throw a DateMalformedStringException in PHP 8.3');
  250. }
  251. public function testImplicitCast(): void
  252. {
  253. $this->assertSame(
  254. '2000-01-25 06:00:00.000000',
  255. Carbon::parse('2000-01-25')->addRealHours('6')->format('Y-m-d H:i:s.u')
  256. );
  257. $this->assertSame(
  258. '2000-01-25 07:00:00.000000',
  259. Carbon::parse('2000-01-25')->addRealUnit('hour', '7')->format('Y-m-d H:i:s.u')
  260. );
  261. $this->assertSame(
  262. '2000-01-25 00:08:00.000000',
  263. Carbon::parse('2000-01-25')->addRealUnit('minute', '8')->format('Y-m-d H:i:s.u')
  264. );
  265. $this->assertSame(
  266. '2000-01-25 00:00:00.007000',
  267. Carbon::parse('2000-01-25')->addRealUnit('millisecond', '7')->format('Y-m-d H:i:s.u')
  268. );
  269. }
  270. }