DateTimeHelperTest.php 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506
  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 iso6801DateFormatProvider()
  10. {
  11. return [
  12. [0, '1970-01-01'],
  13. [1456704000, '2016-02-29'],
  14. [1479202824, '2016-11-15'],
  15. ];
  16. }
  17. /**
  18. * @dataProvider iso6801DateFormatProvider
  19. */
  20. public function testIso6801DateFormat($timestamp, $expected_date)
  21. {
  22. $date = date(DateTimeHelper::ISO8601_DATE_FORMAT, $timestamp);
  23. $this->assertEquals($expected_date, $date);
  24. }
  25. public function timestampToDateTimeProvider()
  26. {
  27. return [
  28. [null, null],
  29. [0, new DT('1970-01-01 00:00:00', new \DateTimeZone('UTC'))],
  30. [0, new DT('1970-01-01 01:00:00', new \DateTimeZone('Europe/Vienna'))],
  31. [1234567890, new DT('2009-02-13 23:31:30', new \DateTimeZone('UTC'))],
  32. [1234567890, new DT('2009-02-14 00:31:30', new \DateTimeZone('Europe/Vienna'))],
  33. [-3600, new DT('1970-01-01 00:00:00', new \DateTimeZone('Europe/Vienna'))],
  34. ];
  35. }
  36. /**
  37. * @dataProvider timestampToDateTimeProvider
  38. */
  39. public function testTimestampToDateTime($timestamp, $expected_datetime)
  40. {
  41. $generated_datetime = DateTimeHelper::timestampToDateTime($timestamp);
  42. $this->assertEquals($expected_datetime, $generated_datetime);
  43. }
  44. public function timestampToDateTimeDefaultTimezoneProvider()
  45. {
  46. return [
  47. ['UTC', 100],
  48. ['Europe/Vienna', 0],
  49. ['Europe/Vienna', -100],
  50. ['Europe/Vienna', 100],
  51. ['Europe/London', 3600],
  52. ['US/Pacific', 3600],
  53. ];
  54. }
  55. /**
  56. * @dataProvider timestampToDateTimeDefaultTimezoneProvider
  57. */
  58. public function testTimestampToDateTimeDefaultTimezone($timezone, $timestamp)
  59. {
  60. date_default_timezone_set($timezone);
  61. $generated_datetime = DateTimeHelper::timestampToDateTime($timestamp);
  62. $this->assertSame($timestamp, $generated_datetime->getTimestamp());
  63. }
  64. public function parseProvider()
  65. {
  66. return [
  67. // null
  68. [null, 'UTC', null],
  69. [null, 'US/Pacific', null],
  70. // year without timezone
  71. ['1900', 'UTC', new DP(new DT('1900-01-01T00:00:00Z'), new DI('P1Y'), 0)],
  72. ['0014', 'Europe/Vienna', new DP(new DT('0014-01-01T00:00:00+01:00'), new DI('P1Y'), 0)],
  73. ['2016', 'US/Pacific', new DP(new DT('2016-01-01T00:00:00-08:00'), new DI('P1Y'), 0)],
  74. // year with timezone
  75. ['1900Z', 'US/Pacific', new DP(new DT('1900-01-01T00:00:00Z'), new DI('P1Y'), 0)],
  76. ['2016Z', 'Europe/Vienna', new DP(new DT('2016-01-01T00:00:00Z'), new DI('P1Y'), 0)],
  77. ['2016+00:00', 'Europe/Vienna', new DP(new DT('2016-01-01T00:00:00Z'), new DI('P1Y'), 0)],
  78. ['2016+02:00', 'US/Pacific', new DP(new DT('2016-01-01T00:00:00+02:00'), new DI('P1Y'), 0)],
  79. ['0000 +02:05', 'US/Pacific', new DP(new DT('0000-01-01T00:00:00+02:05'), new DI('P1Y'), 0)],
  80. ['2016-08:00', 'UTC', new DP(new DT('2016-01-01T00:00:00-08:00'), new DI('P1Y'), 0)],
  81. ['2016 -08:00', 'UTC', new DP(new DT('2016-01-01T00:00:00-08:00'), new DI('P1Y'), 0)],
  82. // month without timezone
  83. ['2016-08', 'UTC', new DP(new DT('2016-08-01T00:00:00Z'), new DI('P1M'), 0)],
  84. ['2016-08', 'Europe/Vienna', new DP(new DT('2016-08-01T00:00:00+02:00'), new DI('P1M'), 0)],
  85. ['2016-01', 'US/Pacific', new DP(new DT('2016-01-01T00:00:00-08:00'), new DI('P1M'), 0)],
  86. // month with timezone
  87. ['2016-08Z', 'US/Pacific', new DP(new DT('2016-08-01T00:00:00Z'), new DI('P1M'), 0)],
  88. ['2016-08Z', 'Europe/Vienna', new DP(new DT('2016-08-01T00:00:00Z'), new DI('P1M'), 0)],
  89. ['2016-01+00:00', 'Europe/Vienna', new DP(new DT('2016-01-01T00:00:00Z'), new DI('P1M'), 0)],
  90. ['2016-01+02:00', 'US/Pacific', new DP(new DT('2016-01-01T00:00:00+02:00'), new DI('P1M'), 0)],
  91. ['2016-01 +02:00', 'US/Pacific', new DP(new DT('2016-01-01T00:00:00+02:00'), new DI('P1M'), 0)],
  92. ['2016-01 -08:00', 'UTC', new DP(new DT('2016-01-01T00:00:00-08:00'), new DI('P1M'), 0)],
  93. // date without timezone
  94. ['2016-08-02', 'UTC', new DP(new DT('2016-08-02T00:00:00Z'), new DI('P1D'), 0)],
  95. ['2016-08-02', 'Europe/Vienna', new DP(new DT('2016-08-02T00:00:00+02:00'), new DI('P1D'), 0)],
  96. ['2016-01-02', 'US/Pacific', new DP(new DT('2016-01-02T00:00:00-08:00'), new DI('P1D'), 0)],
  97. // date with timezone
  98. ['2016-08-02Z', 'US/Pacific', new DP(new DT('2016-08-02T00:00:00Z'), new DI('P1D'), 0)],
  99. ['2016-08-02Z', 'Europe/Vienna', new DP(new DT('2016-08-02T00:00:00Z'), new DI('P1D'), 0)],
  100. ['2016-01-02+00:00', 'Europe/Vienna', new DP(new DT('2016-01-02T00:00:00Z'), new DI('P1D'), 0)],
  101. ['2016-01-02+02:00', 'US/Pacific', new DP(new DT('2016-01-02T00:00:00+02:00'), new DI('P1D'), 0)],
  102. ['2016-01-02-08:13', 'UTC', new DP(new DT('2016-01-02T00:00:00-08:13'), new DI('P1D'), 0)],
  103. // minute without timezone
  104. ['2016-08-02 15:52', 'UTC', new DP(new DT('2016-08-02T15:52:00Z'), new DI('PT1M'), 0)],
  105. ['2016-08-02T15:52', 'UTC', new DP(new DT('2016-08-02T15:52:00Z'), new DI('PT1M'), 0)],
  106. ['2016-08-02T15:52', 'Europe/Vienna', new DP(new DT('2016-08-02T15:52:00+02:00'), new DI('PT1M'), 0)],
  107. ['2016-01-02T15:52', 'US/Pacific', new DP(new DT('2016-01-02T15:52:00-08:00'), new DI('PT1M'), 0)],
  108. // minute with timezone
  109. ['2016-08-02 15:52Z', 'US/Pacific', new DP(new DT('2016-08-02T15:52:00Z'), new DI('PT1M'), 0)],
  110. ['2016-08-02T15:52Z', 'Europe/Vienna', new DP(new DT('2016-08-02T15:52:00Z'), new DI('PT1M'), 0)],
  111. ['2016-01-02T15:52+00:00', 'Europe/Vienna', new DP(new DT('2016-01-02T15:52:00Z'), new DI('PT1M'), 0)],
  112. ['2016-01-02T15:52+02:00', 'US/Pacific', new DP(new DT('2016-01-02T15:52:00+02:00'), new DI('PT1M'), 0)],
  113. ['2016-01-02T15:52-08:00', 'UTC', new DP(new DT('2016-01-02T15:52:00-08:00'), new DI('PT1M'), 0)],
  114. // second without timezone
  115. ['2016-08-02 15:52:13', 'UTC', new DP(new DT('2016-08-02T15:52:13Z'), new DI('PT1S'), 0)],
  116. ['2016-08-02T15:52:13', 'UTC', new DP(new DT('2016-08-02T15:52:13Z'), new DI('PT1S'), 0)],
  117. ['2016-08-02T15:52:13', 'Europe/Vienna', new DP(new DT('2016-08-02T15:52:13+02:00'), new DI('PT1S'), 0)],
  118. ['2016-01-02T15:52:00', 'US/Pacific', new DP(new DT('2016-01-02T15:52:00-08:00'), new DI('PT1S'), 0)],
  119. // second with timezone
  120. ['2016-08-02 15:52:13Z', 'US/Pacific', new DP(new DT('2016-08-02T15:52:13Z'), new DI('PT1S'), 0)],
  121. ['2016-08-02T15:52:13Z', 'Europe/Vienna', new DP(new DT('2016-08-02T15:52:13Z'), new DI('PT1S'), 0)],
  122. ['2016-01-02T15:52:13+00:00', 'Europe/Vienna', new DP(new DT('2016-01-02T15:52:13Z'), new DI('PT1S'), 0)],
  123. ['2016-01-02T15:52:13+02:00', 'US/Pacific', new DP(new DT('2016-01-02T15:52:13+02:00'), new DI('PT1S'), 0)],
  124. ['2016-01-02T15:52:13-08:00', 'UTC', new DP(new DT('2016-01-02T15:52:13-08:00'), new DI('PT1S'), 0)],
  125. ];
  126. }
  127. /**
  128. * @dataProvider parseProvider
  129. */
  130. public function testParse($text, $timezone, $expected)
  131. {
  132. date_default_timezone_set($timezone);
  133. $this->assertEquals($expected, DateTimeHelper::parse($text));
  134. }
  135. public function parseInvalidArgumentProvider()
  136. {
  137. return [
  138. [' '],
  139. [''],
  140. ['2016--12'],
  141. ['2016-01-08:00'],
  142. ['2016-10-12 08:20#01'],
  143. [1],
  144. [false],
  145. ];
  146. }
  147. /**
  148. * @dataProvider parseInvalidArgumentProvider
  149. * @expectedException \InvalidArgumentException
  150. */
  151. public function testParseInvalidArgument($text)
  152. {
  153. DateTimeHelper::parse($text);
  154. }
  155. public function parseGetStartProvider()
  156. {
  157. return [
  158. [null, 'UTC', null],
  159. [null, 'US/Pacific', null],
  160. ['1900', 'UTC', new DT('1900-01-01T00:00:00Z') ],
  161. ['0014', 'Europe/Vienna', new DT('0014-01-01T00:00:00+01:00')],
  162. ['2016', 'US/Pacific', new DT('2016-01-01T00:00:00-08:00')],
  163. ['1900Z', 'US/Pacific', new DT('1900-01-01T00:00:00Z') ],
  164. ['2016Z', 'Europe/Vienna', new DT('2016-01-01T00:00:00Z') ],
  165. ['2016+00:00', 'Europe/Vienna', new DT('2016-01-01T00:00:00Z') ],
  166. ['2016+02:00', 'US/Pacific', new DT('2016-01-01T00:00:00+02:00')],
  167. ['0000 +02:05', 'US/Pacific', new DT('0000-01-01T00:00:00+02:05')],
  168. ['2016-08:00', 'UTC', new DT('2016-01-01T00:00:00-08:00')],
  169. ['2016 -08:00', 'UTC', new DT('2016-01-01T00:00:00-08:00')],
  170. ['2016-08', 'UTC', new DT('2016-08-01T00:00:00Z') ],
  171. ['2016-08', 'Europe/Vienna', new DT('2016-08-01T00:00:00+02:00')],
  172. ['2016-01', 'US/Pacific', new DT('2016-01-01T00:00:00-08:00')],
  173. ['2016-08Z', 'US/Pacific', new DT('2016-08-01T00:00:00Z') ],
  174. ['2016-08Z', 'Europe/Vienna', new DT('2016-08-01T00:00:00Z') ],
  175. ['2016-01+00:00', 'Europe/Vienna', new DT('2016-01-01T00:00:00Z') ],
  176. ['2016-01+02:00', 'US/Pacific', new DT('2016-01-01T00:00:00+02:00')],
  177. ['2016-01 +02:00', 'US/Pacific', new DT('2016-01-01T00:00:00+02:00')],
  178. ['2016-01 -08:00', 'UTC', new DT('2016-01-01T00:00:00-08:00')],
  179. ['2016-08-02', 'UTC', new DT('2016-08-02T00:00:00Z') ],
  180. ['2016-08-02', 'Europe/Vienna', new DT('2016-08-02T00:00:00+02:00')],
  181. ['2016-01-02', 'US/Pacific', new DT('2016-01-02T00:00:00-08:00')],
  182. ['2016-08-02Z', 'US/Pacific', new DT('2016-08-02T00:00:00Z') ],
  183. ['2016-08-02Z', 'Europe/Vienna', new DT('2016-08-02T00:00:00Z') ],
  184. ['2016-01-02+00:00', 'Europe/Vienna', new DT('2016-01-02T00:00:00Z') ],
  185. ['2016-01-02+02:00', 'US/Pacific', new DT('2016-01-02T00:00:00+02:00')],
  186. ['2016-01-02-08:13', 'UTC', new DT('2016-01-02T00:00:00-08:13')],
  187. ['2016-08-02 15:52', 'UTC', new DT('2016-08-02T15:52:00Z') ],
  188. ['2016-08-02T15:52', 'UTC', new DT('2016-08-02T15:52:00Z') ],
  189. ['2016-08-02T15:52', 'Europe/Vienna', new DT('2016-08-02T15:52:00+02:00')],
  190. ['2016-01-02T15:52', 'US/Pacific', new DT('2016-01-02T15:52:00-08:00')],
  191. ['2016-08-02 15:52Z', 'US/Pacific', new DT('2016-08-02T15:52:00Z') ],
  192. ['2016-08-02T15:52Z', 'Europe/Vienna', new DT('2016-08-02T15:52:00Z') ],
  193. ['2016-01-02T15:52+00:00', 'Europe/Vienna', new DT('2016-01-02T15:52:00Z') ],
  194. ['2016-01-02T15:52+02:00', 'US/Pacific', new DT('2016-01-02T15:52:00+02:00')],
  195. ['2016-01-02T15:52-08:00', 'UTC', new DT('2016-01-02T15:52:00-08:00')],
  196. ['2016-08-02 15:52:13', 'UTC', new DT('2016-08-02T15:52:13Z') ],
  197. ['2016-08-02T15:52:13', 'UTC', new DT('2016-08-02T15:52:13Z') ],
  198. ['2016-08-02T15:52:13', 'Europe/Vienna', new DT('2016-08-02T15:52:13+02:00')],
  199. ['2016-01-02T15:52:00', 'US/Pacific', new DT('2016-01-02T15:52:00-08:00')],
  200. ['2016-08-02 15:52:13Z', 'US/Pacific', new DT('2016-08-02T15:52:13Z') ],
  201. ['2016-08-02T15:52:13Z', 'Europe/Vienna', new DT('2016-08-02T15:52:13Z') ],
  202. ['2016-01-02T15:52:13+00:00', 'Europe/Vienna', new DT('2016-01-02T15:52:13Z') ],
  203. ['2016-01-02T15:52:13+02:00', 'US/Pacific', new DT('2016-01-02T15:52:13+02:00')],
  204. ['2016-01-02T15:52:13-08:00', 'UTC', new DT('2016-01-02T15:52:13-08:00')],
  205. ];
  206. }
  207. /**
  208. * @dataProvider parseGetStartProvider
  209. */
  210. public function testParseGetStart($text, $timezone, $expected)
  211. {
  212. date_default_timezone_set($timezone);
  213. $this->assertEquals($expected, DateTimeHelper::parseGetStart($text));
  214. }
  215. public function parseGetStartInvalidArgumentProvider()
  216. {
  217. return [
  218. [' '],
  219. [''],
  220. ['2016--12'],
  221. ['2016-01-08:00'],
  222. ['2016-10-12 08:20#01'],
  223. [1],
  224. [false],
  225. ];
  226. }
  227. /**
  228. * @dataProvider parseGetStartInvalidArgumentProvider
  229. * @expectedException \InvalidArgumentException
  230. */
  231. public function testParseGetStartInvalidArgument($text)
  232. {
  233. DateTimeHelper::parseGetStart($text);
  234. }
  235. public function deinvertIntervalProvider()
  236. {
  237. return [
  238. [
  239. DI::createFromDateString('-2 years'),
  240. ['y' => -2, 'm' => 0, 'd' => 0, 'h' => 0, 'i' => 0, 's' => 0],
  241. ],
  242. [
  243. DI::createFromDateString('-2 months'),
  244. ['y' => 0, 'm' => -2, 'd' => 0, 'h' => 0, 'i' => 0, 's' => 0],
  245. ],
  246. [
  247. DI::createFromDateString('-2 days'),
  248. ['y' => 0, 'm' => 0, 'd' => -2, 'h' => 0, 'i' => 0, 's' => 0],
  249. ],
  250. [
  251. DI::createFromDateString('-2 hours'),
  252. ['y' => 0, 'm' => 0, 'd' => 0, 'h' => -2, 'i' => 0, 's' => 0],
  253. ],
  254. [
  255. DI::createFromDateString('-2 minutes'),
  256. ['y' => 0, 'm' => 0, 'd' => 0, 'h' => 0, 'i' => -2, 's' => 0],
  257. ],
  258. [
  259. DI::createFromDateString('-2 seconds'),
  260. ['y' => 0, 'm' => 0, 'd' => 0, 'h' => 0, 'i' => 0, 's' => -2],
  261. ],
  262. [
  263. (new DT('2016-08'))->diff(new DT('2016-07')),
  264. ['y' => 0, 'm' => -1, 'd' => 0, 'h' => 0, 'i' => 0, 's' => 0],
  265. ],
  266. [
  267. (new DT('2016-08-03'))->diff(new DT('2016-07-03')),
  268. ['y' => 0, 'm' => -1, 'd' => 0, 'h' => 0, 'i' => 0, 's' => 0],
  269. ],
  270. [
  271. (new DT('2016-07-03'))->diff(new DT('2016-08-03')),
  272. ['y' => 0, 'm' => 1, 'd' => 0, 'h' => 0, 'i' => 0, 's' => 0],
  273. ],
  274. [
  275. (new DT('2016-08-04'))->diff(new DT('2016-07-03')),
  276. ['y' => 0, 'm' => -1, 'd' => -1, 'h' => 0, 'i' => 0, 's' => 0],
  277. ],
  278. [
  279. (new DT('2016-07-03'))->diff(new DT('2016-08-04')),
  280. ['y' => 0, 'm' => 1, 'd' => 1, 'h' => 0, 'i' => 0, 's' => 0],
  281. ],
  282. [
  283. (new DT('2016-08-02'))->diff(new DT('2016-07-03')),
  284. ['y' => 0, 'm' => 0, 'd' => -30, 'h' => 0, 'i' => 0, 's' => 0],
  285. ],
  286. [
  287. (new DT('2016-07-03'))->diff(new DT('2016-08-02')),
  288. ['y' => 0, 'm' => 0, 'd' => 30, 'h' => 0, 'i' => 0, 's' => 0],
  289. ],
  290. [
  291. (new DT('2016-08-04 18:10:02'))->diff(new DT('2016-07-03 14:13:03')),
  292. ['y' => 0, 'm' => -1, 'd' => -1, 'h' => -3, 'i' => -56, 's' => -59],
  293. ],
  294. [
  295. (new DT('2016-07-03 14:13:03'))->diff(new DT('2016-08-04 18:10:02')),
  296. ['y' => 0, 'm' => 1, 'd' => 1, 'h' => 3, 'i' => 56, 's' => 59],
  297. ],
  298. ];
  299. }
  300. /**
  301. * @dataProvider deinvertIntervalProvider
  302. */
  303. public function testDeinvertInterval($source, $expected_attr)
  304. {
  305. // \DateInterval does not implement clone.
  306. // @see https://bugs.php.net/bug.php?id=50559
  307. $source_copy = unserialize(serialize($source));
  308. $deinverted = DateTimeHelper::deinvertInterval($source_copy);
  309. $this->assertEquals($source, $source_copy);
  310. $this->assertEquals(0, $deinverted->invert);
  311. foreach($expected_attr as $k => $v) {
  312. $this->assertSame($v, $deinverted->$k);
  313. }
  314. }
  315. public function isoProvider()
  316. {
  317. return [
  318. [null, null],
  319. [new DT('2016-09-16 21:13+02:00'), '2016-09-16T21:13:00+02:00'],
  320. // \DateInterval::__construct() does not support negative specifiers.
  321. // e.g. 'P-1Y'
  322. // 0 years
  323. [new DI('P0Y0M0DT0H0M0S'), 'P0S' ],
  324. [new DI('P0Y0M0DT0H0M6S'), 'PT6S' ],
  325. [new DI('P0Y0M0DT0H5M0S'), 'PT5M' ],
  326. [new DI('P0Y0M0DT0H5M6S'), 'PT5M6S' ],
  327. [new DI('P0Y0M0DT4H0M0S'), 'PT4H' ],
  328. [new DI('P0Y0M3DT0H0M0S'), 'P3D' ],
  329. [new DI('P0Y0M3DT0H0M6S'), 'P3DT6S' ],
  330. [new DI('P0Y0M3DT4H5M6S'), 'P3DT4H5M6S' ],
  331. [new DI('P0Y2M0DT0H0M0S'), 'P2M' ],
  332. [new DI('P0Y2M0DT0H0M6S'), 'P2MT6S' ],
  333. [new DI('P0Y2M3DT0H0M6S'), 'P2M3DT6S' ],
  334. // >0 years, 0 months
  335. [new DI('P1Y0M0DT0H0M0S'), 'P1Y' ],
  336. [new DI('P1Y0M0DT0H0M6S'), 'P1YT6S' ],
  337. [new DI('P1Y0M0DT0H5M0S'), 'P1YT5M' ],
  338. [new DI('P1Y0M0DT0H5M6S'), 'P1YT5M6S' ],
  339. [new DI('P1Y0M0DT4H0M0S'), 'P1YT4H' ],
  340. [new DI('P1Y0M3DT0H0M0S'), 'P1Y3D' ],
  341. [new DI('P1Y0M3DT0H0M6S'), 'P1Y3DT6S' ],
  342. [new DI('P1Y0M3DT4H5M6S'), 'P1Y3DT4H5M6S' ],
  343. // >0 years, >0 months, 0 days (complete)
  344. [new DI('P1Y2M0DT0H0M0S'), 'P1Y2M' ],
  345. [new DI('P1Y2M0DT0H0M6S'), 'P1Y2MT6S' ],
  346. [new DI('P1Y2M0DT0H5M0S'), 'P1Y2MT5M' ],
  347. [new DI('P1Y2M0DT0H5M6S'), 'P1Y2MT5M6S' ],
  348. [new DI('P1Y2M0DT4H0M0S'), 'P1Y2MT4H' ],
  349. [new DI('P1Y2M0DT4H0M6S'), 'P1Y2MT4H6S' ],
  350. [new DI('P1Y2M0DT4H5M0S'), 'P1Y2MT4H5M' ],
  351. [new DI('P1Y2M0DT4H5M6S'), 'P1Y2MT4H5M6S' ],
  352. // >0 years, >0 months, >0 days (complete)
  353. [new DI('P1Y2M3DT0H0M0S'), 'P1Y2M3D' ],
  354. [new DI('P1Y2M3DT0H0M6S'), 'P1Y2M3DT6S' ],
  355. [new DI('P1Y2M3DT0H5M0S'), 'P1Y2M3DT5M' ],
  356. [new DI('P1Y2M3DT0H5M6S'), 'P1Y2M3DT5M6S' ],
  357. [new DI('P1Y2M3DT4H0M0S'), 'P1Y2M3DT4H' ],
  358. [new DI('P1Y2M3DT4H0M6S'), 'P1Y2M3DT4H6S' ],
  359. [new DI('P1Y2M3DT4H5M0S'), 'P1Y2M3DT4H5M' ],
  360. [new DI('P1Y2M3DT4H5M6S'), 'P1Y2M3DT4H5M6S'],
  361. [
  362. new DP(
  363. new DT('2016-08-05T14:50:14+08:00'),
  364. new DI('P1D'),
  365. new DT('2016-08-10T14:50:14+08:00')
  366. ),
  367. 'R4/2016-08-05T14:50:14+08:00/P1D',
  368. ],
  369. [
  370. new DP(
  371. new DT('2016-08-05T14:50:14+08:00'),
  372. new DI('P5D'),
  373. new DT('2016-08-10T14:50:14+08:00')
  374. ),
  375. '2016-08-05T14:50:14+08:00/P5D',
  376. ],
  377. [
  378. new DP(
  379. new DT('2016-08-05T14:50:14+08:00'),
  380. new DI('P1Y2M3DT4H5M6S'),
  381. new DT('2017-10-08T18:55:20+08:00')
  382. ),
  383. '2016-08-05T14:50:14+08:00/P1Y2M3DT4H5M6S',
  384. ],
  385. [
  386. new DP(
  387. new DT('2016-08-05T14:50:14Z'),
  388. new DI('P1D'),
  389. 0
  390. ),
  391. '2016-08-05T14:50:14+00:00/P1D',
  392. ],
  393. [
  394. new DP(
  395. new DT('2016-08-05T14:50:14Z'),
  396. new DI('PT5M'),
  397. 3
  398. ),
  399. 'R3/2016-08-05T14:50:14+00:00/PT5M',
  400. ],
  401. [
  402. new DP('R3/2016-08-05T14:50:14Z/PT5M'),
  403. 'R3/2016-08-05T14:50:14+00:00/PT5M',
  404. ],
  405. [
  406. new DP('R4/2016-08-05T14:50:14Z/P1Y2M3DT4H5M6S'),
  407. 'R4/2016-08-05T14:50:14+00:00/P1Y2M3DT4H5M6S',
  408. ],
  409. [
  410. DateTimeHelper::parse('2016-08-05T14:50:14Z'),
  411. '2016-08-05T14:50:14+00:00/PT1S',
  412. ],
  413. [
  414. DateTimeHelper::parse('2016-08-05Z'),
  415. '2016-08-05T00:00:00+00:00/P1D',
  416. ],
  417. [
  418. DateTimeHelper::parse('2016-08-05-03:00'),
  419. '2016-08-05T00:00:00-03:00/P1D',
  420. ],
  421. ];
  422. }
  423. /**
  424. * @dataProvider isoProvider
  425. */
  426. public function testIso($interval, $iso)
  427. {
  428. $this->assertSame($iso, DateTimeHelper::iso($interval));
  429. }
  430. public function isoReinitProvider()
  431. {
  432. return [
  433. [new DT('2016-09-16')],
  434. [new DT('2016-09-16 +02:00')],
  435. [new DT('2016-09-16 -07:13')],
  436. [new DT('2016-09-16 21:13')],
  437. [new DT('2016-09-16 21:13+02:00')],
  438. [new DT('2016-09-16 14:13-07:00')],
  439. [new DI('P1Y')],
  440. [new DI('P1M')],
  441. [new DI('P1D')],
  442. [new DI('PT1H')],
  443. [new DI('PT1M')],
  444. [new DI('PT1S')],
  445. [new DI('P3DT1S')],
  446. [new DI('P1Y2M3DT4H5M6S')],
  447. ];
  448. }
  449. /**
  450. * @dataProvider isoReinitProvider
  451. */
  452. public function testIsoReinit($obj)
  453. {
  454. $iso = DateTimeHelper::iso($obj);
  455. $class = get_class($obj);
  456. $this->assertEquals($obj, new $class($iso));
  457. }
  458. public function isoUnsupportedProvider()
  459. {
  460. return [
  461. [DI::createFromDateString('-2 years')],
  462. [DI::createFromDateString('-2 months')],
  463. [DI::createFromDateString('-2 days')],
  464. [DI::createFromDateString('-2 hours')],
  465. [DI::createFromDateString('-2 minutes')],
  466. [DI::createFromDateString('-2 seconds')],
  467. [(new DT('2016-08-03'))->diff(new DT('2016-07-03'))],
  468. [(new DT('2016-08-03 10:00:01'))->diff(new DT('2016-08-03 10:00:00'))],
  469. [new DP(new DT('2016-08-05'), new DI('P1D'), new DT('2016-08-05'))],
  470. [new DP(new DT('2016-08-05'), new DI('PT1S'), new DT('2016-08-04'))],
  471. [new \Exception('unsupported class')],
  472. ];
  473. }
  474. /**
  475. * @dataProvider isoUnsupportedProvider
  476. * @expectedException \InvalidArgumentException
  477. */
  478. public function testIsoUnsupported($interval)
  479. {
  480. DateTimeHelper::iso($interval);
  481. }
  482. }