1
0

DateTimeHelperTest.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  1. <?php
  2. namespace fphammerle\helpers\tests;
  3. use \DateInterval as DI;
  4. use \DatePeriod as DP;
  5. use \DateTime as DT;
  6. use \fphammerle\helpers\DateTimeHelper;
  7. class DateTimeHelperTest extends \PHPUnit_Framework_TestCase
  8. {
  9. public function timestampToDateTimeProvider()
  10. {
  11. return [
  12. [null, null],
  13. [0, new DT('1970-01-01 00:00:00', new \DateTimeZone('UTC'))],
  14. [0, new DT('1970-01-01 01:00:00', new \DateTimeZone('Europe/Vienna'))],
  15. [1234567890, new DT('2009-02-13 23:31:30', new \DateTimeZone('UTC'))],
  16. [1234567890, new DT('2009-02-14 00:31:30', new \DateTimeZone('Europe/Vienna'))],
  17. [-3600, new DT('1970-01-01 00:00:00', new \DateTimeZone('Europe/Vienna'))],
  18. ];
  19. }
  20. /**
  21. * @dataProvider timestampToDateTimeProvider
  22. */
  23. public function testTimestampToDateTime($timestamp, $expected_datetime)
  24. {
  25. $generated_datetime = DateTimeHelper::timestampToDateTime($timestamp);
  26. $this->assertEquals($expected_datetime, $generated_datetime);
  27. }
  28. public function timestampToDateTimeDefaultTimezoneProvider()
  29. {
  30. return [
  31. ['UTC', 100],
  32. ['Europe/Vienna', 0],
  33. ['Europe/Vienna', -100],
  34. ['Europe/Vienna', 100],
  35. ['Europe/London', 3600],
  36. ['US/Pacific', 3600],
  37. ];
  38. }
  39. /**
  40. * @dataProvider timestampToDateTimeDefaultTimezoneProvider
  41. */
  42. public function testTimestampToDateTimeDefaultTimezone($timezone, $timestamp)
  43. {
  44. date_default_timezone_set($timezone);
  45. $generated_datetime = DateTimeHelper::timestampToDateTime($timestamp);
  46. $this->assertSame($timestamp, $generated_datetime->getTimestamp());
  47. }
  48. public function parseProvider()
  49. {
  50. return [
  51. // null
  52. [null, 'UTC', null],
  53. [null, 'US/Pacific', null],
  54. // month without timezone
  55. ['2016-08', 'UTC', new DP(new DT('2016-08-01T00:00:00Z'), new DI('P1M'), 0)],
  56. ['2016-08', 'UTC', new DP(new DT('2016-08-01T00:00:00Z'), new DI('P1M'), 0)],
  57. ['2016-08', 'Europe/Vienna', new DP(new DT('2016-08-01T00:00:00+02:00'), new DI('P1M'), 0)],
  58. ['2016-01', 'US/Pacific', new DP(new DT('2016-01-01T00:00:00-08:00'), new DI('P1M'), 0)],
  59. // month with timezone
  60. ['2016-08Z', 'US/Pacific', new DP(new DT('2016-08-01T00:00:00Z'), new DI('P1M'), 0)],
  61. ['2016-08Z', 'Europe/Vienna', new DP(new DT('2016-08-01T00:00:00Z'), new DI('P1M'), 0)],
  62. ['2016-01+00:00', 'Europe/Vienna', new DP(new DT('2016-01-01T00:00:00Z'), new DI('P1M'), 0)],
  63. ['2016-01+02:00', 'US/Pacific', new DP(new DT('2016-01-01T00:00:00+02:00'), new DI('P1M'), 0)],
  64. ['2016-01 +02:00', 'US/Pacific', new DP(new DT('2016-01-01T00:00:00+02:00'), new DI('P1M'), 0)],
  65. ['2016-01 -08:00', 'UTC', new DP(new DT('2016-01-01T00:00:00-08:00'), new DI('P1M'), 0)],
  66. // date without timezone
  67. ['2016-08-02', 'UTC', new DP(new DT('2016-08-02T00:00:00Z'), new DI('P1D'), 0)],
  68. ['2016-08-02', 'UTC', new DP(new DT('2016-08-02T00:00:00Z'), new DI('P1D'), 0)],
  69. ['2016-08-02', 'Europe/Vienna', new DP(new DT('2016-08-02T00:00:00+02:00'), new DI('P1D'), 0)],
  70. ['2016-01-02', 'US/Pacific', new DP(new DT('2016-01-02T00:00:00-08:00'), new DI('P1D'), 0)],
  71. // date with timezone
  72. ['2016-08-02Z', 'US/Pacific', new DP(new DT('2016-08-02T00:00:00Z'), new DI('P1D'), 0)],
  73. ['2016-08-02Z', 'Europe/Vienna', new DP(new DT('2016-08-02T00:00:00Z'), new DI('P1D'), 0)],
  74. ['2016-01-02+00:00', 'Europe/Vienna', new DP(new DT('2016-01-02T00:00:00Z'), new DI('P1D'), 0)],
  75. ['2016-01-02+02:00', 'US/Pacific', new DP(new DT('2016-01-02T00:00:00+02:00'), new DI('P1D'), 0)],
  76. ['2016-01-02-08:00', 'UTC', new DP(new DT('2016-01-02T00:00:00-08:00'), new DI('P1D'), 0)],
  77. // minute without timezone
  78. ['2016-08-02 15:52', 'UTC', new DP(new DT('2016-08-02T15:52:00Z'), new DI('PT1M'), 0)],
  79. ['2016-08-02T15:52', 'UTC', new DP(new DT('2016-08-02T15:52:00Z'), new DI('PT1M'), 0)],
  80. ['2016-08-02T15:52', 'Europe/Vienna', new DP(new DT('2016-08-02T15:52:00+02:00'), new DI('PT1M'), 0)],
  81. ['2016-01-02T15:52', 'US/Pacific', new DP(new DT('2016-01-02T15:52:00-08:00'), new DI('PT1M'), 0)],
  82. // minute with timezone
  83. ['2016-08-02 15:52Z', 'US/Pacific', new DP(new DT('2016-08-02T15:52:00Z'), new DI('PT1M'), 0)],
  84. ['2016-08-02T15:52Z', 'Europe/Vienna', new DP(new DT('2016-08-02T15:52:00Z'), new DI('PT1M'), 0)],
  85. ['2016-01-02T15:52+00:00', 'Europe/Vienna', new DP(new DT('2016-01-02T15:52:00Z'), new DI('PT1M'), 0)],
  86. ['2016-01-02T15:52+02:00', 'US/Pacific', new DP(new DT('2016-01-02T15:52:00+02:00'), new DI('PT1M'), 0)],
  87. ['2016-01-02T15:52-08:00', 'UTC', new DP(new DT('2016-01-02T15:52:00-08:00'), new DI('PT1M'), 0)],
  88. // second without timezone
  89. ['2016-08-02 15:52:13', 'UTC', new DP(new DT('2016-08-02T15:52:13Z'), new DI('PT1S'), 0)],
  90. ['2016-08-02T15:52:13', 'UTC', new DP(new DT('2016-08-02T15:52:13Z'), new DI('PT1S'), 0)],
  91. ['2016-08-02T15:52:13', 'Europe/Vienna', new DP(new DT('2016-08-02T15:52:13+02:00'), new DI('PT1S'), 0)],
  92. ['2016-01-02T15:52:00', 'US/Pacific', new DP(new DT('2016-01-02T15:52:00-08:00'), new DI('PT1S'), 0)],
  93. // second with timezone
  94. ['2016-08-02 15:52:13Z', 'US/Pacific', new DP(new DT('2016-08-02T15:52:13Z'), new DI('PT1S'), 0)],
  95. ['2016-08-02T15:52:13Z', 'Europe/Vienna', new DP(new DT('2016-08-02T15:52:13Z'), new DI('PT1S'), 0)],
  96. ['2016-01-02T15:52:13+00:00', 'Europe/Vienna', new DP(new DT('2016-01-02T15:52:13Z'), new DI('PT1S'), 0)],
  97. ['2016-01-02T15:52:13+02:00', 'US/Pacific', new DP(new DT('2016-01-02T15:52:13+02:00'), new DI('PT1S'), 0)],
  98. ['2016-01-02T15:52:13-08:00', 'UTC', new DP(new DT('2016-01-02T15:52:13-08:00'), new DI('PT1S'), 0)],
  99. ];
  100. }
  101. /**
  102. * @dataProvider parseProvider
  103. */
  104. public function testParse($text, $timezone, $expected)
  105. {
  106. date_default_timezone_set($timezone);
  107. $this->assertEquals($expected, DateTimeHelper::parse($text));
  108. }
  109. public function parseInvalidArgumentProvider()
  110. {
  111. return [
  112. [' '],
  113. [''],
  114. ['2016--12'],
  115. ['2016-10-12 08:20#01'],
  116. [1],
  117. [false],
  118. ];
  119. }
  120. /**
  121. * @dataProvider parseInvalidArgumentProvider
  122. * @expectedException \InvalidArgumentException
  123. */
  124. public function testParseInvalidArgument($text)
  125. {
  126. DateTimeHelper::parse($text);
  127. }
  128. public function parseGetStartProvider()
  129. {
  130. return [
  131. [null, 'UTC', null],
  132. [null, 'US/Pacific', null],
  133. ['2016-08-02', 'UTC', new DT('2016-08-02T00:00:00Z')],
  134. ['2016-08-02', 'Europe/Vienna', new DT('2016-08-02T00:00:00+02:00')],
  135. ['2016-08-02', 'Europe/Vienna', new DT('2016-08-01T22:00:00Z')],
  136. ['2016-08-02 15:52:13', 'UTC', new DT('2016-08-02T15:52:13Z')],
  137. ['2016-08-02 15:52:13', 'Europe/Vienna', new DT('2016-08-02T15:52:13+02:00')],
  138. ['2016-08-02 15:52:13', 'Europe/Vienna', new DT('2016-08-02T13:52:13Z')],
  139. ['2016-08-02T15:52:13', 'US/Pacific', new DT('2016-08-02T15:52:13-07:00')],
  140. ];
  141. }
  142. /**
  143. * @dataProvider parseGetStartProvider
  144. */
  145. public function testParseGetStart($text, $timezone, $expected)
  146. {
  147. date_default_timezone_set($timezone);
  148. $this->assertEquals($expected, DateTimeHelper::parseGetStart($text));
  149. }
  150. public function parseGetStartInvalidArgumentProvider()
  151. {
  152. return [
  153. [' '],
  154. [''],
  155. ['2016--12'],
  156. ['2016-10-12 08:20#01'],
  157. [1],
  158. [false],
  159. ];
  160. }
  161. /**
  162. * @dataProvider parseGetStartInvalidArgumentProvider
  163. * @expectedException \InvalidArgumentException
  164. */
  165. public function testParseGetStartInvalidArgument($text)
  166. {
  167. DateTimeHelper::parseGetStart($text);
  168. }
  169. public function deinvertIntervalProvider()
  170. {
  171. return [
  172. [
  173. DI::createFromDateString('-2 years'),
  174. ['y' => -2, 'm' => 0, 'd' => 0, 'h' => 0, 'i' => 0, 's' => 0],
  175. ],
  176. [
  177. DI::createFromDateString('-2 months'),
  178. ['y' => 0, 'm' => -2, 'd' => 0, 'h' => 0, 'i' => 0, 's' => 0],
  179. ],
  180. [
  181. DI::createFromDateString('-2 days'),
  182. ['y' => 0, 'm' => 0, 'd' => -2, 'h' => 0, 'i' => 0, 's' => 0],
  183. ],
  184. [
  185. DI::createFromDateString('-2 hours'),
  186. ['y' => 0, 'm' => 0, 'd' => 0, 'h' => -2, 'i' => 0, 's' => 0],
  187. ],
  188. [
  189. DI::createFromDateString('-2 minutes'),
  190. ['y' => 0, 'm' => 0, 'd' => 0, 'h' => 0, 'i' => -2, 's' => 0],
  191. ],
  192. [
  193. DI::createFromDateString('-2 seconds'),
  194. ['y' => 0, 'm' => 0, 'd' => 0, 'h' => 0, 'i' => 0, 's' => -2],
  195. ],
  196. [
  197. (new DT('2016-08'))->diff(new DT('2016-07')),
  198. ['y' => 0, 'm' => -1, 'd' => 0, 'h' => 0, 'i' => 0, 's' => 0],
  199. ],
  200. [
  201. (new DT('2016-08-03'))->diff(new DT('2016-07-03')),
  202. ['y' => 0, 'm' => -1, 'd' => 0, 'h' => 0, 'i' => 0, 's' => 0],
  203. ],
  204. [
  205. (new DT('2016-07-03'))->diff(new DT('2016-08-03')),
  206. ['y' => 0, 'm' => 1, 'd' => 0, 'h' => 0, 'i' => 0, 's' => 0],
  207. ],
  208. [
  209. (new DT('2016-08-04'))->diff(new DT('2016-07-03')),
  210. ['y' => 0, 'm' => -1, 'd' => -1, 'h' => 0, 'i' => 0, 's' => 0],
  211. ],
  212. [
  213. (new DT('2016-07-03'))->diff(new DT('2016-08-04')),
  214. ['y' => 0, 'm' => 1, 'd' => 1, 'h' => 0, 'i' => 0, 's' => 0],
  215. ],
  216. [
  217. (new DT('2016-08-02'))->diff(new DT('2016-07-03')),
  218. ['y' => 0, 'm' => 0, 'd' => -30, 'h' => 0, 'i' => 0, 's' => 0],
  219. ],
  220. [
  221. (new DT('2016-07-03'))->diff(new DT('2016-08-02')),
  222. ['y' => 0, 'm' => 0, 'd' => 30, 'h' => 0, 'i' => 0, 's' => 0],
  223. ],
  224. [
  225. (new DT('2016-08-04 18:10:02'))->diff(new DT('2016-07-03 14:13:03')),
  226. ['y' => 0, 'm' => -1, 'd' => -1, 'h' => -3, 'i' => -56, 's' => -59],
  227. ],
  228. [
  229. (new DT('2016-07-03 14:13:03'))->diff(new DT('2016-08-04 18:10:02')),
  230. ['y' => 0, 'm' => 1, 'd' => 1, 'h' => 3, 'i' => 56, 's' => 59],
  231. ],
  232. ];
  233. }
  234. /**
  235. * @dataProvider deinvertIntervalProvider
  236. */
  237. public function testDeinvertInterval($source, $expected_attr)
  238. {
  239. // \DateInterval does not implement clone.
  240. // @see https://bugs.php.net/bug.php?id=50559
  241. $source_copy = unserialize(serialize($source));
  242. $deinverted = DateTimeHelper::deinvertInterval($source_copy);
  243. $this->assertEquals($source, $source_copy);
  244. $this->assertEquals(0, $deinverted->invert);
  245. foreach($expected_attr as $k => $v) {
  246. $this->assertSame($v, $deinverted->$k);
  247. }
  248. }
  249. public function intervalToIsoProvider()
  250. {
  251. return [
  252. [null, null],
  253. ];
  254. }
  255. /**
  256. * @dataProvider intervalToIsoProvider
  257. */
  258. public function testIntervalToIso($interval, $iso)
  259. {
  260. $this->assertSame($iso, DateTimeHelper::intervalToIso($interval));
  261. }
  262. public function intervalToIsoReinitProvider()
  263. {
  264. return [
  265. [new DI('P1Y')],
  266. [new DI('P1M')],
  267. [new DI('P1D')],
  268. [new DI('PT1H')],
  269. [new DI('PT1M')],
  270. [new DI('PT1S')],
  271. [new DI('P1Y2M3DT4H5M6S')],
  272. ];
  273. }
  274. /**
  275. * @dataProvider intervalToIsoReinitProvider
  276. */
  277. public function testIntervalToIsoReinit($interval)
  278. {
  279. $iso = DateTimeHelper::intervalToIso($interval);
  280. $this->assertEquals($interval, new DI($iso));
  281. }
  282. public function intervalToIsoReinitUnsupportedProvider()
  283. {
  284. return [
  285. [DI::createFromDateString('-2 years')],
  286. [DI::createFromDateString('-2 months')],
  287. [DI::createFromDateString('-2 days')],
  288. [DI::createFromDateString('-2 hours')],
  289. [DI::createFromDateString('-2 minutes')],
  290. [DI::createFromDateString('-2 seconds')],
  291. [(new DT('2016-08-03'))->diff(new DT('2016-07-03'))],
  292. [(new DT('2016-08-03 10:00:01'))->diff(new DT('2016-08-03 10:00:00'))],
  293. ];
  294. }
  295. /**
  296. * @dataProvider intervalToIsoReinitUnsupportedProvider
  297. * @expectedException \Exception
  298. */
  299. public function testIntervalToIsoReinitUnsupported($interval)
  300. {
  301. DateTimeHelper::intervalToIso($interval);
  302. }
  303. public function periodToIsoProvider()
  304. {
  305. return [
  306. [null, null],
  307. [
  308. new DP(
  309. new DT('2016-08-05T14:50:14+08:00'),
  310. new DI('P1D'),
  311. new DT('2016-08-10T14:50:14+08:00')
  312. ),
  313. 'R4/2016-08-05T14:50:14+08:00/P0Y0M1DT0H0M0S',
  314. ],
  315. [
  316. new DP(
  317. new DT('2016-08-05T14:50:14+08:00'),
  318. new DI('P5D'),
  319. new DT('2016-08-10T14:50:14+08:00')
  320. ),
  321. '2016-08-05T14:50:14+08:00/P0Y0M5DT0H0M0S',
  322. ],
  323. [
  324. new DP(
  325. new DT('2016-08-05T14:50:14+08:00'),
  326. new DI('P1Y2M3DT4H5M6S'),
  327. new DT('2017-10-08T18:55:20+08:00')
  328. ),
  329. '2016-08-05T14:50:14+08:00/P1Y2M3DT4H5M6S',
  330. ],
  331. [
  332. new DP(
  333. new DT('2016-08-05T14:50:14Z'),
  334. new DI('P1D'),
  335. 0
  336. ),
  337. '2016-08-05T14:50:14+00:00/P0Y0M1DT0H0M0S',
  338. ],
  339. [
  340. new DP(
  341. new DT('2016-08-05T14:50:14Z'),
  342. new DI('PT5M'),
  343. 3
  344. ),
  345. 'R3/2016-08-05T14:50:14+00:00/P0Y0M0DT0H5M0S',
  346. ],
  347. [
  348. new DP('R3/2016-08-05T14:50:14Z/PT5M'),
  349. 'R3/2016-08-05T14:50:14+00:00/P0Y0M0DT0H5M0S',
  350. ],
  351. [
  352. new DP('R4/2016-08-05T14:50:14Z/P1Y2M3DT4H5M6S'),
  353. 'R4/2016-08-05T14:50:14+00:00/P1Y2M3DT4H5M6S',
  354. ],
  355. [
  356. DateTimeHelper::parse('2016-08-05T14:50:14Z'),
  357. '2016-08-05T14:50:14+00:00/P0Y0M0DT0H0M1S',
  358. ],
  359. [
  360. DateTimeHelper::parse('2016-08-05Z'),
  361. '2016-08-05T00:00:00+00:00/P0Y0M1DT0H0M0S',
  362. ],
  363. [
  364. DateTimeHelper::parse('2016-08-05-03:00'),
  365. '2016-08-05T00:00:00-03:00/P0Y0M1DT0H0M0S',
  366. ],
  367. ];
  368. }
  369. /**
  370. * @dataProvider periodToIsoProvider
  371. */
  372. public function testPeriodToIso($period, $iso)
  373. {
  374. $this->assertSame($iso, DateTimeHelper::periodToIso($period));
  375. }
  376. }