1
0

DateTimeHelper.php 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. <?php
  2. namespace fphammerle\helpers;
  3. class DateTimeHelper
  4. {
  5. /**
  6. * @param integer|null $timestamp unix timestamp
  7. * @return \DateTime|null
  8. */
  9. public static function timestampToDateTime($timestamp)
  10. {
  11. if($timestamp === null) {
  12. return null;
  13. } elseif(is_int($timestamp)) {
  14. $dt = new \DateTime();
  15. $dt->setTimestamp($timestamp);
  16. return $dt;
  17. } else {
  18. throw new \InvalidArgumentException('expected integer or null');
  19. }
  20. }
  21. /**
  22. * @param string|null $text
  23. * @return \DatePeriod|null
  24. */
  25. public static function parse($text)
  26. {
  27. if($text === null) {
  28. return null;
  29. } else {
  30. if(preg_match(
  31. '/^(?P<y>\d{4})-(?P<m>\d{2})-(?P<d>\d{2})'
  32. .'([ T](?P<h>\d{2}):(?P<i>\d{2})(:(?P<s>\d{2}))?)?'
  33. . '(Z|[\+-]\d{2}:\d{2})?$/',
  34. $text,
  35. $attr
  36. )) {
  37. $start = new \DateTime($text);
  38. if(!empty($attr['s'])) {
  39. $interval = new \DateInterval('PT1S');
  40. } elseif(!empty($attr['i'])) {
  41. $interval = new \DateInterval('PT1M');
  42. } else {
  43. $interval = new \DateInterval('P1D');
  44. }
  45. return new \DatePeriod($start, $interval, 0);
  46. } else {
  47. throw new \InvalidArgumentException(
  48. sprintf("could not parse string '%s'", $text)
  49. );
  50. }
  51. }
  52. }
  53. /**
  54. * @param string|null $text
  55. * @return \DateTime|null
  56. */
  57. public static function parseGetStart($text)
  58. {
  59. $period = self::parse($text);
  60. if($period) {
  61. return $period->start;
  62. } else {
  63. return null;
  64. }
  65. }
  66. public static function deinvertInterval(\DateInterval $source = null)
  67. {
  68. // \DateInterval does not implement clone.
  69. // @see https://bugs.php.net/bug.php?id=50559
  70. $result = unserialize(serialize($source));
  71. if($result->invert) {
  72. $result->y *= -1;
  73. $result->m *= -1;
  74. $result->d *= -1;
  75. $result->h *= -1;
  76. $result->i *= -1;
  77. $result->s *= -1;
  78. $result->invert = 0;
  79. }
  80. return $result;
  81. }
  82. /**
  83. * @param \DateInterval|null $i
  84. * @return string|null
  85. */
  86. public static function intervalToIso(\DateInterval $i = null)
  87. {
  88. if(is_null($i)) {
  89. return null;
  90. } elseif(sizeof(get_object_vars($i)) == 0) {
  91. throw new \InvalidArgumentException(
  92. sprintf("given interval is invalid\n%s", print_r($i, true))
  93. );
  94. } else {
  95. $i = self::deinvertInterval($i);
  96. if($i->y < 0 || $i->m < 0 || $i->d < 0 || $i->h < 0 || $i->i < 0 || $i->s < 0) {
  97. throw new \Exception('negative intervals are not supported');
  98. } else {
  99. return $i->format('P%yY%mM%dDT%hH%iM%sS');
  100. }
  101. }
  102. }
  103. /**
  104. * @param \DatePeriod|null $p
  105. * @return string|null
  106. */
  107. public static function periodToIso(\DatePeriod $p = null)
  108. {
  109. if(is_null($p)) {
  110. return null;
  111. } else {
  112. // Cave:
  113. // (new \DatePeriod(
  114. // new \DateTime('2016-08-05T14:50:14Z'),
  115. // new \DateInterval('P1D'),
  116. // -1
  117. // )->recurrences == 1
  118. if($p->recurrences <= 0) {
  119. throw new \Exception(
  120. 'conversion of periods with number of occurances'
  121. . ' being negative is not supported'
  122. );
  123. }
  124. $repetitions = -1;
  125. foreach($p as $dt) {
  126. $repetitions++;
  127. // printf("%d. %s\n", $repetitions, $dt->format(\DateTime::ATOM));
  128. }
  129. // \DatePeriod::getStartDate() is available from php 5.6.5.
  130. $start_iso = $p->start->format(\DateTime::ATOM);
  131. // \DatePeriod::getDateInterval() is available from php 5.6.5.
  132. // \DatePeriod::$interval returned an invalid \DatePeriod instance
  133. // in php 7.0.8
  134. $interval_iso = self::intervalToIso(get_object_vars($p)['interval']);
  135. switch($repetitions) {
  136. case -1:
  137. // no valid date within period
  138. // e.g. new \DatePeriod(
  139. // new \DateTime('2016-08-05T14:50:14+08:00'),
  140. // new \DateInterval('PT1S'),
  141. // new \DateTime('2016-08-05T14:50:14+08:00')
  142. // )
  143. throw new \InvalidArgumentException(
  144. 'given period does not contain any valid date'
  145. );
  146. case 0:
  147. return sprintf('%s/%s', $start_iso, $interval_iso);
  148. default:
  149. return sprintf('R%d/%s/%s', $repetitions, $start_iso, $interval_iso);
  150. }
  151. }
  152. }
  153. }