lib_date.php 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. <?php
  2. /**
  3. * Author: Alexandre Alapetite http://alexandre.alapetite.fr
  4. * 2014-06-01
  5. * License: GNU AGPLv3 http://www.gnu.org/licenses/agpl-3.0.html
  6. *
  7. * Parser of ISO 8601 time intervals http://en.wikipedia.org/wiki/ISO_8601#Time_intervals
  8. * Examples: "2014-02/2014-04", "2014-02/04", "2014-06", "P1M"
  9. */
  10. /*
  11. example('2014-03');
  12. example('201403');
  13. example('2014-03-30');
  14. example('2014-05-30T13');
  15. example('2014-05-30T13:30');
  16. example('2014-02/2014-04');
  17. example('2014-02--2014-04');
  18. example('2014-02/04');
  19. example('2014-02-03/05');
  20. example('2014-02-03T22:00/22:15');
  21. example('2014-02-03T22:00/15');
  22. example('2014-03/');
  23. example('/2014-03');
  24. example('2014-03/P1W');
  25. example('P1W/2014-05-25T23:59:59');
  26. example('P1Y/');
  27. example('P1Y');
  28. example('P2M/');
  29. example('P3W/');
  30. example('P4D/');
  31. example('PT5H/');
  32. example('PT6M/');
  33. example('PT7S/');
  34. example('P1DT1H/');
  35. function example($dateInterval) {
  36. $dateIntervalArray = parseDateInterval($dateInterval);
  37. echo $dateInterval, "\t=>\t",
  38. $dateIntervalArray[0] == null ? 'null' : @date('c', $dateIntervalArray[0]), '/',
  39. $dateIntervalArray[1] == null ? 'null' : @date('c', $dateIntervalArray[1]), "\n";
  40. }
  41. */
  42. function _dateFloor($isoDate) {
  43. $x = explode('T', $isoDate, 2);
  44. $t = isset($x[1]) ? str_pad($x[1], 6, '0') : '000000';
  45. return str_pad($x[0], 8, '01') . 'T' . $t;
  46. }
  47. function _dateCeiling($isoDate) {
  48. $x = explode('T', $isoDate, 2);
  49. $t = isset($x[1]) && strlen($x[1]) > 1 ? str_pad($x[1], 6, '59') : '235959';
  50. switch (strlen($x[0])) {
  51. case 4:
  52. return $x[0] . '1231T' . $t;
  53. case 6:
  54. $d = @strtotime($x[0] . '01');
  55. return $x[0] . date('t', $d) . 'T' . $t;
  56. default:
  57. return $x[0] . 'T' . $t;
  58. }
  59. }
  60. function _noDelimit($isoDate) {
  61. return $isoDate === null || $isoDate === '' ? null :
  62. str_replace(array('-', ':'), '', $isoDate); //FIXME: Bug with negative time zone
  63. }
  64. function _dateRelative($d1, $d2) {
  65. if ($d2 === null) {
  66. return $d1 !== null && $d1[0] !== 'P' ? $d1 : null;
  67. } elseif ($d2 !== '' && $d2[0] != 'P' && $d1 !== null && $d1[0] !== 'P') {
  68. $y2 = substr($d2, 0, 4);
  69. if (strlen($y2) < 4 || !ctype_digit($y2)) { //Does not start by a year
  70. $d2 = _noDelimit($d2);
  71. return substr($d1, 0, -strlen($d2)) . $d2; //Add prefix from $d1
  72. }
  73. }
  74. return _noDelimit($d2);
  75. }
  76. /**
  77. * Parameter $dateInterval is a string containing an ISO 8601 time interval.
  78. * Returns an array with the minimum and maximum Unix timestamp of this interval,
  79. * or null if open interval, or false if error.
  80. */
  81. function parseDateInterval($dateInterval) {
  82. $dateInterval = trim($dateInterval);
  83. $dateInterval = str_replace('--', '/', $dateInterval);
  84. $dateInterval = strtoupper($dateInterval);
  85. $min = null;
  86. $max = null;
  87. $x = explode('/', $dateInterval, 2);
  88. $d1 = _noDelimit($x[0]);
  89. $d2 = _dateRelative($d1, count($x) > 1 ? $x[1] : null);
  90. if ($d1 !== null && $d1[0] !== 'P') {
  91. $min = @strtotime(_dateFloor($d1));
  92. }
  93. if ($d2 !== null) {
  94. if ($d2[0] === 'P') {
  95. try {
  96. $di2 = new DateInterval($d2);
  97. $dt1 = @date_create(); //new DateTime() would create an Exception if the default time zone is not defined
  98. if ($min !== null && $min !== false) {
  99. $dt1->setTimestamp($min);
  100. }
  101. $max = $dt1->add($di2)->getTimestamp() - 1;
  102. } catch (Exception $e) {
  103. $max = false;
  104. }
  105. } elseif ($d1 === null || $d1[0] !== 'P') {
  106. $max = @strtotime(_dateCeiling($d2));
  107. } else {
  108. $max = @strtotime($d2);
  109. }
  110. }
  111. if ($d1 !== null && $d1[0] === 'P') {
  112. try {
  113. $di1 = new DateInterval($d1);
  114. $dt2 = @date_create();
  115. if ($max !== null && $max !== false) {
  116. $dt2->setTimestamp($max);
  117. }
  118. $min = $dt2->sub($di1)->getTimestamp() + 1;
  119. } catch (Exception $e) {
  120. $min = false;
  121. }
  122. }
  123. return array($min, $max);
  124. }