Current Path : /var/www/www-root/data/www/monolith-realty.ru/bitrix/modules/main/lib/text/ |
Current File : /var/www/www-root/data/www/monolith-realty.ru/bitrix/modules/main/lib/text/dateconverter.php |
<?php namespace Bitrix\Main\Text; use Bitrix\Main\Localization\Loc as Loc; class DateConverter { /** * Creates Date object from Text (return array of result object) * * Examples: "end of next week", "tomorrow morning", "friday 25.10" * * @param string $text * @param integer $limit * @return \Bitrix\Main\Text\DateConverterResult[] */ public static function decode($text, $limit = 0) { $result = Array(); if ($text == '') { return $result; } $metrics = Array(); $date = new \Bitrix\Main\Type\DateTime(); if ($limit > 0 && mb_strlen($text) > $limit) { $text = mb_substr($text, 0, $limit); } $originalText = $text; $text = mb_strtolower($text); $workTimeStart = explode('.', \Bitrix\Main\Config\Option::get('calendar', 'work_time_start', '9')); $timeOfStartDate = str_pad(intval($workTimeStart[0] ?? 0), 2, "0", STR_PAD_LEFT).':'.str_pad(intval($workTimeStart[1] ?? 0), 2, "0", STR_PAD_LEFT); $workTimeEnd = explode('.', \Bitrix\Main\Config\Option::get('calendar', 'work_time_end', '18')); $timeOfEndDate = str_pad(intval($workTimeEnd[0] ?? 0), 2, "0", STR_PAD_LEFT).':'.str_pad(intval($workTimeEnd[1] ?? 0), 2, "0", STR_PAD_LEFT); $defaultPregExceptionSearch = Array('.', '/', '-', ':'); $defaultPregExceptionReplace = Array('\.', '\/', '\-', '\:'); // metric 1: near date $pattern = Array(); for ($i = 1; $i <= 11; $i++) { $pattern[$i] = mb_strtolower(Loc::getMessage("MAIN_TDC_METRIC_1_".$i)); $pattern[$i] = $pattern[$i] <> ''? $pattern[$i]: 'bxt2dmetricskip'; $pattern[$i] = str_replace($defaultPregExceptionSearch, $defaultPregExceptionReplace, $pattern[$i]); } if (preg_match_all("/(".implode('|', $pattern).")/", $text, $match, PREG_OFFSET_CAPTURE)) { foreach ($match[0] as $matchPattern) { $matchType = ''; switch($matchPattern[0]) { case $pattern[1]: $matchType = 'DAYAFTERTOMORROW'; break; case $pattern[2]: $matchType = 'TOMORROW'; break; case $pattern[3]: $matchType = 'TODAY'; break; case $pattern[4]: $matchType = 'YESTERDAY'; break; case $pattern[5]: $matchType = 'DAYBEFOREYESTERDAY'; break; case $pattern[9]: $matchType = 'WEEK'; break; case $pattern[10]: $matchType = 'WEEKEND'; break; case $pattern[11]: $matchType = 'MONTH'; break; } if ($matchType <> '') { $position = defined("BX_UTF")? mb_strlen(substr($text, 0, $matchPattern[1])) : $matchPattern[1]; $matchWord = self::getMatchWord($originalText, $position); $metrics[1][] = Array( 'TYPE' => $matchType, 'COUNT' => mb_strlen($matchWord), 'POSITION' => $position, 'MATCH' => $matchWord ); } } } // metric 2: day of weeks $pattern = Array(); for ($i = 1; $i <= 10; $i++) { $pattern[$i] = mb_strtolower(Loc::getMessage("MAIN_TDC_METRIC_2_".$i)); $pattern[$i] = $pattern[$i] <> ''? $pattern[$i]: 'bxt2dmetricskip'; $pattern[$i] = str_replace($defaultPregExceptionSearch, $defaultPregExceptionReplace, $pattern[$i]); } if (preg_match_all("/(".implode('|', $pattern).")/", $text, $match, PREG_OFFSET_CAPTURE)) { foreach ($match[0] as $matchPattern) { $matchType = ''; switch($matchPattern[0]) { case $pattern[1]: $matchType = 'MONDAY'; if (is_array($metrics[1])) { foreach ($metrics[1] as $key => $metric) { if ($metric['TYPE'] == 'WEEK') { $position = defined("BX_UTF")? mb_strlen(substr($text, 0, $matchPattern[1])) : $matchPattern[1]; $matchWord = self::getMatchWord($originalText, $position); if ($matchPattern[1] < $metric['POSITION'] && $matchPattern[1] + mb_strlen($matchWord) >= $metric['POSITION'] + $metric['COUNT']) { unset($metrics[1][$key]); if (empty($metrics[1])) { unset($metrics[1]); } } } } } break; case $pattern[2]: $matchType = 'TUESDAY'; break; case $pattern[3]: case $pattern[4]: case $pattern[5]: $matchType = 'WEDNESDAY'; break; case $pattern[6]: $matchType = 'THURSDAY'; break; case $pattern[7]: $matchType = 'FRIDAY'; break; case $pattern[8]: $matchType = 'SATURDAY'; break; case $pattern[9]: case $pattern[10]: $matchType = 'SUNDAY'; break; } if ($matchType <> '') { $position = defined("BX_UTF")? mb_strlen(substr($text, 0, $matchPattern[1])) : $matchPattern[1]; $matchWord = self::getMatchWord($originalText, $position); $metrics[2][] = Array( 'TYPE' => $matchType, 'COUNT' => mb_strlen($matchWord), 'POSITION' => $position, 'MATCH' => $matchWord ); } } } // metric 3: modificators before/after and time $pattern = Array(); for ($i = 1; $i <= 9; $i++) { $pattern[$i] = mb_strtolower(Loc::getMessage("MAIN_TDC_METRIC_3_".$i)); $pattern[$i] = $pattern[$i] <> ''? $pattern[$i]: 'bxt2dmetricskip'; $pattern[$i] = str_replace($defaultPregExceptionSearch, $defaultPregExceptionReplace, $pattern[$i]); } if (preg_match_all("/(".implode('|', $pattern).")/", $text, $match, PREG_OFFSET_CAPTURE)) { foreach ($match[0] as $matchPattern) { $matchType = ''; switch($matchPattern[0]) { case $pattern[1]: $matchType = 'BEFORE'; break; case $pattern[2]: $matchType = 'AFTER'; break; case $pattern[3]: $matchType = 'NEXT'; break; case $pattern[4]: $matchType = 'PREVIOUS'; break; case $pattern[5]: case $pattern[6]: $matchType = 'ENDOF'; break; case $pattern[7]: $matchType = 'MIDDLEOF'; break; case $pattern[8]: $matchType = 'STARTOF'; break; case $pattern[9]: case $pattern[10]: $matchType = 'THIS'; break; } if (in_array($matchType, Array('BEFORE', 'AFTER')) && isset($metrics[1])) { foreach ($metrics[1] as $key => $metric) { if (in_array($metric['TYPE'], Array('DAYAFTERTOMORROW', 'DAYBEFOREYESTERDAY'))) { if ($metric['POSITION'] == $matchPattern[1]) { $matchType = ''; } } else if (in_array($metric['TYPE'], Array('TOMORROW', 'YESTERDAY'))) { if ($metric['POSITION'] == $matchPattern[1] + mb_strlen($matchPattern[0])+1) { if ($metric['TYPE'] == 'TOMORROW') { $metrics[1][$key]['TYPE'] = $matchType == 'AFTER'? 'DAYAFTERTOMORROW': 'TODAY'; } else { $metrics[1][$key]['TYPE'] = $matchType == 'AFTER'? 'TODAY': 'DAYBEFOREYESTERDAY'; } $matchType = ''; } } } } if ($matchType <> '') { $position = defined("BX_UTF")? mb_strlen(substr($text, 0, $matchPattern[1])) : $matchPattern[1]; $matchWord = self::getMatchWord($originalText, $position); $metrics[3][] = Array( 'TYPE' => $matchType, 'COUNT' => mb_strlen($matchWord), 'POSITION' => $position, 'MATCH' => $matchWord ); } } } if (preg_match_all("/([0-2][0-9]:[0-5][0-9])/", $text, $match, PREG_OFFSET_CAPTURE)) { foreach ($match[0] as $matchPattern) { $position = defined("BX_UTF")? mb_strlen(substr($text, 0, $matchPattern[1])) : $matchPattern[1]; $matchWord = self::getMatchWord($originalText, $position); $metrics[3][] = Array( 'TYPE' => 'HHMM', 'VALUE' => $matchPattern[0], 'COUNT' => mb_strlen($matchPattern[0]), 'POSITION' => $position, 'MATCH' => $matchWord ); } } // metric 4: date $pattern = Array(); $patternOriginal = Array(); $patternLength = Array(); for ($i = 1; $i <= 3; $i++) { $patternOriginal[$i] = mb_strtolower(Loc::getMessage("MAIN_TDC_METRIC_4_".$i)); $patternOriginal[$i] = $patternOriginal[$i] <> ''? $patternOriginal[$i]: 'bxt2dmetricskip'; $patternLength[$i] = mb_strlen($patternOriginal[$i]); if ($patternOriginal[$i] != 'bxt2dmetricskip') { $pattern[$i] = str_replace($defaultPregExceptionSearch, $defaultPregExceptionReplace, $patternOriginal[$i]); $pattern[$i] = str_replace( Array('yyyy', 'yy', 'mm', 'dd'), Array('[1-2][0-9][0-9][0-9]', '[0-9][0-9]', '[0-1][0-9]', '[0-3][0-9]'), $pattern[$i] ); $pattern[$i] = '^(?>[\s|\t]?)('.$pattern[$i].')|[\s|^|\t]('.$pattern[$i].')(?=[\s|$|\r|\t])'; } } if (preg_match_all("/".implode('|', $pattern)."/", $text, $match, PREG_OFFSET_CAPTURE)) { $count = count($match)-1; for ($i = 1; $i <= $count; $i++) { foreach ($match[$i] as $matchPattern) { if (!$matchPattern[0]) { continue; } $matchType = ''; $matchLength = ''; switch(mb_strlen($matchPattern[0])) { case $patternLength[1]: $matchType = 'DDMMYYYY'; $matchYear = mb_substr($matchPattern[0], mb_strpos($patternOriginal[1], 'yyyy'), 4); $matchMonth = mb_substr($matchPattern[0], mb_strpos($patternOriginal[1], 'mm'), 2); $matchDay = mb_substr($matchPattern[0], mb_strpos($patternOriginal[1], 'dd'), 2); $matchPattern[0] = $matchYear.'-'.$matchMonth.'-'.$matchDay; $matchLength = $patternLength[1]; break; case $patternLength[2]: $matchType = 'DDMMYY'; $matchYear = mb_substr($matchPattern[0], mb_strpos($patternOriginal[2], 'yy'), 2); $matchMonth = mb_substr($matchPattern[0], mb_strpos($patternOriginal[2], 'mm'), 2); $matchDay = mb_substr($matchPattern[0], mb_strpos($patternOriginal[2], 'dd'), 2); $matchPattern[0] = '20'.$matchYear.'-'.$matchMonth.'-'.$matchDay; $matchLength = $patternLength[2]; break; case $patternLength[3]: $matchType = 'DDMM'; $matchMonth = mb_substr($matchPattern[0], mb_strpos($patternOriginal[3], 'mm'), 2); $matchDay = mb_substr($matchPattern[0], mb_strpos($patternOriginal[3], 'dd'), 2); $matchPattern[0] = $date->format('Y').'-'.$matchMonth.'-'.$matchDay; $matchLength = $patternLength[3]; break; } $position = defined("BX_UTF")? mb_strlen(substr($text, 0, $matchPattern[1])) : $matchPattern[1]; $matchWord = mb_substr($originalText, $position, $matchLength); $metrics[4][] = Array( 'TYPE' => $matchType, 'VALUE' => $matchPattern[0], 'COUNT' => $matchLength, 'POSITION' => $position, 'MATCH' => $matchWord ); } } } // metric 5: modificators of time $pattern = Array(); for ($i = 1; $i <= 5; $i++) { $pattern[$i] = mb_strtolower(Loc::getMessage("MAIN_TDC_METRIC_5_".$i)); $pattern[$i] = $pattern[$i] <> ''? $pattern[$i]: 'bxt2dmetricskip'; $pattern[$i] = str_replace($defaultPregExceptionSearch, $defaultPregExceptionReplace, $pattern[$i]); } if (preg_match_all("/(".implode('|', $pattern).")/", $text, $match, PREG_OFFSET_CAPTURE)) { foreach ($match[0] as $matchPattern) { $matchType = ''; $matchValue = ''; switch($matchPattern[0]) { case $pattern[1]: $matchType = 'MORNING'; $matchValue = $timeOfStartDate; break; case $pattern[2]: $matchType = 'LUNCH'; $matchValue = '14:00'; break; case $pattern[3]: break; case $pattern[4]: $matchType = 'WORKDAY'; $matchValue = $timeOfEndDate; if (isset($metrics[1])) { foreach ($metrics[1] as $key => $metric) { if ($metric['TYPE'] == 'TODAY') { if ($metric['POSITION'] == $matchPattern[1] + mb_strlen($matchPattern[3])) { $matchType = ''; } } } } break; case $pattern[5]: $matchType = 'EVENING'; $matchValue = '20:00'; break; } if ($matchType <> '') { $position = defined("BX_UTF")? mb_strlen(substr($text, 0, $matchPattern[1])) : $matchPattern[1]; $matchWord = self::getMatchWord($originalText, $position); $metrics[5][] = Array( 'TYPE' => $matchType, 'VALUE' => $matchValue, 'COUNT' => mb_strlen($matchWord), 'POSITION' => $position, 'MATCH' => $matchWord ); } } } $countOfMetrics = 0; foreach ($metrics as $values) { if (!empty($values)) { $countOfMetrics++; } } $useDefault = false; if ($countOfMetrics == 1 && (isset($metrics[3]) || isset($metrics[5]))) {} else if ($countOfMetrics == 1) { $useDefault = true; } else if ($countOfMetrics == 2 && isset($metrics[3])) { $useDefault = !isset($metrics[5]); } else if ($countOfMetrics == 2 && isset($metrics[5]) && (isset($metrics[1]) || isset($metrics[2]) || isset($metrics[4]))) { if (isset($metrics[1])) { foreach ($metrics[1] as $metric) { $progressDate = self::createDateUsingMetrics(1, $metric, $metrics[5]); $matchParams = self::getTextForReplace($originalText, $metric, $metrics[5]); $result[] = new DateConverterResult($progressDate, $matchParams, DateConverterResult::TYPE_RELATIVE, $metric, $metrics[5]); } } else if (isset($metrics[2])) { foreach ($metrics[2] as $metric) { $progressDate = self::createDateUsingMetrics(2, $metric, $metrics[5]); $matchParams = self::getTextForReplace($originalText, $metric, $metrics[5]); $result[] = new DateConverterResult($progressDate, $matchParams, DateConverterResult::TYPE_DAYOFWEEK, $metric, $metrics[5]); } } else if (isset($metrics[4])) { foreach ($metrics[4] as $metric) { $progressDate = self::createDateUsingMetrics(4, $metric, $metrics[5]); $matchParams = self::getTextForReplace($originalText, $metric, $metrics[5]); $result[] = new DateConverterResult($progressDate, $matchParams, DateConverterResult::TYPE_CALENDAR, $metric, $metrics[5]); } } } else if ($countOfMetrics == 2 && isset($metrics[1]) && (isset($metrics[2]) || isset($metrics[4]))) { if (isset($metrics[2])) { foreach ($metrics[2] as $metric) { $array = array(); $progressDate = self::createDateUsingMetrics(2, $metric, $array); $matchParams = self::getTextForReplace($originalText, $metric, array()); $result[] = new DateConverterResult($progressDate, $matchParams, DateConverterResult::TYPE_DAYOFWEEK, $metric); } } elseif (isset($metrics[4])) { foreach ($metrics[4] as $metric) { $array = array(); $progressDate = self::createDateUsingMetrics(4, $metric, $array); $matchParams = self::getTextForReplace($originalText, $metric, array()); $result[] = new DateConverterResult($progressDate, $matchParams, DateConverterResult::TYPE_CALENDAR, $metric); } } } else { $useDefault = true; } if ($useDefault) { $modificators = $metrics[3] ?? array(); if (isset($metrics[4]) && count($metrics[4])) { foreach ($metrics[4] as $metric) { $progressDate = self::createDateUsingMetrics(4, $metric, $modificators); $matchParams = self::getTextForReplace($originalText, $metric, $modificators); $result[] = new DateConverterResult($progressDate, $matchParams, DateConverterResult::TYPE_CALENDAR, $metric, $modificators); } } else if (isset($metrics[2]) && count($metrics[2])) { foreach ($metrics[2] as $metric) { $progressDate = self::createDateUsingMetrics(2, $metric, $modificators); $matchParams = self::getTextForReplace($originalText, $metric, $modificators); $result[] = new DateConverterResult($progressDate, $matchParams, DateConverterResult::TYPE_DAYOFWEEK, $metric, $modificators); } } else if (isset($metrics[1]) && count($metrics[1])) { foreach ($metrics[1] as $metric) { $progressDate = self::createDateUsingMetrics(1, $metric, $modificators); $matchParams = self::getTextForReplace($originalText, $metric, $modificators); $result[] = new DateConverterResult($progressDate, $matchParams, DateConverterResult::TYPE_RELATIVE, $metric, $modificators); } } else if (isset($metrics[5]) && count($metrics[5])) { foreach ($metrics[5] as $metric) { $progressDate = self::createDateUsingMetrics(5, $metric, $modificators); $matchParams = self::getTextForReplace($originalText, $metric, $modificators); $result[] = new DateConverterResult($progressDate, $matchParams, DateConverterResult::TYPE_PARTOFDAY, $metric, $modificators); } } else if (isset($metrics[3]) && count($metrics[3])) { foreach ($metrics[3] as $metric) { $array = array(); $progressDate = self::createDateUsingMetrics(3, $metric, $array); $matchParams = self::getTextForReplace($originalText, $metric, $modificators); $result[] = new DateConverterResult($progressDate, $matchParams, DateConverterResult::TYPE_MODIFIER, $metric); } } } return $result; } /** * Creates Date object from metrics (private method for self::decode) * * @param int $type Type of metric * @param array $metric Params of metric * @param array $metricModificator List of metric modificators * @param \Bitrix\Main\Type\DateTime $date If not specified, the modified date is got from the current date. * @return \Bitrix\Main\Type\DateTime * */ private static function createDateUsingMetrics($type, $metric, &$metricModificator = array(), \Bitrix\Main\Type\DateTime $date = null) { $defaultDate = $date? $date: new \Bitrix\Main\Type\DateTime(); $metricModificator = is_array($metricModificator)? $metricModificator: array(); $workTimeStart = explode('.', \Bitrix\Main\Config\Option::get('calendar', 'work_time_start', '9')); $timeOfStartDate = str_pad(intval($workTimeStart[0]), 2, "0", STR_PAD_LEFT).':'.str_pad(intval($workTimeStart[1] ?? 0), 2, "0", STR_PAD_LEFT); $workTimeEnd = explode('.', \Bitrix\Main\Config\Option::get('calendar', 'work_time_end', '18')); $timeOfEndDate = str_pad(intval($workTimeEnd[0]), 2, "0", STR_PAD_LEFT).':'.str_pad(intval($workTimeEnd[1] ?? 0), 2, "0", STR_PAD_LEFT); $result = null; switch($type) { case 1: $metricDate = $defaultDate; switch($metric['TYPE']) { case 'DAYAFTERTOMORROW': $metricDate->add('TOMORROW')->add('TOMORROW'); break; case 'TOMORROW': $metricDate->add('TOMORROW'); break; case 'YESTERDAY': $metricDate->add('YESTERDAY'); break; case 'DAYBEFOREYESTERDAY': $metricDate->add('YESTERDAY')->add('YESTERDAY'); break; } $modificator = ''; $metricTime = $timeOfEndDate; $metricModificator = self::checkModifierPosition($metric, $metricModificator); foreach ($metricModificator as $currentModificator) { if ($metric['TYPE'] == 'WEEK') { if (in_array($currentModificator['TYPE'], Array('BEFORE', 'PREVIOUS'))) { $metricDate->add('-1 WEEK'); } else if (in_array($currentModificator['TYPE'], Array('AFTER', 'NEXT'))) { $metricDate->add('1 WEEK'); } else if ($currentModificator['TYPE'] == 'MIDDLEOF') { $metricDate = self::getDateOfDayOfCurrentWeek('WEDNESDAY', $metricDate); $modificator = true; } else if ($currentModificator['TYPE'] == 'STARTOF') { $metricDate = self::getDateOfDayOfCurrentWeek('MONDAY', $metricDate); $modificator = true; } else if ($currentModificator['TYPE'] == 'ENDOF') { $metricDate = self::getDateOfDayOfCurrentWeek('FRIDAY', $metricDate); $modificator = true; } } else if ($metric['TYPE'] == 'WEEKEND') { if (in_array($currentModificator['TYPE'], Array('BEFORE'))) { $metricDate = self::getDateOfDayOfCurrentWeek('SATURDAY', $metricDate); $metricDate->add('-1 DAY'); $modificator = true; } else if (in_array($currentModificator['TYPE'], Array('PREVIOUS'))) { $metricDate->add('-1 WEEK'); $metricDate = self::getDateOfDayOfCurrentWeek('SATURDAY', $metricDate); $modificator = true; } else if (in_array($currentModificator['TYPE'], Array('NEXT'))) { $metricDate->add('1 WEEK'); $metricDate = self::getDateOfDayOfCurrentWeek('SATURDAY', $metricDate); $modificator = true; } else if (in_array($currentModificator['TYPE'], Array('AFTER'))) { $metricDate = self::getDateOfDayOfCurrentWeek('SUNDAY', $metricDate); $metricDate->add('1 DAY'); $modificator = true; } else if ($currentModificator['TYPE'] == 'MIDDLEOF') { $metricDate = self::getDateOfDayOfCurrentWeek('SATURDAY', $metricDate); $modificator = true; } else if ($currentModificator['TYPE'] == 'STARTOF') { $metricDate = self::getDateOfDayOfCurrentWeek('SATURDAY', $metricDate); $metricTime = $timeOfStartDate; $modificator = true; } else if ($currentModificator['TYPE'] == 'ENDOF') { $metricDate = self::getDateOfDayOfCurrentWeek('SUNDAY', $metricDate); $modificator = true; } } else if ($metric['TYPE'] == 'MONTH') { if (in_array($currentModificator['TYPE'], Array('BEFORE', 'PREVIOUS'))) { $metricDate->add('-1 MONTH'); $numberOfMonth = $metricDate->format('t'); $metricDate = new \Bitrix\Main\Type\DateTime($metricDate->format('Y-m').'-'.$numberOfMonth.' '.$timeOfEndDate.':00', 'Y-m-d H:i:s'); $modificator = true; } else if (in_array($currentModificator['TYPE'], Array('AFTER', 'NEXT'))) { $metricDate->add('1 MONTH'); $numberOfMonth = $metricDate->format('t'); $metricDate = new \Bitrix\Main\Type\DateTime($metricDate->format('Y-m').'-'.$numberOfMonth.' '.$timeOfEndDate.':00', 'Y-m-d H:i:s'); $modificator = true; } else if ($currentModificator['TYPE'] == 'MIDDLEOF') { $numberOfHalfMonth = ceil($metricDate->format('t')/2); $metricDate = new \Bitrix\Main\Type\DateTime($metricDate->format('Y-m').'-'.$numberOfHalfMonth.' '.$timeOfEndDate.':00', 'Y-m-d H:i:s'); $modificator = true; } else if ($currentModificator['TYPE'] == 'STARTOF') { $metricDate = new \Bitrix\Main\Type\DateTime($metricDate->format('Y-m').'-01 '.$timeOfStartDate.':00', 'Y-m-d H:i:s'); $modificator = true; } else if ($currentModificator['TYPE'] == 'ENDOF') { $numberOfMonth = $metricDate->format('t'); $metricDate = new \Bitrix\Main\Type\DateTime($metricDate->format('Y-m').'-'.$numberOfMonth.' '.$timeOfEndDate.':00', 'Y-m-d H:i:s'); $modificator = true; } } else { if (in_array($currentModificator['TYPE'], Array('BEFORE', 'PREVIOUS'))) { $metricDate->add('-1 DAY'); } else if (in_array($currentModificator['TYPE'], Array('AFTER', 'NEXT'))) { $metricDate->add('1 DAY'); } else if ($currentModificator['TYPE'] == 'MIDDLEOF') { $metricTime = '14:00'; } else if ($currentModificator['TYPE'] == 'STARTOF') { $metricTime = $timeOfStartDate; } $modificator = true; } if (in_array($currentModificator['TYPE'], Array('MORNING', 'LUNCH', 'EVENING', 'HHMM'))) { $metricTime = $currentModificator['VALUE']; $modificator = true; } } if (!$modificator) { if ($metric['TYPE'] == 'WEEK') { if ($metricDate->format('N') == 3) { $metricDate->add('FRIDAY'); } else if ($metricDate->format('N') < 3) { $metricDate->add('THURSDAY'); } else if ($metricDate->format('N') != 7) { $metricDate->add('SUNDAY'); } } else if ($metric['TYPE'] == 'WEEKEND') { if (strtolower($metricDate->format('l')) == 'saturday') $metricDate->add('SUNDAY'); else if (strtolower($metricDate->format('l')) != 'sunday') $metricDate->add('SATURDAY'); } else if ($metric['TYPE'] == 'MONTH') { $numberOfMonth = $metricDate->format('j'); if ($numberOfMonth > 15) { $plus = $metricDate->format('t')-$numberOfMonth; if ($plus >= 1) { $metricDate->add($plus.' DAY'); } } elseif ($numberOfMonth >= 10) { $plus = 20-$numberOfMonth; $metricDate->add($plus.' DAY'); } else { $plus = 15-$numberOfMonth; $metricDate->add($plus.' DAY'); } } } $result = new \Bitrix\Main\Type\DateTime($metricDate->format('Y-m-d').' '.$metricTime.':00', 'Y-m-d H:i:s'); break; case 2: $metricDate = $defaultDate; $modificator = ''; $metricTime = $timeOfEndDate; $metricModificator = self::checkModifierPosition($metric, $metricModificator); foreach ($metricModificator as $currentModificator) { $metricDate = self::getDateOfDayOfCurrentWeek($metric['TYPE'], $metricDate); if ($currentModificator['TYPE'] == 'BEFORE') { $metricDate->add('-1 DAY'); } else if ($currentModificator['TYPE'] == 'AFTER') { $metricDate->add('1 DAY'); } else if ($currentModificator['TYPE'] == 'THIS') { $metricDate->add('LAST '.$metric['TYPE']); } else if (in_array($currentModificator['TYPE'], Array('NEXT', 'PREVIOUS'))) { if ($currentModificator['TYPE'] == 'NEXT') { $metricDate->add('NEXT '.$metric['TYPE']); } else { $metricDate->add('PREVIOUS '.$metric['TYPE']); } } else if ($currentModificator['TYPE'] == 'MIDDLEOF') { $metricTime = '14:00'; } else if ($currentModificator['TYPE'] == 'STARTOF') { $metricTime = $timeOfStartDate; } else if (in_array($currentModificator['TYPE'], Array('MORNING', 'LUNCH', 'EVENING', 'HHMM'))) { $metricTime = $currentModificator['VALUE']; } $modificator = true; } if (!$modificator) { $modificator = strtolower($metric['TYPE']) == strtolower($metricDate->format('l'))? 'NEXT ': ''; $metricDate->add($modificator.$metric['TYPE']); } $result = new \Bitrix\Main\Type\DateTime($metricDate->format('Y-m-d').' '.$metricTime.':00', 'Y-m-d H:i:s'); break; case 3: $metricDate = $defaultDate; $metricTime = $timeOfEndDate; switch($metric['TYPE']) { case 'BEFORE': $metricDate->add('TOMORROW')->add('TOMORROW'); break; case 'AFTER': $metricDate->add('TOMORROW'); break; case 'NEXT': $metricDate->add('YESTERDAY'); break; case 'PREVIOUS': $metricDate->add('YESTERDAY')->add('YESTERDAY'); break; case 'MIDDLEOF': $metricTime = '14:00'; break; case 'STARTOF': $metricTime = $timeOfStartDate; break; case 'HHMM': $metricTime = $metric['VALUE']; break; } $result = new \Bitrix\Main\Type\DateTime($metricDate->format('Y-m-d').' '.$metricTime.':00', 'Y-m-d H:i:s'); break; case 4: $modificator = ''; $metricTime = $timeOfEndDate; $metricModificator = self::checkModifierPosition($metric, $metricModificator); foreach ($metricModificator as $currentModificator) { if (in_array($currentModificator['TYPE'], Array('MORNING', 'LUNCH', 'EVENING', 'HHMM'))) { $metricTime = $currentModificator['VALUE']; } } $result = new \Bitrix\Main\Type\DateTime($metric['VALUE'].' '.$metricTime.':00', 'Y-m-d H:i:s'); break; case 5: $metricDate = $defaultDate; $modificator = ''; $metricTime = $metric['VALUE']; $metricModificator = self::checkModifierPosition($metric, $metricModificator); foreach ($metricModificator as $currentModificator) { if ($currentModificator['TYPE'] == 'BEFORE') { $metricDate->add('-1 DAY'); } else if ($currentModificator['TYPE'] == 'AFTER') { $metricDate->add('1 DAY'); } else if (in_array($currentModificator['TYPE'], Array('NEXT', 'PREVIOUS'))) { if ($currentModificator['TYPE'] == 'NEXT') { $metricDate->add('NEXT '.$metric['TYPE']); } else { $metricDate->add('PREVIOUS '.$metric['TYPE']); } } else if ($currentModificator['TYPE'] == 'MIDDLEOF') { $metricTime = '14:00'; } else if ($currentModificator['TYPE'] == 'STARTOF') { $metricTime = $timeOfStartDate; } else if (in_array($currentModificator['TYPE'], Array('MORNING', 'LUNCH', 'EVENING', 'HHMM'))) { $metricTime = $currentModificator['VALUE']; } $modificator = true; } if (!$modificator) { $modificator = strtolower($metric['TYPE']) == strtolower($metricDate->format('l'))? 'NEXT ': ''; $metricDate->add($modificator.$metric['TYPE']); } $result = new \Bitrix\Main\Type\DateTime($metricDate->format('Y-m-d').' '.$metricTime.':00', 'Y-m-d H:i:s'); break; } return $result; } /** * Creates Date object of the day of the method week (private function for self::createDateUsingMetrics) * * @param string $nameOfday name of the day (monday, tuesday, etc) * @param \Bitrix\Main\Type\DateTime $date If not specified, the modified date is got from the current date. * @return \Bitrix\Main\Type\DateTime * */ private static function getDateOfDayOfCurrentWeek($nameOfday, \Bitrix\Main\Type\DateTime $date = null) { $date = $date? $date: new \Bitrix\Main\Type\DateTime(); $nameOfday = mb_strtoupper($nameOfday); if (!in_array($nameOfday, Array('MONDAY', 'TUESDAY', 'WEDNESDAY', 'THURSDAY', 'FRIDAY', 'SATURDAY', 'SUNDAY'))) return false; $relation = ''; $day = $date->format('N'); if ( $nameOfday == 'MONDAY' && $day == 1 || $nameOfday == 'TUESDAY' && $day <= 2 || $nameOfday == 'WEDNESDAY' && $day <= 3 || $nameOfday == 'THURSDAY' && $day <= 4 || $nameOfday == 'FRIDAY' && $day <= 5 || $nameOfday == 'SATURDAY' && $day <= 6 || $nameOfday == 'SUNDAY' && $day <= 7 ) { $relation = 'THIS'; } $date->add($relation.' '.$nameOfday); return $date; } /** * @param $text * @param $position * @return string */ private static function getMatchWord($text, $position) { $letters = array_merge(Array(" ", "\n", "\t", "\r"), str_split('"-.,?!#$%^&*();:<>\|{}-=^@[]`')); $spaceFound = self::findFirstOccurrence($text, $letters, $position); if ($spaceFound !== false) { $result = mb_substr($text, $position, $spaceFound - $position); } else { $result = mb_substr($text, $position); } return $result; } private static function getTextForReplace($text, $metrics, $metricModifier) { $found = false; $minStartPosition = null; $maxEndPosition = null; if (!empty($metrics)) { $minStartPosition = $metrics['POSITION']; $maxEndPosition = $metrics['POSITION'] + $metrics['COUNT']; $found = true; } if (is_array($metricModifier)) { foreach ($metricModifier as $metrics) { if (!$found) { $minStartPosition = $metrics['POSITION']; $maxEndPosition = $metrics['POSITION'] + $metrics['COUNT']; $found = true; } else { if ($minStartPosition > $metrics['POSITION']) { $minStartPosition = $metrics['POSITION']; } if ($maxEndPosition < $metrics['POSITION'] + $metrics['COUNT']) { $maxEndPosition = $metrics['POSITION'] + $metrics['COUNT']; } } } } if (is_null($minStartPosition) || is_null($maxEndPosition)) { $result = false; } else { $result = mb_substr($text, $minStartPosition, $maxEndPosition - $minStartPosition); $result = Array('TEXT' => $result, 'POSITION' => $minStartPosition, 'LENGTH' => mb_strlen($result)); } return $result; } private static function checkModifierPosition($metrics, $metricModifier) { $newMetrics = $metrics; $stackMetrics = Array(); $while = true; $maxWhile = 100; while ($while && $maxWhile > 0) { $while = false; foreach ($metricModifier as $key => $currentModificator) { $diffResult = abs($newMetrics['POSITION'] - ($currentModificator['POSITION'] + $currentModificator['COUNT'])); if ($diffResult < 5) { $while = true; $newMetrics = $currentModificator; $stackMetrics[] = $currentModificator; unset($metricModifier[$key]); } else { $diffResult = abs($newMetrics['POSITION']+$newMetrics['COUNT'] - ($currentModificator['POSITION'])); if ($diffResult < 5) { $while = true; $newMetrics = $currentModificator; $stackMetrics[] = $currentModificator; unset($metricModifier[$key]); } } } $maxWhile--; } return $stackMetrics; } private static function findFirstOccurrence($haystack, $needle, $offset=0) { $haystack = mb_substr($haystack, 0, 25 + $offset); if(!is_array($needle)) { $needle = array($needle); } $positions = array(); if ($offset < mb_strlen($haystack)) { foreach ($needle as $query) { $result = mb_strpos($haystack, $query, $offset); if ($result !== false) { $positions[] = $result; } } } return empty($positions)? false: min($positions); } }