Bitrix-D7  20.5.0
dateconverter.php
См. документацию.
1 <?php
2 namespace Bitrix\Main\Text;
3 
5 
7 {
8  /**
9  * Creates Date object from Text (return array of result object)
10  *
11  * Examples: "end of next week", "tomorrow morning", "friday 25.10"
12  *
13  * @param string $text
14  * @param integer $limit
15  * @return \Bitrix\Main\Text\DateConverterResult[]
16  */
17  public static function decode($text, $limit = 0)
18  {
19  $result = Array();
20  if ($text == '')
21  {
22  return $result;
23  }
24 
25  $metrics = Array();
26  $date = new \Bitrix\Main\Type\DateTime();
27 
28  if ($limit > 0 && mb_strlen($text) > $limit)
29  {
30  $text = mb_substr($text, 0, $limit);
31  }
32 
33  $originalText = $text;
34  $text = ToLower($text);
35 
36  $workTimeStart = explode('.', \Bitrix\Main\Config\Option::get('calendar', 'work_time_start', '9'));
37  $timeOfStartDate = str_pad(intval($workTimeStart[0]), 2, "0", STR_PAD_LEFT).':'.str_pad(intval($workTimeStart[1]), 2, "0", STR_PAD_LEFT);
38 
39  $workTimeEnd = explode('.', \Bitrix\Main\Config\Option::get('calendar', 'work_time_end', '18'));
40  $timeOfEndDate = str_pad(intval($workTimeEnd[0]), 2, "0", STR_PAD_LEFT).':'.str_pad(intval($workTimeEnd[1]), 2, "0", STR_PAD_LEFT);
41 
42  $defaultPregExceptionSearch = Array('.', '/', '-', ':');
43  $defaultPregExceptionReplace = Array('\.', '\/', '\-', '\:');
44 
45  // metric 1: near date
46  $pattern = Array();
47  for ($i = 1; $i <= 11; $i++)
48  {
49  $pattern[$i] = ToLower(Loc::getMessage("MAIN_TDC_METRIC_1_".$i));
50  $pattern[$i] = $pattern[$i] <> ''? $pattern[$i]: 'bxt2dmetricskip';
51  $pattern[$i] = str_replace($defaultPregExceptionSearch, $defaultPregExceptionReplace, $pattern[$i]);
52  }
53  if (preg_match_all("/(".implode('|', $pattern).")/", $text, $match, PREG_OFFSET_CAPTURE))
54  {
55  foreach ($match[0] as $matchPattern)
56  {
57  $matchType = '';
58  switch($matchPattern[0])
59  {
60  case $pattern[1]:
61  $matchType = 'DAYAFTERTOMORROW';
62  break;
63  case $pattern[2]:
64  $matchType = 'TOMORROW';
65  break;
66  case $pattern[3]:
67  $matchType = 'TODAY';
68  break;
69  case $pattern[4]:
70  $matchType = 'YESTERDAY';
71  break;
72  case $pattern[5]:
73  $matchType = 'DAYBEFOREYESTERDAY';
74  break;
75  case $pattern[6]:
76  case $pattern[7]:
77  case $pattern[8]:
78  $matchType = '';
79  break;
80  case $pattern[9]:
81  $matchType = 'WEEK';
82  break;
83  case $pattern[10]:
84  $matchType = 'WEEKEND';
85  break;
86  case $pattern[11]:
87  $matchType = 'MONTH';
88  break;
89  }
90  if ($matchType <> '')
91  {
92  $position = defined("BX_UTF")? mb_strlen(substr($text, 0, $matchPattern[1])) : $matchPattern[1];
93  $matchWord = self::getMatchWord($originalText, $position);
94 
95  $metrics[1][] = Array(
96  'TYPE' => $matchType,
97  'COUNT' => mb_strlen($matchWord),
98  'POSITION' => $position,
99  'MATCH' => $matchWord
100  );
101  }
102  }
103  }
104 
105  // metric 2: day of weeks
106  $pattern = Array();
107  for ($i = 1; $i <= 10; $i++)
108  {
109  $pattern[$i] = ToLower(Loc::getMessage("MAIN_TDC_METRIC_2_".$i));
110  $pattern[$i] = $pattern[$i] <> ''? $pattern[$i]: 'bxt2dmetricskip';
111  $pattern[$i] = str_replace($defaultPregExceptionSearch, $defaultPregExceptionReplace, $pattern[$i]);
112  }
113  if (preg_match_all("/(".implode('|', $pattern).")/", $text, $match, PREG_OFFSET_CAPTURE))
114  {
115  foreach ($match[0] as $matchPattern)
116  {
117  $matchType = '';
118  switch($matchPattern[0])
119  {
120  case $pattern[1]:
121  $matchType = 'MONDAY';
122  if (is_array($metrics[1]))
123  {
124  foreach ($metrics[1] as $key => $metric)
125  {
126  if ($metric['TYPE'] == 'WEEK')
127  {
128  $position = defined("BX_UTF")? mb_strlen(substr($text, 0, $matchPattern[1])) : $matchPattern[1];
129  $matchWord = self::getMatchWord($originalText, $position);
130 
131  if ($matchPattern[1] < $metric['POSITION'] && $matchPattern[1] + mb_strlen($matchWord) >= $metric['POSITION'] + $metric['COUNT'])
132  {
133  unset($metrics[1][$key]);
134  if (count($metrics[1]) == 0)
135  {
136  unset($metrics[1]);
137  }
138  }
139  }
140  }
141  }
142  break;
143  case $pattern[2]:
144  $matchType = 'TUESDAY';
145  break;
146  case $pattern[3]:
147  case $pattern[4]:
148  case $pattern[5]:
149  $matchType = 'WEDNESDAY';
150  break;
151  case $pattern[6]:
152  $matchType = 'THURSDAY';
153  break;
154  case $pattern[7]:
155  $matchType = 'FRIDAY';
156  break;
157  case $pattern[8]:
158  $matchType = 'SATURDAY';
159  break;
160  case $pattern[9]:
161  case $pattern[10]:
162  $matchType = 'SUNDAY';
163  break;
164  }
165 
166  if ($matchType <> '')
167  {
168  $position = defined("BX_UTF")? mb_strlen(substr($text, 0, $matchPattern[1])) : $matchPattern[1];
169  $matchWord = self::getMatchWord($originalText, $position);
170 
171  $metrics[2][] = Array(
172  'TYPE' => $matchType,
173  'COUNT' => mb_strlen($matchWord),
174  'POSITION' => $position,
175  'MATCH' => $matchWord
176  );
177  }
178  }
179  }
180 
181  // metric 3: modificators before/after and time
182  $pattern = Array();
183  for ($i = 1; $i <= 9; $i++)
184  {
185  $pattern[$i] = ToLower(Loc::getMessage("MAIN_TDC_METRIC_3_".$i));
186  $pattern[$i] = $pattern[$i] <> ''? $pattern[$i]: 'bxt2dmetricskip';
187  $pattern[$i] = str_replace($defaultPregExceptionSearch, $defaultPregExceptionReplace, $pattern[$i]);
188  }
189  if (preg_match_all("/(".implode('|', $pattern).")/", $text, $match, PREG_OFFSET_CAPTURE))
190  {
191  foreach ($match[0] as $matchPattern)
192  {
193  $matchType = '';
194  switch($matchPattern[0])
195  {
196  case $pattern[1]:
197  $matchType = 'BEFORE';
198  break;
199  case $pattern[2]:
200  $matchType = 'AFTER';
201  break;
202  case $pattern[3]:
203  $matchType = 'NEXT';
204  break;
205  case $pattern[4]:
206  $matchType = 'PREVIOUS';
207  break;
208  case $pattern[5]:
209  case $pattern[6]:
210  $matchType = 'ENDOF';
211  break;
212  case $pattern[7]:
213  $matchType = 'MIDDLEOF';
214  break;
215  case $pattern[8]:
216  $matchType = 'STARTOF';
217  break;
218  case $pattern[9]:
219  case $pattern[10]:
220  $matchType = 'THIS';
221  break;
222  }
223 
224  if (in_array($matchType, Array('BEFORE', 'AFTER')) && isset($metrics[1]))
225  {
226  foreach ($metrics[1] as $key => $metric)
227  {
228  if (in_array($metric['TYPE'], Array('DAYAFTERTOMORROW', 'DAYBEFOREYESTERDAY')))
229  {
230  if ($metric['POSITION'] == $matchPattern[1])
231  {
232  $matchType = '';
233  }
234  }
235  else if (in_array($metric['TYPE'], Array('TOMORROW', 'YESTERDAY')))
236  {
237  if ($metric['POSITION'] == $matchPattern[1] + mb_strlen($matchPattern[0])+1)
238  {
239  if ($metric['TYPE'] == 'TOMORROW')
240  {
241  $metrics[1][$key]['TYPE'] = $matchType == 'AFTER'? 'DAYAFTERTOMORROW': 'TODAY';
242  }
243  else
244  {
245  $metrics[1][$key]['TYPE'] = $matchType == 'AFTER'? 'TODAY': 'DAYBEFOREYESTERDAY';
246  }
247  $matchType = '';
248  }
249  }
250  }
251  }
252 
253  if ($matchType <> '')
254  {
255  $position = defined("BX_UTF")? mb_strlen(substr($text, 0, $matchPattern[1])) : $matchPattern[1];
256  $matchWord = self::getMatchWord($originalText, $position);
257 
258  $metrics[3][] = Array(
259  'TYPE' => $matchType,
260  'COUNT' => mb_strlen($matchWord),
261  'POSITION' => $position,
262  'MATCH' => $matchWord
263  );
264  }
265  }
266  }
267  if (preg_match_all("/([0-2][0-9]:[0-5][0-9])/", $text, $match, PREG_OFFSET_CAPTURE))
268  {
269  foreach ($match[0] as $matchPattern)
270  {
271  $position = defined("BX_UTF")? mb_strlen(substr($text, 0, $matchPattern[1])) : $matchPattern[1];
272  $matchWord = self::getMatchWord($originalText, $position);
273 
274  $metrics[3][] = Array(
275  'TYPE' => 'HHMM',
276  'VALUE' => $matchPattern[0],
277  'COUNT' => mb_strlen($matchPattern[0]),
278  'POSITION' => $position,
279  'MATCH' => $matchWord
280  );
281  }
282  }
283 
284  // metric 4: date
285  $pattern = Array();
286  $patternOriginal = Array();
287  $patternLength = Array();
288  for ($i = 1; $i <= 3; $i++)
289  {
290  $patternOriginal[$i] = ToLower(Loc::getMessage("MAIN_TDC_METRIC_4_".$i));
291  $patternOriginal[$i] = $patternOriginal[$i] <> ''? $patternOriginal[$i]: 'bxt2dmetricskip';
292  $patternLength[$i] = mb_strlen($patternOriginal[$i]);
293  if ($patternOriginal[$i] != 'bxt2dmetricskip')
294  {
295  $pattern[$i] = str_replace($defaultPregExceptionSearch, $defaultPregExceptionReplace, $patternOriginal[$i]);
296  $pattern[$i] = str_replace(
297  Array('yyyy', 'yy', 'mm', 'dd'),
298  Array('[1-2][0-9][0-9][0-9]', '[0-9][0-9]', '[0-1][0-9]', '[0-3][0-9]'),
299  $pattern[$i]
300  );
301  $pattern[$i] = '^(?>[\s|\t]?)('.$pattern[$i].')|[\s|^|\t]('.$pattern[$i].')(?=[\s|$|\r|\t])';
302  }
303  }
304  if (preg_match_all("/".implode('|', $pattern)."/", $text, $match, PREG_OFFSET_CAPTURE))
305  {
306  $count = count($match)-1;
307  for ($i = 1; $i <= $count; $i++)
308  {
309  foreach ($match[$i] as $matchPattern)
310  {
311  if (!$matchPattern[0])
312  {
313  continue;
314  }
315 
316  $matchType = '';
317  $matchLength = '';
318  switch(mb_strlen($matchPattern[0]))
319  {
320  case $patternLength[1]:
321  $matchType = 'DDMMYYYY';
322  $matchYear = mb_substr($matchPattern[0], mb_strpos($patternOriginal[1], 'yyyy'), 4);
323  $matchMonth = mb_substr($matchPattern[0], mb_strpos($patternOriginal[1], 'mm'), 2);
324  $matchDay = mb_substr($matchPattern[0], mb_strpos($patternOriginal[1], 'dd'), 2);
325  $matchPattern[0] = $matchYear.'-'.$matchMonth.'-'.$matchDay;
326  $matchLength = $patternLength[1];
327  break;
328  case $patternLength[2]:
329  $matchType = 'DDMMYY';
330  $matchYear = mb_substr($matchPattern[0], mb_strpos($patternOriginal[2], 'yy'), 2);
331  $matchMonth = mb_substr($matchPattern[0], mb_strpos($patternOriginal[2], 'mm'), 2);
332  $matchDay = mb_substr($matchPattern[0], mb_strpos($patternOriginal[2], 'dd'), 2);
333  $matchPattern[0] = '20'.$matchYear.'-'.$matchMonth.'-'.$matchDay;
334  $matchLength = $patternLength[2];
335  break;
336  case $patternLength[3]:
337  $matchType = 'DDMM';
338  $matchMonth = mb_substr($matchPattern[0], mb_strpos($patternOriginal[3], 'mm'), 2);
339  $matchDay = mb_substr($matchPattern[0], mb_strpos($patternOriginal[3], 'dd'), 2);
340  $matchPattern[0] = $date->format('Y').'-'.$matchMonth.'-'.$matchDay;
341  $matchLength = $patternLength[3];
342  break;
343  }
344 
345  $position = defined("BX_UTF")? mb_strlen(substr($text, 0, $matchPattern[1])) : $matchPattern[1];
346  $matchWord = mb_substr($originalText, $position, $matchLength);
347 
348  $metrics[4][] = Array(
349  'TYPE' => $matchType,
350  'VALUE' => $matchPattern[0],
351  'COUNT' => $matchLength,
352  'POSITION' => $position,
353  'MATCH' => $matchWord
354  );
355  }
356  }
357  }
358 
359  // metric 5: modificators of time
360  $pattern = Array();
361  for ($i = 1; $i <= 5; $i++)
362  {
363  $pattern[$i] = ToLower(Loc::getMessage("MAIN_TDC_METRIC_5_".$i));
364  $pattern[$i] = $pattern[$i] <> ''? $pattern[$i]: 'bxt2dmetricskip';
365  $pattern[$i] = str_replace($defaultPregExceptionSearch, $defaultPregExceptionReplace, $pattern[$i]);
366  }
367  if (preg_match_all("/(".implode('|', $pattern).")/", $text, $match, PREG_OFFSET_CAPTURE))
368  {
369  foreach ($match[0] as $matchPattern)
370  {
371  $matchType = '';
372  $matchValue = '';
373  switch($matchPattern[0])
374  {
375  case $pattern[1]:
376  $matchType = 'MORNING';
377  $matchValue = $timeOfStartDate;
378  break;
379  case $pattern[2]:
380  $matchType = 'LUNCH';
381  $matchValue = '14:00';
382  break;
383  case $pattern[3]:
384  break;
385  case $pattern[4]:
386  $matchType = 'WORKDAY';
387  $matchValue = $timeOfEndDate;
388 
389  if (isset($metrics[1]))
390  {
391  foreach ($metrics[1] as $key => $metric)
392  {
393  if ($metric['TYPE'] == 'TODAY')
394  {
395  if ($metric['POSITION'] == $matchPattern[1] + mb_strlen($matchPattern[3]))
396  {
397  $matchType = '';
398  }
399  }
400  }
401  }
402  break;
403  case $pattern[5]:
404  $matchType = 'EVENING';
405  $matchValue = '20:00';
406  break;
407  }
408  if ($matchType <> '')
409  {
410  $position = defined("BX_UTF")? mb_strlen(substr($text, 0, $matchPattern[1])) : $matchPattern[1];
411  $matchWord = self::getMatchWord($originalText, $position);
412 
413  $metrics[5][] = Array(
414  'TYPE' => $matchType,
415  'VALUE' => $matchValue,
416  'COUNT' => mb_strlen($matchWord),
417  'POSITION' => $position,
418  'MATCH' => $matchWord
419  );
420  }
421  }
422  }
423 
424  $countOfMetrics = 0;
425  foreach ($metrics as $values)
426  {
427  if (count($values) > 0)
428  {
429  $countOfMetrics++;
430  }
431  }
432 
433  $useDefault = false;
434  if ($countOfMetrics == 1 && (isset($metrics[3]) || isset($metrics[5])))
435  {}
436  else if ($countOfMetrics == 1)
437  {
438  $useDefault = true;
439  }
440  else if ($countOfMetrics == 2 && isset($metrics[3]))
441  {
442  $useDefault = !isset($metrics[5]);
443  }
444  else if ($countOfMetrics == 2 && isset($metrics[5]) && (isset($metrics[1]) || isset($metrics[2]) || isset($metrics[4])))
445  {
446  if (isset($metrics[1]))
447  {
448  foreach ($metrics[1] as $metric)
449  {
450  $progressDate = self::createDateUsingMetrics(1, $metric, $metrics[5]);
451  $matchParams = self::getTextForReplace($originalText, $metric, $metrics[5]);
452  $result[] = new DateConverterResult($progressDate, $matchParams, DateConverterResult::TYPE_RELATIVE, $metric, $metrics[5]);
453  }
454  }
455  else if (isset($metrics[2]))
456  {
457  foreach ($metrics[2] as $metric)
458  {
459  $progressDate = self::createDateUsingMetrics(2, $metric, $metrics[5]);
460  $matchParams = self::getTextForReplace($originalText, $metric, $metrics[5]);
461  $result[] = new DateConverterResult($progressDate, $matchParams, DateConverterResult::TYPE_DAYOFWEEK, $metric, $metrics[5]);
462  }
463  }
464  else if (isset($metrics[4]))
465  {
466  foreach ($metrics[4] as $metric)
467  {
468  $progressDate = self::createDateUsingMetrics(4, $metric, $metrics[5]);
469  $matchParams = self::getTextForReplace($originalText, $metric, $metrics[5]);
470  $result[] = new DateConverterResult($progressDate, $matchParams, DateConverterResult::TYPE_CALENDAR, $metric, $metrics[5]);
471  }
472  }
473  }
474  else if ($countOfMetrics == 2 && isset($metrics[1]) && (isset($metrics[2]) || isset($metrics[4])))
475  {
476  if (isset($metrics[2]))
477  {
478  foreach ($metrics[2] as $metric)
479  {
480  $array = array();
481  $progressDate = self::createDateUsingMetrics(2, $metric, $array);
482  $matchParams = self::getTextForReplace($originalText, $metric, array());
483  $result[] = new DateConverterResult($progressDate, $matchParams, DateConverterResult::TYPE_DAYOFWEEK, $metric);
484  }
485  }
486  elseif (isset($metrics[4]))
487  {
488  foreach ($metrics[4] as $metric)
489  {
490  $array = array();
491  $progressDate = self::createDateUsingMetrics(4, $metric, $array);
492  $matchParams = self::getTextForReplace($originalText, $metric, array());
493  $result[] = new DateConverterResult($progressDate, $matchParams, DateConverterResult::TYPE_CALENDAR, $metric);
494  }
495  }
496  }
497  else
498  {
499  $useDefault = true;
500  }
501 
502  if ($useDefault)
503  {
504  $modificators = isset($metrics[3])? $metrics[3]: array();
505  if (isset($metrics[4]) && count($metrics[4]))
506  {
507  foreach ($metrics[4] as $metric)
508  {
509  $progressDate = self::createDateUsingMetrics(4, $metric, $modificators);
510  $matchParams = self::getTextForReplace($originalText, $metric, $modificators);
511  $result[] = new DateConverterResult($progressDate, $matchParams, DateConverterResult::TYPE_CALENDAR, $metric, $modificators);
512  }
513  }
514  else if (isset($metrics[2]) && count($metrics[2]))
515  {
516  foreach ($metrics[2] as $metric)
517  {
518  $progressDate = self::createDateUsingMetrics(2, $metric, $modificators);
519  $matchParams = self::getTextForReplace($originalText, $metric, $modificators);
520  $result[] = new DateConverterResult($progressDate, $matchParams, DateConverterResult::TYPE_DAYOFWEEK, $metric, $modificators);
521  }
522  }
523  else if (isset($metrics[1]) && count($metrics[1]))
524  {
525  foreach ($metrics[1] as $metric)
526  {
527  $progressDate = self::createDateUsingMetrics(1, $metric, $modificators);
528  $matchParams = self::getTextForReplace($originalText, $metric, $modificators);
529  $result[] = new DateConverterResult($progressDate, $matchParams, DateConverterResult::TYPE_RELATIVE, $metric, $modificators);
530  }
531  }
532  else if (isset($metrics[5]) && count($metrics[5]))
533  {
534  foreach ($metrics[5] as $metric)
535  {
536  $progressDate = self::createDateUsingMetrics(5, $metric, $modificators);
537  $matchParams = self::getTextForReplace($originalText, $metric, $modificators);
538  $result[] = new DateConverterResult($progressDate, $matchParams, DateConverterResult::TYPE_PARTOFDAY, $metric, $modificators);
539  }
540  }
541  else if (isset($metrics[3]) && count($metrics[3]))
542  {
543  foreach ($metrics[3] as $metric)
544  {
545  $array = array();
546  $progressDate = self::createDateUsingMetrics(3, $metric, $array);
547  $matchParams = self::getTextForReplace($originalText, $metric, $modificators);
548  $result[] = new DateConverterResult($progressDate, $matchParams, DateConverterResult::TYPE_MODIFIER, $metric);
549  }
550  }
551 
552  }
553 
554  return $result;
555  }
556 
557  /**
558  * Creates Date object from metrics (private method for self::decode)
559  *
560  * @param int $type Type of metric
561  * @param array $metric Params of metric
562  * @param array $metricModificator List of metric modificators
563  * @param \Bitrix\Main\Type\DateTime $date If not specified, the modified date is got from the current date.
564  * @return \Bitrix\Main\Type\DateTime
565  *
566  */
567  private static function createDateUsingMetrics($type, $metric, &$metricModificator = array(), \Bitrix\Main\Type\DateTime $date = null)
568  {
569  $defaultDate = $date? $date: new \Bitrix\Main\Type\DateTime();
570  $metricModificator = is_array($metricModificator)? $metricModificator: array();
571 
572  $workTimeStart = explode('.', \Bitrix\Main\Config\Option::get('calendar', 'work_time_start', '9'));
573  $timeOfStartDate = str_pad(intval($workTimeStart[0]), 2, "0", STR_PAD_LEFT).':'.str_pad(intval($workTimeStart[1]), 2, "0", STR_PAD_LEFT);
574 
575  $workTimeEnd = explode('.', \Bitrix\Main\Config\Option::get('calendar', 'work_time_end', '18'));
576  $timeOfEndDate = str_pad(intval($workTimeEnd[0]), 2, "0", STR_PAD_LEFT).':'.str_pad(intval($workTimeEnd[1]), 2, "0", STR_PAD_LEFT);
577 
578  $result = null;
579  switch($type)
580  {
581  case 1:
582  $metricDate = $defaultDate;
583  switch($metric['TYPE'])
584  {
585  case 'DAYAFTERTOMORROW':
586  $metricDate->add('TOMORROW')->add('TOMORROW');
587  break;
588  case 'TOMORROW':
589  $metricDate->add('TOMORROW');
590  break;
591  case 'YESTERDAY':
592  $metricDate->add('YESTERDAY');
593  break;
594  case 'DAYBEFOREYESTERDAY':
595  $metricDate->add('YESTERDAY')->add('YESTERDAY');
596  break;
597  }
598 
599  $modificator = '';
600  $metricTime = $timeOfEndDate;
601 
602  $metricModificator = self::checkModifierPosition($metric, $metricModificator);
603 
604  foreach ($metricModificator as $currentModificator)
605  {
606  if ($metric['TYPE'] == 'WEEK')
607  {
608  if (in_array($currentModificator['TYPE'], Array('BEFORE', 'PREVIOUS')))
609  {
610  $metricDate->add('-1 WEEK');
611  }
612  else if (in_array($currentModificator['TYPE'], Array('AFTER', 'NEXT')))
613  {
614  $metricDate->add('1 WEEK');
615  }
616  else if ($currentModificator['TYPE'] == 'MIDDLEOF')
617  {
618  $metricDate = self::getDateOfDayOfCurrentWeek('WEDNESDAY', $metricDate);
619  $modificator = true;
620  }
621  else if ($currentModificator['TYPE'] == 'STARTOF')
622  {
623  $metricDate = self::getDateOfDayOfCurrentWeek('MONDAY', $metricDate);
624  $modificator = true;
625  }
626  else if ($currentModificator['TYPE'] == 'ENDOF')
627  {
628  $metricDate = self::getDateOfDayOfCurrentWeek('FRIDAY', $metricDate);
629  $modificator = true;
630  }
631  }
632  else if ($metric['TYPE'] == 'WEEKEND')
633  {
634  if (in_array($currentModificator['TYPE'], Array('BEFORE')))
635  {
636  $metricDate = self::getDateOfDayOfCurrentWeek('SATURDAY', $metricDate);
637  $metricDate->add('-1 DAY');
638  $modificator = true;
639  }
640  else if (in_array($currentModificator['TYPE'], Array('PREVIOUS')))
641  {
642  $metricDate->add('-1 WEEK');
643  $metricDate = self::getDateOfDayOfCurrentWeek('SATURDAY', $metricDate);
644  $modificator = true;
645  }
646  else if (in_array($currentModificator['TYPE'], Array('NEXT')))
647  {
648  $metricDate->add('1 WEEK');
649  $metricDate = self::getDateOfDayOfCurrentWeek('SATURDAY', $metricDate);
650  $modificator = true;
651  }
652  else if (in_array($currentModificator['TYPE'], Array('AFTER')))
653  {
654  $metricDate = self::getDateOfDayOfCurrentWeek('SUNDAY', $metricDate);
655  $metricDate->add('1 DAY');
656  $modificator = true;
657  }
658  else if ($currentModificator['TYPE'] == 'MIDDLEOF')
659  {
660  $metricDate = self::getDateOfDayOfCurrentWeek('SATURDAY', $metricDate);
661  $modificator = true;
662  }
663  else if ($currentModificator['TYPE'] == 'STARTOF')
664  {
665  $metricDate = self::getDateOfDayOfCurrentWeek('SATURDAY', $metricDate);
666  $metricTime = $timeOfStartDate;
667  $modificator = true;
668  }
669  else if ($currentModificator['TYPE'] == 'ENDOF')
670  {
671  $metricDate = self::getDateOfDayOfCurrentWeek('SUNDAY', $metricDate);
672  $modificator = true;
673  }
674  }
675  else if ($metric['TYPE'] == 'MONTH')
676  {
677  if (in_array($currentModificator['TYPE'], Array('BEFORE', 'PREVIOUS')))
678  {
679  $metricDate->add('-1 MONTH');
680  $numberOfMonth = $metricDate->format('t');
681  $metricDate = new \Bitrix\Main\Type\DateTime($metricDate->format('Y-m').'-'.$numberOfMonth.' '.$timeOfEndDate.':00', 'Y-m-d H:i:s');
682  $modificator = true;
683  }
684  else if (in_array($currentModificator['TYPE'], Array('AFTER', 'NEXT')))
685  {
686  $metricDate->add('1 MONTH');
687  $numberOfMonth = $metricDate->format('t');
688  $metricDate = new \Bitrix\Main\Type\DateTime($metricDate->format('Y-m').'-'.$numberOfMonth.' '.$timeOfEndDate.':00', 'Y-m-d H:i:s');
689  $modificator = true;
690  }
691  else if ($currentModificator['TYPE'] == 'MIDDLEOF')
692  {
693  $numberOfHalfMonth = ceil($metricDate->format('t')/2);
694  $metricDate = new \Bitrix\Main\Type\DateTime($metricDate->format('Y-m').'-'.$numberOfHalfMonth.' '.$timeOfEndDate.':00', 'Y-m-d H:i:s');
695  $modificator = true;
696  }
697  else if ($currentModificator['TYPE'] == 'STARTOF')
698  {
699  $metricDate = new \Bitrix\Main\Type\DateTime($metricDate->format('Y-m').'-01 '.$timeOfStartDate.':00', 'Y-m-d H:i:s');
700  $modificator = true;
701  }
702  else if ($currentModificator['TYPE'] == 'ENDOF')
703  {
704  $numberOfMonth = $metricDate->format('t');
705  $metricDate = new \Bitrix\Main\Type\DateTime($metricDate->format('Y-m').'-'.$numberOfMonth.' '.$timeOfEndDate.':00', 'Y-m-d H:i:s');
706  $modificator = true;
707  }
708  }
709  else
710  {
711  if (in_array($currentModificator['TYPE'], Array('BEFORE', 'PREVIOUS')))
712  {
713  $metricDate->add('-1 DAY');
714  }
715  else if (in_array($currentModificator['TYPE'], Array('AFTER', 'NEXT')))
716  {
717  $metricDate->add('1 DAY');
718  }
719  else if ($currentModificator['TYPE'] == 'MIDDLEOF')
720  {
721  $metricTime = '14:00';
722  }
723  else if ($currentModificator['TYPE'] == 'STARTOF')
724  {
725  $metricTime = $timeOfStartDate;
726  }
727  $modificator = true;
728  }
729 
730  if (in_array($currentModificator['TYPE'], Array('MORNING', 'LUNCH', 'EVENING', 'HHMM')))
731  {
732  $metricTime = $currentModificator['VALUE'];
733  $modificator = true;
734  }
735  }
736  if (!$modificator)
737  {
738  if ($metric['TYPE'] == 'WEEK')
739  {
740  if ($metricDate->format('N') == 3)
741  {
742  $metricDate->add('FRIDAY');
743  }
744  else if ($metricDate->format('N') < 3)
745  {
746  $metricDate->add('THURSDAY');
747  }
748  else if ($metricDate->format('N') != 7)
749  {
750  $metricDate->add('SUNDAY');
751  }
752  }
753  else if ($metric['TYPE'] == 'WEEKEND')
754  {
755  if (ToLower($metricDate->format('l')) == 'saturday')
756  $metricDate->add('SUNDAY');
757  else if (ToLower($metricDate->format('l')) != 'sunday')
758  $metricDate->add('SATURDAY');
759  }
760  else if ($metric['TYPE'] == 'MONTH')
761  {
762  $numberOfMonth = $metricDate->format('j');
763  if ($numberOfMonth > 15)
764  {
765  $plus = $metricDate->format('t')-$numberOfMonth;
766  if ($plus >= 1)
767  {
768  $metricDate->add($plus.' DAY');
769  }
770  }
771  else if ($numberOfMonth >= 10 && $numberOfMonth <= 15)
772  {
773  $plus = 20-$numberOfMonth;
774  $metricDate->add($plus.' DAY');
775  }
776  else
777  {
778  $plus = 15-$numberOfMonth;
779  $metricDate->add($plus.' DAY');
780  }
781  }
782  }
783 
784  $result = new \Bitrix\Main\Type\DateTime($metricDate->format('Y-m-d').' '.$metricTime.':00', 'Y-m-d H:i:s');
785 
786  break;
787  case 2:
788 
789  $metricDate = $defaultDate;
790  $modificator = '';
791  $metricTime = $timeOfEndDate;
792 
793  $metricModificator = self::checkModifierPosition($metric, $metricModificator);
794 
795  foreach ($metricModificator as $currentModificator)
796  {
797  $metricDate = self::getDateOfDayOfCurrentWeek($metric['TYPE'], $metricDate);
798  if ($currentModificator['TYPE'] == 'BEFORE')
799  {
800  $metricDate->add('-1 DAY');
801  }
802  else if ($currentModificator['TYPE'] == 'AFTER')
803  {
804  $metricDate->add('1 DAY');
805  }
806  else if ($currentModificator['TYPE'] == 'THIS')
807  {
808  $metricDate->add('LAST '.$metric['TYPE']);
809  }
810  else if (in_array($currentModificator['TYPE'], Array('NEXT', 'PREVIOUS')))
811  {
812  if ($currentModificator['TYPE'] == 'NEXT')
813  {
814  $metricDate->add('NEXT '.$metric['TYPE']);
815  }
816  else
817  {
818  $metricDate->add('PREVIOUS '.$metric['TYPE']);
819  }
820  }
821  else if ($currentModificator['TYPE'] == 'MIDDLEOF')
822  {
823  $metricTime = '14:00';
824  }
825  else if ($currentModificator['TYPE'] == 'STARTOF')
826  {
827  $metricTime = $timeOfStartDate;
828  }
829  else if (in_array($currentModificator['TYPE'], Array('MORNING', 'LUNCH', 'EVENING', 'HHMM')))
830  {
831  $metricTime = $currentModificator['VALUE'];
832  }
833  $modificator = true;
834  }
835  if (!$modificator)
836  {
837  $modificator = ToLower($metric['TYPE']) == ToLower($metricDate->format('l'))? 'NEXT ': '';
838  $metricDate->add($modificator.$metric['TYPE']);
839  }
840 
841  $result = new \Bitrix\Main\Type\DateTime($metricDate->format('Y-m-d').' '.$metricTime.':00', 'Y-m-d H:i:s');
842 
843  break;
844  case 3:
845  $metricDate = $defaultDate;
846  $metricTime = $timeOfEndDate;
847  switch($metric['TYPE'])
848  {
849  case 'BEFORE':
850  $metricDate->add('TOMORROW')->add('TOMORROW');
851  break;
852  case 'AFTER':
853  $metricDate->add('TOMORROW');
854  break;
855  case 'NEXT':
856  $metricDate->add('YESTERDAY');
857  break;
858  case 'PREVIOUS':
859  $metricDate->add('YESTERDAY')->add('YESTERDAY');
860  break;
861  case 'MIDDLEOF':
862  $metricTime = '14:00';
863  break;
864  case 'STARTOF':
865  $metricTime = $timeOfStartDate;
866  break;
867  case 'HHMM':
868  $metricTime = $metric['VALUE'];
869  break;
870  }
871  $result = new \Bitrix\Main\Type\DateTime($metricDate->format('Y-m-d').' '.$metricTime.':00', 'Y-m-d H:i:s');
872 
873  break;
874  case 4:
875  $modificator = '';
876  $metricTime = $timeOfEndDate;
877 
878  $metricModificator = self::checkModifierPosition($metric, $metricModificator);
879 
880  foreach ($metricModificator as $currentModificator)
881  {
882  if (in_array($currentModificator['TYPE'], Array('MORNING', 'LUNCH', 'EVENING', 'HHMM')))
883  {
884  $metricTime = $currentModificator['VALUE'];
885  }
886  }
887 
888  $result = new \Bitrix\Main\Type\DateTime($metric['VALUE'].' '.$metricTime.':00', 'Y-m-d H:i:s');
889 
890  break;
891  case 5:
892 
893  $metricDate = $defaultDate;
894  $modificator = '';
895  $metricTime = $metric['VALUE'];
896 
897  $metricModificator = self::checkModifierPosition($metric, $metricModificator);
898 
899  foreach ($metricModificator as $currentModificator)
900  {
901  if ($currentModificator['TYPE'] == 'BEFORE')
902  {
903  $metricDate->add('-1 DAY');
904  }
905  else if ($currentModificator['TYPE'] == 'AFTER')
906  {
907  $metricDate->add('1 DAY');
908  }
909  else if (in_array($currentModificator['TYPE'], Array('NEXT', 'PREVIOUS')))
910  {
911  if ($currentModificator['TYPE'] == 'NEXT')
912  {
913  $metricDate->add('NEXT '.$metric['TYPE']);
914  }
915  else
916  {
917  $metricDate->add('PREVIOUS '.$metric['TYPE']);
918  }
919  }
920  else if ($currentModificator['TYPE'] == 'MIDDLEOF')
921  {
922  $metricTime = '14:00';
923  }
924  else if ($currentModificator['TYPE'] == 'STARTOF')
925  {
926  $metricTime = $timeOfStartDate;
927  }
928  else if (in_array($currentModificator['TYPE'], Array('MORNING', 'LUNCH', 'EVENING', 'HHMM')))
929  {
930  $metricTime = $currentModificator['VALUE'];
931  }
932  $modificator = true;
933 
934  }
935 
936  if (!$modificator)
937  {
938  $modificator = ToLower($metric['TYPE']) == ToLower($metricDate->format('l'))? 'NEXT ': '';
939  $metricDate->add($modificator.$metric['TYPE']);
940  }
941 
942  $result = new \Bitrix\Main\Type\DateTime($metricDate->format('Y-m-d').' '.$metricTime.':00', 'Y-m-d H:i:s');
943  break;
944  }
945 
946  return $result;
947  }
948 
949  /**
950  * Creates Date object of the day of the method week (private function for self::createDateUsingMetrics)
951  *
952  * @param string $nameOfday name of the day (monday, tuesday, etc)
953  * @param \Bitrix\Main\Type\DateTime $date If not specified, the modified date is got from the current date.
954  * @return \Bitrix\Main\Type\DateTime
955  *
956  */
957  private static function getDateOfDayOfCurrentWeek($nameOfday, \Bitrix\Main\Type\DateTime $date = null)
958  {
959  $date = $date? $date: new \Bitrix\Main\Type\DateTime();
960 
961  $nameOfday = mb_strtoupper($nameOfday);
962  if (!in_array($nameOfday, Array('MONDAY', 'TUESDAY', 'WEDNESDAY', 'THURSDAY', 'FRIDAY', 'SATURDAY', 'SUNDAY')))
963  return false;
964 
965  $relation = '';
966  $day = $date->format('N');
967  if (
968  $nameOfday == 'MONDAY' && $day == 1 ||
969  $nameOfday == 'TUESDAY' && $day <= 2 ||
970  $nameOfday == 'WEDNESDAY' && $day <= 3 ||
971  $nameOfday == 'THURSDAY' && $day <= 4 ||
972  $nameOfday == 'FRIDAY' && $day <= 5 ||
973  $nameOfday == 'SATURDAY' && $day <= 6 ||
974  $nameOfday == 'SUNDAY' && $day <= 7
975  )
976  {
977  $relation = 'THIS';
978  }
979  $date->add($relation.' '.$nameOfday);
980 
981  return $date;
982  }
983 
984  /**
985  * @param $text
986  * @param $position
987  * @return string
988  */
989  private static function getMatchWord($text, $position)
990  {
991  $letters = array_merge(Array(" ", "\n", "\t", "\r"), str_split('"\'-.,?!#$%^&*();:<>\|{}-=^@[]`'));
992  $spaceFound = self::findFirstOccurrence($text, $letters, $position);
993  if ($spaceFound !== false)
994  {
995  $result = mb_substr($text, $position, $spaceFound - $position);
996  }
997  else
998  {
999  $result = mb_substr($text, $position);
1000  }
1001  return $result;
1002  }
1003 
1004  private static function getTextForReplace($text, $metrics, $metricModifier)
1005  {
1006  $found = false;
1007 
1008  $minStartPosition = null;
1009  $maxEndPosition = null;
1010 
1011  if (!empty($metrics))
1012  {
1013  $minStartPosition = $metrics['POSITION'];
1014  $maxEndPosition = $metrics['POSITION'] + $metrics['COUNT'];
1015  $found = true;
1016  }
1017 
1018  if (is_array($metricModifier))
1019  {
1020  foreach ($metricModifier as $metrics)
1021  {
1022  if (!$found)
1023  {
1024  $minStartPosition = $metrics['POSITION'];
1025  $maxEndPosition = $metrics['POSITION'] + $metrics['COUNT'];
1026  $found = true;
1027  }
1028  else
1029  {
1030  if ($minStartPosition > $metrics['POSITION'])
1031  {
1032  $minStartPosition = $metrics['POSITION'];
1033  }
1034  if ($maxEndPosition < $metrics['POSITION'] + $metrics['COUNT'])
1035  {
1036  $maxEndPosition = $metrics['POSITION'] + $metrics['COUNT'];
1037  }
1038  }
1039  }
1040  }
1041 
1042  if (is_null($minStartPosition) || is_null($maxEndPosition))
1043  {
1044  $result = false;
1045  }
1046  else
1047  {
1048  $result = mb_substr($text, $minStartPosition, $maxEndPosition - $minStartPosition);
1049  $result = Array('TEXT' => $result, 'POSITION' => $minStartPosition, 'LENGTH' => mb_strlen($result));
1050  }
1051 
1052  return $result;
1053  }
1054 
1055  private static function checkModifierPosition($metrics, $metricModifier)
1056  {
1057  $newMetrics = $metrics;
1058 
1059  $stackMetrics = Array();
1060 
1061  $while = true;
1062  $maxWhile = 100;
1063  while ($while && $maxWhile > 0)
1064  {
1065  $while = false;
1066  foreach ($metricModifier as $key => $currentModificator)
1067  {
1068  $diffResult = abs($newMetrics['POSITION'] - ($currentModificator['POSITION'] + $currentModificator['COUNT']));
1069  if ($diffResult < 5)
1070  {
1071  $while = true;
1072  $newMetrics = $currentModificator;
1073  $stackMetrics[] = $currentModificator;
1074  unset($metricModifier[$key]);
1075  }
1076  else
1077  {
1078  $diffResult = abs($newMetrics['POSITION']+$newMetrics['COUNT'] - ($currentModificator['POSITION']));
1079  if ($diffResult < 5)
1080  {
1081  $while = true;
1082  $newMetrics = $currentModificator;
1083  $stackMetrics[] = $currentModificator;
1084  unset($metricModifier[$key]);
1085  }
1086  }
1087  }
1088  $maxWhile--;
1089  }
1090 
1091  return $stackMetrics;
1092  }
1093 
1094  private static function findFirstOccurrence($haystack, $needle, $offset=0)
1095  {
1096  $haystack = mb_substr($haystack, 0, 25 + $offset);
1097  if(!is_array($needle))
1098  {
1099  $needle = array($needle);
1100  }
1101 
1102  $positions = array();
1103  foreach($needle as $query)
1104  {
1105  $result = mb_strpos($haystack, $query, $offset);
1106  if ($result !== false)
1107  {
1108  $positions[] = $result;
1109  }
1110  }
1111 
1112  return empty($positions)? false: min($positions);
1113  }
1114 }
static get($moduleId, $name, $default="", $siteId=false)
Returns a value of an option.
static getMessage($code, $replace=null, $language=null)
Returns translation by message code.
Definition: loc.php:29
static decode($text, $limit=0)
Creates Date object from Text (return array of result object)