isValidDateExpression($dateExpr)) { $sanitized = str_replace(array('<', '>'), '', $dateExpr); throw new \InvalidArgumentException("DateFormula $sanitized is invalid."); } $matches = array(); $returnMatches = array(); if (preg_match_all(self::REGEX_PATTERN_SUBEXPRESSION, $dateExpr, $matches)) { $returnMatches = $matches[0]; } return $returnMatches; } /** * @param $subExp * @return string * @throws \InvalidArgumentException */ public function getSubExpressionSign($subExp) { if (!$this->isValidDateSubExpression($subExp)) { $sanitized = str_replace(array('<', '>'), '', $subExp); throw new \InvalidArgumentException("SubExpression $sanitized is invalid."); } $matches = array(); preg_match(self::REGEX_PATTERN_SIGN, $subExp, $matches); if (isset($matches[0]) && $matches[0] === '-') { return '-'; } else { return '+'; } } /** * @param $subExp * @return int * @throws \InvalidArgumentException */ public function getSubExpressionNoOfIntervals($subExp) { if (!$this->isValidDateSubExpression($subExp)) { $sanitized = str_replace(array('<', '>'), '', $subExp); throw new \InvalidArgumentException("SubExpression $sanitized is invalid."); } $matches = array(); preg_match(self::REGEX_PATTERN_NO_OF_INTERVALS, $subExp, $matches); if (isset($matches[1]) && (int)$matches[1] > 0) { return (int)$matches[1]; } else { return 0; } } /** * @param $subExp * @return string * @throws \InvalidArgumentException */ public function getSubExpressionPrefix($subExp) { if (!$this->isValidDateSubExpression($subExp)) { $sanitized = str_replace(array('<', '>'), '', $subExp); throw new \InvalidArgumentException("SubExpression $sanitized is invalid."); } $matches = array(); preg_match(self::REGEX_PATTERN_PREFIX, $subExp, $matches); if (isset($matches[1])) { return 'C'; } else { return ''; } } /** * @param $subExp * @return string * @throws \InvalidArgumentException */ public function getSubExpressionIntervalTerm($subExp) { if (!$this->isValidDateSubExpression($subExp)) { $sanitized = str_replace(array('<', '>'), '', $subExp); throw new \InvalidArgumentException("SubExpression $sanitized is invalid."); } $matches = array(); preg_match(self::REGEX_PATTERN_INTERVAL_TERM, $subExp, $matches); if (isset($matches[1])) { return $matches[1]; } else { return 'CD'; } } /** * @param $subExp * @return int * @throws \InvalidArgumentException */ public function getSubExpressionIntervalOrdinal($subExp) { if (!$this->isValidDateSubExpression($subExp)) { $sanitized = str_replace(array('<', '>'), '', $subExp); throw new \InvalidArgumentException("SubExpression $sanitized is invalid."); } $matches = array(); preg_match(self::REGEX_PATTERN_INTERVAL_ORDINAL, $subExp, $matches); if (isset($matches[1]) && (int)$matches[1] > 0) { return (int)$matches[1]; } else { return 0; } } /** * @param $formula * @param \DateTime $dateTime * @throws \InvalidArgumentException */ public function evaluateDateFormula($formula, \DateTime $dateTime) { $formula = str_replace(array('<', '>'), '', $formula); if (!$this->isValidDateExpression($formula)) { throw new \InvalidArgumentException('Argument ' . $formula . ' is not a valid DateFormula'); } $subExpressions = $this->getSubExpressionArray($formula); foreach ($subExpressions as $subExpression) { $this->_evaluateSubExpression($subExpression, $dateTime); } } /** * @param \DateTime $referenceDateTime * @return int */ public function getMinusCW(\DateTime $referenceDateTime) { return strtotime('last monday', strtotime('tomorrow', $referenceDateTime->getTimestamp())); } /** * @param \DateTime $referenceDateTime * @return int */ public function getPlusCW(\DateTime $referenceDateTime) { return strtotime('next sunday + 1 day', strtotime('yesterday', $referenceDateTime->getTimestamp())); } /** * @param \DateTime $referenceDateTime * @return int */ public function getMinusCM(\DateTime $referenceDateTime) { return strtotime('first day of this month', $referenceDateTime->getTimestamp()); } /** * @param \DateTime $referenceDateTime * @return int */ public function getPlusCM(\DateTime $referenceDateTime) { return strtotime('last day of this month', $referenceDateTime->getTimestamp()); } /** * @param \DateTime $referenceDateTime * @return mixed */ public function getMinusCQ(\DateTime $referenceDateTime) { return $this->getStartEndDateForCurrentQuarter($referenceDateTime)[0]; } /** * @param \DateTime $referenceDateTime * @return mixed */ public function getPlusCQ(\DateTime $referenceDateTime) { return $this->getStartEndDateForCurrentQuarter($referenceDateTime)[1]; } /** * @param \DateTime $referenceDateTime * @return int */ public function getMinusCY(\DateTime $referenceDateTime) { $year = date('Y', $referenceDateTime->getTimestamp()); return strtotime('01-January-' . $year); } /** * @param \DateTime $referenceDateTime * @return int */ public function getPlusCY(\DateTime $referenceDateTime) { $year = date('Y', $referenceDateTime->getTimestamp()); return strtotime('31-December-' . $year); } /** * @param $subExp * @param \DateTime $dateRef */ protected function _evaluateSubExpression($subExp, \DateTime $dateRef) { if (!$this->isValidDateSubExpression($subExp)) { $sanitized = str_replace(array('<', '>'), '', $subExp); throw new \InvalidArgumentException("SubExpression $sanitized is invalid."); } $sign = $this->getSubExpressionSign($subExp); $prefix = $this->getSubExpressionPrefix($subExp); $noOfIntervals = $this->getSubExpressionNoOfIntervals($subExp); $intervalTerm = $this->getSubExpressionIntervalTerm($subExp); $intervalOrdinal = $this->getSubExpressionIntervalOrdinal($subExp); if ($prefix === 'C' || $prefix === 'L') { $prefix = 'C'; } if ($intervalTerm === 'T') { $intervalTerm = 'D'; } elseif ($intervalTerm === 'WT') { $intervalTerm = 'WD'; } elseif ($intervalTerm === 'J') { $intervalTerm = 'Y'; } //NAV handles WD/WT when preceded by a number as 'D' if ($noOfIntervals > 0 && $intervalTerm == 'WD') { $intervalTerm = 'D'; } if ($prefix === 'C') { if ($intervalTerm === 'D' || $intervalTerm === 'WD') { //Day is equal to reference date, thus no change in $dateRef return; } $callableNamePrefix = 'get'; $signNamePart = 'Plus'; if ($sign === '-') { $signNamePart = 'Minus'; } $callableName = $callableNamePrefix . $signNamePart . $prefix . $intervalTerm; $newTimestamp = $this->{$callableName}($dateRef); $dateRef->setTimestamp($newTimestamp); } elseif ($prefix === '' && $noOfIntervals > 0) { $this->traverseDateAndMutateRef($sign, $noOfIntervals, $intervalTerm, $dateRef); } elseif ($prefix === '' && $intervalOrdinal > 0) { $this->mutateDateTimeForOrdinalExpression($sign, $intervalTerm, $intervalOrdinal, $dateRef); } } /** * @param $sign * @param $intervalTerm * @param $intervalOrdinal * @param \DateTime $dateRef */ public function mutateDateTimeForOrdinalExpression($sign, $intervalTerm, $intervalOrdinal, \DateTime $dateRef) { $combined = $sign . $intervalTerm . $intervalOrdinal; if (!$this->isValidDateSubExpression($combined)) { $sanitized = str_replace(array('<', '>'), '', $combined); throw new \InvalidArgumentException("SubExpression $sanitized is invalid."); } switch ($intervalTerm) { case 'D': $this->mutateDateTimeForDayOrdinal($sign, $intervalOrdinal, $dateRef); break; case 'T': $this->mutateDateTimeForDayOrdinal($sign, $intervalOrdinal, $dateRef); break; case 'WD': $this->mutateDateTimeForWeekDayOrdinal($sign, $intervalOrdinal, $dateRef); break; case 'WT': $this->mutateDateTimeForWeekDayOrdinal($sign, $intervalOrdinal, $dateRef); break; case 'W': $this->mutateDateTimeForWeekOrdinal($sign, $intervalOrdinal, $dateRef); break; case 'M': $this->mutateDateTimeForMonthOrdinal($sign, $intervalOrdinal, $dateRef); break; case 'Q': $this->mutateDateTimeForQuarterOrdinal($sign, $intervalOrdinal, $dateRef); break; case 'Y': $this->mutateDateTimeForYearOrdinal($sign, $intervalOrdinal, $dateRef); break; case 'J': $this->mutateDateTimeForYearOrdinal($sign, $intervalOrdinal, $dateRef); break; } } /** * @param $sign * @param $intervalOrdinal * @param \DateTime $dateRef */ protected function mutateDateTimeForDayOrdinal($sign, $intervalOrdinal, \DateTime $dateRef) { $intervalTerm = 'D'; $combined = $sign . $intervalTerm . $intervalOrdinal; if (!$this->isValidDateSubExpression($combined)) { $sanitized = str_replace(array('<', '>'), '', $combined); throw new \InvalidArgumentException("SubExpression $sanitized is invalid."); } $dateRefInitTimestamp = $dateRef->getTimestamp(); $dateRefInitMidnightTimestamp = strtotime($dateRef->format('d.m.Y')); $dateRefInitDayOfMonthNo = strftime('%d', $dateRefInitTimestamp); $dateRefInitMonthNo = strftime('%m', $dateRefInitTimestamp); $dateRefInitYear4digit = strftime('%Y', $dateRefInitTimestamp); $intermediateTimestamp = strtotime(sprintf('%02d.%02d.%4d', $intervalOrdinal, $dateRefInitMonthNo, $dateRefInitYear4digit)); $finalTimestamp = $intermediateTimestamp; if ($sign === '+' && (($intermediateTimestamp <= $dateRefInitMidnightTimestamp))) { $calcMonthNo = (int)$dateRefInitMonthNo + 1; $calcYearNo = $dateRefInitYear4digit; if ($calcMonthNo === 13) { $calcMonthNo = '01'; $calcYearNo = (int)$calcYearNo + 1; } $finalTimestamp = strtotime(sprintf('%02d.%02d.%4d', $intervalOrdinal, $calcMonthNo, $calcYearNo)); } elseif ($sign === '-' && ($intermediateTimestamp <= $dateRefInitMidnightTimestamp)) { $finalTimestamp = $intermediateTimestamp; } elseif ($sign === '-' && ($intermediateTimestamp > $dateRefInitMidnightTimestamp)) { $calcMonthNo = (int)$dateRefInitDayOfMonthNo - 1; $calcYearNo = $dateRefInitYear4digit; if ($calcMonthNo === 0) { $calcMonthNo = '12'; $calcYearNo = (int)$calcYearNo - 1; } $finalTimestamp = strtotime(sprintf('%02d.%02d.%4d', $intervalOrdinal, $calcMonthNo, $calcYearNo)); } $dtStr = date("c", $finalTimestamp); $newDateTime = new \DateTime($dtStr); $dateRef->setTimestamp($newDateTime->getTimestamp()); } /** * @param $sign * @param $intervalOrdinal * @param \DateTime $dateRef */ protected function mutateDateTimeForWeekDayOrdinal($sign, $intervalOrdinal, \DateTime $dateRef) { $intervalTerm = 'WD'; $combined = $sign . $intervalTerm . $intervalOrdinal; if (!$this->isValidDateSubExpression($combined)) { $sanitized = str_replace(array('<', '>'), '', $combined); throw new \InvalidArgumentException("SubExpression $sanitized is invalid."); } $dateRefInitTimestamp = $dateRef->getTimestamp(); $dateRefInitWeekNo = $dateRef->format('W'); $dateRefInitDayOfWeek = date("N", $dateRefInitTimestamp); $dateRefInitYear4digit = $dateRef->format('Y'); $startEndOfRefWeekArr = $this->getStartAndEndDateTimestampForWeek($dateRefInitWeekNo, $dateRefInitYear4digit); $startOfRefWeek = $startEndOfRefWeekArr[0]; $startOfPrevWeek = strtotime("-1 weeks", $startOfRefWeek); $startOfNextWeek = strtotime("+1 weeks", $startOfRefWeek); $targetTimestamp = $startOfNextWeek; if(($sign === '+' && ($dateRefInitDayOfWeek < $intervalOrdinal))||($sign === '-' && ($dateRefInitDayOfWeek > $intervalOrdinal))) { $targetTimestamp = $startOfRefWeek; } elseif($sign === '-') { $targetTimestamp = $startOfPrevWeek; } if ($intervalOrdinal > 1) { $noOfDaysToTraverse = $intervalOrdinal - 1; $targetTimestamp = strtotime("+$noOfDaysToTraverse days", $targetTimestamp); } $dtStr = date("c", $targetTimestamp); $newDateTime = new \DateTime($dtStr); $dateRef->setTimestamp($newDateTime->getTimestamp()); } /** * @param $sign * @param $intervalOrdinal * @param \DateTime $dateRef */ protected function mutateDateTimeForWeekOrdinal($sign, $intervalOrdinal, \DateTime $dateRef) { $intervalTerm = 'W'; $combined = $sign . $intervalTerm . $intervalOrdinal; if (!$this->isValidDateSubExpression($combined)) { $sanitized = str_replace(array('<', '>'), '', $combined); throw new \InvalidArgumentException("SubExpression $sanitized is invalid."); } $dateRefInitTimestamp = $dateRef->getTimestamp(); $dateRefInitYear4digit = strftime('%Y', $dateRefInitTimestamp); $dateRefInitWeekNo = strftime('%V', $dateRefInitTimestamp); $finalTimestamp = strtotime(sprintf("%4dW%02d", $dateRefInitYear4digit, $intervalOrdinal)); if ($sign === '' && ($dateRefInitWeekNo >= $intervalOrdinal)) { $calcYearNo = (int)$dateRefInitYear4digit + 1; $finalTimestamp = strtotime(sprintf("%4dW%02d", $calcYearNo, $intervalOrdinal)); } elseif ($sign === '-' && ($dateRefInitWeekNo < $intervalOrdinal)) { $calcYearNo = (int)$dateRefInitYear4digit - 1; $finalTimestamp = strtotime(sprintf("%4dW%02d", $calcYearNo, $intervalOrdinal)); } $dtStr = date("c", $finalTimestamp); $newDateTime = new \DateTime($dtStr); $dateRef->setTimestamp($newDateTime->getTimestamp()); } /** * @param $sign * @param $intervalOrdinal * @param \DateTime $dateRef * @throws \InvalidArgumentException */ protected function mutateDateTimeForMonthOrdinal($sign, $intervalOrdinal, \DateTime $dateRef) { $intervalTerm = 'M'; $combined = $sign . $intervalTerm . $intervalOrdinal; if (!$this->isValidDateSubExpression($combined)) { $sanitized = str_replace(array('<', '>'), '', $combined); throw new \InvalidArgumentException("SubExpression $sanitized is invalid."); } $dateRefInitTimestamp = $dateRef->getTimestamp(); $dateRefInitYear4digit = strftime('%Y', $dateRefInitTimestamp); $dateRefInitMonthNo = strftime('%m', $dateRefInitTimestamp); $newDateTime = \DateTime::createFromFormat('d.m.Y', sprintf('%02d.%02d.%04d', '01', $intervalOrdinal, $dateRefInitYear4digit)); if ($sign === '' && ($dateRefInitMonthNo >= $intervalOrdinal)) { $calcYearNo = (int)$dateRefInitYear4digit + 1; $newDateTime = \DateTime::createFromFormat('d.m.Y', sprintf('%02d.%02d.%04d', '01', $intervalOrdinal, $calcYearNo)); } elseif ($sign === '-' && ($dateRefInitMonthNo < $intervalOrdinal)) { $calcYearNo = (int)$dateRefInitYear4digit - 1; $newDateTime = \DateTime::createFromFormat('d.m.Y', sprintf('%02d.%02d.%04d', '01', $intervalOrdinal, $calcYearNo)); } $dateRef->setTimestamp($newDateTime->getTimestamp()); } /** * @param $sign * @param $intervalOrdinal * @param \DateTime $dateRef */ protected function mutateDateTimeForQuarterOrdinal($sign, $intervalOrdinal, \DateTime $dateRef) { $intervalTerm = 'Q'; $combined = $sign . $intervalTerm . $intervalOrdinal; if (!$this->isValidDateSubExpression($combined)) { $sanitized = str_replace(array('<', '>'), '', $combined); throw new \InvalidArgumentException("SubExpression $sanitized is invalid."); } $dateRefInitTimestamp = $dateRef->getTimestamp(); $dateRefInitYear4digit = strftime('%Y', $dateRefInitTimestamp); $dateRefInitMonthNo = strftime('%m', $dateRefInitTimestamp); $dateRefInitQuarterNo = ceil($dateRefInitMonthNo / 3); if ($intervalOrdinal < 1) { $intervalOrdinal = 1; } if ($intervalOrdinal > 4) { $intervalOrdinal = 4; } $endMonthNoTargetQuarter = ($intervalOrdinal * 3); $startMonthTargetQuarter = $endMonthNoTargetQuarter - 2; $newDateTime = \DateTime::createFromFormat('d.m.Y', sprintf('%02d.%02d.%04d', '01', $startMonthTargetQuarter, $dateRefInitYear4digit)); if ($sign === '' && ($dateRefInitQuarterNo >= $intervalOrdinal)) { $calcYearNo = (int)$dateRefInitYear4digit + 1; $newDateTime = \DateTime::createFromFormat('d.m.Y', sprintf('%02d.%02d.%04d', '01', $startMonthTargetQuarter, $calcYearNo)); } elseif ($sign === '-' && ($dateRefInitQuarterNo < $intervalOrdinal)) { $calcYearNo = (int)$dateRefInitYear4digit - 1; $newDateTime = \DateTime::createFromFormat('d.m.Y', sprintf('%02d.%02d.%04d', '01', $startMonthTargetQuarter, $calcYearNo)); } $dateRef->setTimestamp($newDateTime->getTimestamp()); } /** * @param $sign * @param $intervalOrdinal * @param \DateTime $dateRef */ protected function mutateDateTimeForYearOrdinal($sign, $intervalOrdinal, \DateTime $dateRef) { $intervalTerm = 'Y'; $combined = $sign . $intervalTerm . $intervalOrdinal; if (!$this->isValidDateSubExpression($combined)) { $sanitized = str_replace(array('<', '>'), '', $combined); throw new \InvalidArgumentException("SubExpression $sanitized is invalid."); } $dateRefInitTimestamp = $dateRef->getTimestamp(); $dateRefInitYear4digit = strftime('%y', $dateRefInitTimestamp); $dateRefInitLast2Digits = substr($dateRefInitYear4digit, -2, 2); $dateRefInitFirst2Digits = substr($dateRefInitYear4digit, 0, 2); if ($intervalOrdinal >= $dateRefInitLast2Digits) { $newYearStr = $dateRefInitFirst2Digits . $intervalOrdinal; } else { $newYearStr = sprintf('%02d%02d', ((int)$dateRefInitFirst2Digits + 1), $intervalOrdinal); }; $newDateTime = \DateTime::createFromFormat('d.m.Y', sprintf('%02d.%02d.%04d', '01', '01', $newYearStr)); $dateRef->setTimestamp($newDateTime->getTimestamp()); } /** * @param $sign * @param $noOfTraversals * @param $intervalTerm * @param \DateTime $dateRef * @throws \InvalidArgumentException */ public function traverseDateAndMutateRef($sign, $noOfTraversals, $intervalTerm, \DateTime $dateRef) { $combined = $sign . $noOfTraversals . $intervalTerm; if (!$this->isValidDateSubExpression($combined)) { $sanitized = str_replace(array('<', '>'), '', $combined); throw new \InvalidArgumentException("SubExpression $sanitized is invalid."); } $strtotimeIntervalTerm = $this->getIntervalTermStrtotimeMapping($intervalTerm); $newTime = strtotime("$sign $noOfTraversals $strtotimeIntervalTerm", $dateRef->getTimestamp()); $dtStr = date("c", $newTime); $newDateTime = new \DateTime($dtStr); $dateRef->setTimestamp($newDateTime->getTimestamp()); } /** * @param $formula * @return mixed * @throws \InvalidArgumentException */ public function getSubExpressionArray($formula) { if (!$this->isValidDateExpression($formula)) { throw new \InvalidArgumentException('Argument is not a valid DateFormula'); } $firstChar = mb_substr($formula, 0); $lastChar = mb_substr($formula, -1); if ($firstChar === '<' && $lastChar === '>') { $formula = rtrim(ltrim($formula, '<'), '>'); } $subExpressionRegex = '/([\+\-]{0,1}(?:(?:[0-9]+(?:D|T|WD|WT|W|M|Q|Y|J))|(?:(?:D|T|WD|WT|W|M|Q|Y|J)[0-9]+)|(?:[CL]{1}(?:D|T|WD|WT|W|M|Q|Y|J))))/'; $allSubExpressions = array(); preg_match_all($subExpressionRegex, $formula, $allSubExpressions); return $allSubExpressions[0]; } /** * @param \DateTime $dateTime * @return int */ public function getCurrentQuarterStartDate(\DateTime $dateTime) { $currentMonth = date('m', $dateTime->getTimestamp()); $currentYear = date('Y', $dateTime->getTimestamp()); $startDate = $dateTime->getTimestamp(); if ($currentMonth >= 1 && $currentMonth <= 3) { $startDate = strtotime('1-January-' . $currentYear); // timestamp or 1-January 12:00:00 AM } elseif ($currentMonth >= 4 && $currentYear <= 6) { $startDate = strtotime('1-April-' . $currentYear); // timestamp or 1-April 12:00:00 AM } elseif ($currentMonth >= 7 && $currentMonth <= 9) { $startDate = strtotime('1-July-' . $currentYear); // timestamp or 1-July 12:00:00 AM } elseif ($currentMonth >= 10 && $currentMonth <= 12) { $startDate = strtotime('1-October-' . $currentYear); // timestamp or 1-October 12:00:00 AM } return $startDate; } /** * @param \DateTime $dateTime * @return int */ public function getNextQuarterStartDate(\DateTime $dateTime) { $currentMonth = date('m', $dateTime->getTimestamp()); $currentYear = date('Y', $dateTime->getTimestamp()); $startDate = $dateTime->getTimestamp(); if ($currentMonth >= 1 && $currentMonth <= 3) { $startDate = strtotime('1-April-' . $currentYear); // timestamp or 1-April 12:00:00 AM } elseif ($currentMonth >= 4 && $currentYear <= 6) { $startDate = strtotime('1-July-' . $currentYear); // timestamp or 1-July 12:00:00 AM } elseif ($currentMonth >= 7 && $currentMonth <= 9) { $startDate = strtotime('1-October-' . $currentYear); // timestamp or 1-October 12:00:00 AM } elseif ($currentMonth >= 10 && $currentMonth <= 12) { $startDate = strtotime('1-January-' . $currentYear); // timestamp or 1-January 12:00:00 AM } return $startDate; } /** * @param \DateTime $dateTime * @return array */ public function getStartEndDateForCurrentQuarter(\DateTime $dateTime) { $dtTimeStamp = $dateTime->getTimestamp(); $currentMonth = date('m', $dtTimeStamp); $currentYear = date('Y', $dtTimeStamp); $startDate = $dtTimeStamp; $endDate = $dtTimeStamp; if ($currentMonth >= 1 && $currentMonth <= 3) { $startDate = strtotime('1-January-' . $currentYear); // timestamp or 1-Januray 12:00:00 AM $endDate = strtotime('1-April-' . $currentYear); // timestamp or 1-April 12:00:00 AM means end of 31 March } elseif ($currentMonth >= 4 && $currentMonth <= 6) { $startDate = strtotime('1-April-' . $currentYear); // timestamp or 1-April 12:00:00 AM $endDate = strtotime('1-July-' . $currentYear); // timestamp or 1-July 12:00:00 AM means end of 30 June } elseif ($currentMonth >= 7 && $currentMonth <= 9) { $startDate = strtotime('1-July-' . $currentYear); // timestamp or 1-July 12:00:00 AM $endDate = strtotime('1-October-' . $currentYear); // timestamp or 1-October 12:00:00 AM means end of 30 September } elseif ($currentMonth >= 10 && $currentMonth <= 12) { $startDate = strtotime('1-October-' . $currentYear); // timestamp or 1-October 12:00:00 AM $endDate = strtotime('1-January-' . ($currentYear + 1)); // timestamp or 1-January Next year 12:00:00 AM means end of 31 December this year } $dateArr = array($startDate, $endDate); return $dateArr; } /** * @param $term * @return string * @throws \InvalidArgumentException */ public function getIntervalTermStrtotimeMapping($term) { $matches = array(); if (!preg_match(self::REGEX_PATTERN_INTERVAL_TERM, $term, $matches)) { throw new \InvalidArgumentException("$term is not a valid interval-term."); } $term = $matches[1]; $strtotimeExp = ''; switch ($term) { case 'D': $strtotimeExp = 'days'; break; case 'T': $strtotimeExp = 'days'; break; case 'WD': $strtotimeExp = 'weekdays'; break; case 'WT': $strtotimeExp = 'weekdays'; break; case 'W': $strtotimeExp = 'weeks'; break; case 'M': $strtotimeExp = 'months'; break; case 'Q': $strtotimeExp = 'months'; break; //special case - calculation by consumer is necessary case 'Y': $strtotimeExp = 'years'; break; case 'J': $strtotimeExp = 'years'; break; } return $strtotimeExp; } /** * @param $week * @param $year * @return array */ public function getStartAndEndDateTimestampForWeek($week, $year) { $startDateTime = new \DateTime(); $startDateTime->setISODate($year, $week); $endDateTime = new \DateTime(); $endDateTime->setISODate($year, $week, 7); return array($startDateTime->getTimestamp(), $endDateTime->getTimestamp()); } /** * @param \DateTime $dateRef * @param string $direction */ public function mutateToClosestWorkDay(\DateTime $dateRef,$direction = '>') { $dateRefInitTimestamp = $dateRef->getTimestamp(); $dateRefInitDayOfWeek = date("N", $dateRefInitTimestamp); if($dateRefInitDayOfWeek <= 5) { return; } else { $targetTimestamp = strtotime('+1 weekdays',$dateRefInitTimestamp); if($direction === '<') { $targetTimestamp = strtotime('+1 weekdays',$dateRefInitTimestamp); } $dateRef->setTimestamp($targetTimestamp); } } }