1
0

DateTimeHelperTest.php 24 KB

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