INFRA-132 - CRM/Upgrade - Convert single-line @param to multi-line
[civicrm-core.git] / CRM / Utils / Date.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
39de6fd5 4 | CiviCRM version 4.6 |
6a488035 5 +--------------------------------------------------------------------+
06b69b18 6 | Copyright CiviCRM LLC (c) 2004-2014 |
6a488035
TO
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
13 | |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
26*/
27
28/**
29 *
30 * @package CRM
06b69b18 31 * @copyright CiviCRM LLC (c) 2004-2014
6a488035
TO
32 * $Id$
33 *
34 */
35
36/**
37 * Date utilties
38 */
39class CRM_Utils_Date {
40
41 /**
100fef9d 42 * Format a date by padding it with leading '0'.
6a488035 43 *
f4aaa82a
EM
44 * @param array $date ('Y', 'M', 'd')
45 * @param string $separator the seperator to use when formatting the date
46 * @param int|string $invalidDate what to return if the date is invalid
6a488035
TO
47 *
48 * @return string - formatted string for date
49 *
50 * @static
51 */
00be9182 52 public static function format($date, $separator = '', $invalidDate = 0) {
6a488035
TO
53 if (is_numeric($date) &&
54 ((strlen($date) == 8) || (strlen($date) == 14))
55 ) {
56 return $date;
57 }
58
59 if (!is_array($date) ||
60 CRM_Utils_System::isNull($date) ||
61 empty($date['Y'])
62 ) {
63 return $invalidDate;
64 }
65
66 $date['Y'] = (int ) $date['Y'];
67 if ($date['Y'] < 1000 || $date['Y'] > 2999) {
68 return $invalidDate;
69 }
70
71 if (array_key_exists('m', $date)) {
72 $date['M'] = $date['m'];
73 }
74 elseif (array_key_exists('F', $date)) {
75 $date['M'] = $date['F'];
76 }
77
a7488080 78 if (!empty($date['M'])) {
6a488035
TO
79 $date['M'] = (int ) $date['M'];
80 if ($date['M'] < 1 || $date['M'] > 12) {
81 return $invalidDate;
82 }
83 }
84 else {
85 $date['M'] = 1;
86 }
87
a7488080 88 if (!empty($date['d'])) {
6a488035
TO
89 $date['d'] = (int ) $date['d'];
90 }
91 else {
92 $date['d'] = 1;
93 }
94
95 if (!checkdate($date['M'], $date['d'], $date['Y'])) {
96 return $invalidDate;
97 }
98
99 $date['M'] = sprintf('%02d', $date['M']);
100 $date['d'] = sprintf('%02d', $date['d']);
101
102 $time = '';
103 if (CRM_Utils_Array::value('H', $date) != NULL ||
104 CRM_Utils_Array::value('h', $date) != NULL ||
105 CRM_Utils_Array::value('i', $date) != NULL ||
106 CRM_Utils_Array::value('s', $date) != NULL
107 ) {
108 // we have time too..
a7488080 109 if (!empty($date['h'])) {
6a488035
TO
110 if (CRM_Utils_Array::value('A', $date) == 'PM' or CRM_Utils_Array::value('a', $date) == 'pm') {
111 if ($date['h'] != 12) {
112 $date['h'] = $date['h'] + 12;
113 }
114 }
115 if ((CRM_Utils_Array::value('A', $date) == 'AM' or CRM_Utils_Array::value('a', $date) == 'am') &&
116 CRM_Utils_Array::value('h', $date) == 12
117 ) {
118 $date['h'] = '00';
119 }
120
121 $date['h'] = (int ) $date['h'];
122 }
123 else {
124 $date['h'] = 0;
125 }
126
127 // in 24-hour format the hour is under the 'H' key
a7488080 128 if (!empty($date['H'])) {
6a488035
TO
129 $date['H'] = (int) $date['H'];
130 }
131 else {
132 $date['H'] = 0;
133 }
134
a7488080 135 if (!empty($date['i'])) {
6a488035
TO
136 $date['i'] = (int ) $date['i'];
137 }
138 else {
139 $date['i'] = 0;
140 }
141
142 if ($date['h'] == 0 && $date['H'] != 0) {
143 $date['h'] = $date['H'];
144 }
145
a7488080 146 if (!empty($date['s'])) {
6a488035
TO
147 $date['s'] = (int ) $date['s'];
148 }
149 else {
150 $date['s'] = 0;
151 }
152
153 $date['h'] = sprintf('%02d', $date['h']);
154 $date['i'] = sprintf('%02d', $date['i']);
155 $date['s'] = sprintf('%02d', $date['s']);
156
157 if ($separator) {
158 $time = '&nbsp;';
159 }
160 $time .= $date['h'] . $separator . $date['i'] . $separator . $date['s'];
161 }
162
163 return $date['Y'] . $separator . $date['M'] . $separator . $date['d'] . $time;
164 }
165
166 /**
100fef9d 167 * Return abbreviated weekday names according to the locale
6a488035
TO
168 *
169 * @return array 0-based array with abbreviated weekday names
170 *
171 * @static
172 */
00be9182 173 public static function &getAbbrWeekdayNames() {
6a488035
TO
174 static $abbrWeekdayNames;
175 if (!isset($abbrWeekdayNames)) {
176
177 // set LC_TIME and build the arrays from locale-provided names
178 // June 1st, 1970 was a Monday
179 CRM_Core_I18n::setLcTime();
180 for ($i = 0; $i < 7; $i++) {
181 $abbrWeekdayNames[$i] = strftime('%a', mktime(0, 0, 0, 6, $i, 1970));
182 }
183 }
184 return $abbrWeekdayNames;
185 }
186
187 /**
100fef9d 188 * Return full weekday names according to the locale
6a488035
TO
189 *
190 * @return array 0-based array with full weekday names
191 *
192 * @static
193 */
00be9182 194 public static function &getFullWeekdayNames() {
6a488035
TO
195 static $fullWeekdayNames;
196 if (!isset($fullWeekdayNames)) {
197
198 // set LC_TIME and build the arrays from locale-provided names
199 // June 1st, 1970 was a Monday
200 CRM_Core_I18n::setLcTime();
201 for ($i = 0; $i < 7; $i++) {
202 $fullWeekdayNames[$i] = strftime('%A', mktime(0, 0, 0, 6, $i, 1970));
203 }
204 }
205 return $fullWeekdayNames;
206 }
207
208 /**
100fef9d 209 * Return abbreviated month names according to the locale
6a488035 210 *
f4aaa82a
EM
211 * @param bool $month
212 *
6a488035
TO
213 * @return array 1-based array with abbreviated month names
214 *
215 * @static
216 */
00be9182 217 public static function &getAbbrMonthNames($month = FALSE) {
6a488035
TO
218 static $abbrMonthNames;
219 if (!isset($abbrMonthNames)) {
220
221 // set LC_TIME and build the arrays from locale-provided names
222 CRM_Core_I18n::setLcTime();
223 for ($i = 1; $i <= 12; $i++) {
224 $abbrMonthNames[$i] = strftime('%b', mktime(0, 0, 0, $i, 10, 1970));
225 }
226 }
227 if ($month) {
228 return $abbrMonthNames[$month];
229 }
230 return $abbrMonthNames;
231 }
232
233 /**
100fef9d 234 * Return full month names according to the locale
6a488035
TO
235 *
236 * @return array 1-based array with full month names
237 *
238 * @static
239 */
00be9182 240 public static function &getFullMonthNames() {
6a488035
TO
241 static $fullMonthNames;
242 if (!isset($fullMonthNames)) {
243
244 // set LC_TIME and build the arrays from locale-provided names
245 CRM_Core_I18n::setLcTime();
246 for ($i = 1; $i <= 12; $i++) {
247 $fullMonthNames[$i] = strftime('%B', mktime(0, 0, 0, $i, 10, 1970));
248 }
249 }
250 return $fullMonthNames;
251 }
252
5bc392e6
EM
253 /**
254 * @param $string
255 *
256 * @return int
257 */
00be9182 258 public static function unixTime($string) {
6a488035
TO
259 if (empty($string)) {
260 return 0;
261 }
262 $parsedDate = date_parse($string);
263 return mktime(CRM_Utils_Array::value('hour', $parsedDate),
264 CRM_Utils_Array::value('minute', $parsedDate),
265 59,
266 CRM_Utils_Array::value('month', $parsedDate),
267 CRM_Utils_Array::value('day', $parsedDate),
268 CRM_Utils_Array::value('year', $parsedDate)
269 );
270 }
271
272 /**
100fef9d 273 * Create a date and time string in a provided format
6a488035
TO
274 *
275 * %b - abbreviated month name ('Jan'..'Dec')
276 * %B - full month name ('January'..'December')
277 * %d - day of the month as a decimal number, 0-padded ('01'..'31')
278 * %e - day of the month as a decimal number, blank-padded (' 1'..'31')
279 * %E - day of the month as a decimal number ('1'..'31')
280 * %f - English ordinal suffix for the day of the month ('st', 'nd', 'rd', 'th')
281 * %H - hour in 24-hour format, 0-padded ('00'..'23')
282 * %I - hour in 12-hour format, 0-padded ('01'..'12')
283 * %k - hour in 24-hour format, blank-padded (' 0'..'23')
284 * %l - hour in 12-hour format, blank-padded (' 1'..'12')
285 * %m - month as a decimal number, 0-padded ('01'..'12')
286 * %M - minute, 0-padded ('00'..'60')
287 * %p - lowercase ante/post meridiem ('am', 'pm')
288 * %P - uppercase ante/post meridiem ('AM', 'PM')
289 * %Y - year as a decimal number including the century ('2005')
290 *
c490a46a 291 * @param string $dateString date and time in 'YYYY-MM-DD hh:mm:ss' format
f4aaa82a
EM
292 * @param string $format the output format
293 * @param array $dateParts an array with the desired date parts
6a488035
TO
294 *
295 * @return string the $format-formatted $date
6a488035
TO
296 * @static
297 */
00be9182 298 public static function customFormat($dateString, $format = NULL, $dateParts = NULL) {
6a488035
TO
299 // 1-based (January) month names arrays
300 $abbrMonths = self::getAbbrMonthNames();
301 $fullMonths = self::getFullMonthNames();
302
303 if (!$format) {
304 $config = CRM_Core_Config::singleton();
305
306 if ($dateParts) {
307 if (array_intersect(array('h', 'H'), $dateParts)) {
308 $format = $config->dateformatDatetime;
309 }
310 elseif (array_intersect(array('d', 'j'), $dateParts)) {
311 $format = $config->dateformatFull;
312 }
313 elseif (array_intersect(array('m', 'M'), $dateParts)) {
314 $format = $config->dateformatPartial;
315 }
316 else {
317 $format = $config->dateformatYear;
318 }
319 }
320 else {
321 if (strpos($dateString, '-')) {
322 $month = (int) substr($dateString, 5, 2);
323 $day = (int) substr($dateString, 8, 2);
324 }
325 else {
326 $month = (int) substr($dateString, 4, 2);
327 $day = (int) substr($dateString, 6, 2);
328 }
329
330 if (strlen($dateString) > 10) {
331 $format = $config->dateformatDatetime;
332 }
333 elseif ($day > 0) {
334 $format = $config->dateformatFull;
335 }
336 elseif ($month > 0) {
337 $format = $config->dateformatPartial;
338 }
339 else {
340 $format = $config->dateformatYear;
341 }
342 }
343 }
344
35fa23f8 345 if (!CRM_Utils_System::isNull($dateString)) {
6a488035
TO
346 if (strpos($dateString, '-')) {
347 $year = (int) substr($dateString, 0, 4);
348 $month = (int) substr($dateString, 5, 2);
349 $day = (int) substr($dateString, 8, 2);
350
351 $hour24 = (int) substr($dateString, 11, 2);
352 $minute = (int) substr($dateString, 14, 2);
353 }
354 else {
355 $year = (int) substr($dateString, 0, 4);
356 $month = (int) substr($dateString, 4, 2);
357 $day = (int) substr($dateString, 6, 2);
358
359 $hour24 = (int) substr($dateString, 8, 2);
360 $minute = (int) substr($dateString, 10, 2);
361 }
362
363 if ($day % 10 == 1 and $day != 11) {
364 $suffix = 'st';
365 }
366 elseif ($day % 10 == 2 and $day != 12) {
367 $suffix = 'nd';
368 }
369 elseif ($day % 10 == 3 and $day != 13) {
370 $suffix = 'rd';
371 }
372 else {
373 $suffix = 'th';
374 }
375
376 if ($hour24 < 12) {
377 if ($hour24 == 00) {
378 $hour12 = 12;
379 }
380 else {
381 $hour12 = $hour24;
382 }
383 $type = 'AM';
384 }
385 else {
386 if ($hour24 == 12) {
387 $hour12 = 12;
388 }
389 else {
390 $hour12 = $hour24 - 12;
391 }
392 $type = 'PM';
393 }
394
395 $date = array(
396 '%b' => CRM_Utils_Array::value($month, $abbrMonths),
397 '%B' => CRM_Utils_Array::value($month, $fullMonths),
398 '%d' => $day > 9 ? $day : '0' . $day,
399 '%e' => $day > 9 ? $day : ' ' . $day,
400 '%E' => $day,
401 '%f' => $suffix,
402 '%H' => $hour24 > 9 ? $hour24 : '0' . $hour24,
403 '%h' => $hour12 > 9 ? $hour12 : '0' . $hour12,
404 '%I' => $hour12 > 9 ? $hour12 : '0' . $hour12,
405 '%k' => $hour24 > 9 ? $hour24 : ' ' . $hour24,
406 '%l' => $hour12 > 9 ? $hour12 : ' ' . $hour12,
407 '%m' => $month > 9 ? $month : '0' . $month,
408 '%M' => $minute > 9 ? $minute : '0' . $minute,
409 '%i' => $minute > 9 ? $minute : '0' . $minute,
410 '%p' => strtolower($type),
411 '%P' => $type,
412 '%A' => $type,
413 '%Y' => $year,
414 );
415
416 return strtr($format, $date);
417 }
418 else {
419 return '';
420 }
421 }
422
423 /**
100fef9d 424 * Converts the date/datetime from MySQL format to ISO format
6a488035
TO
425 *
426 * @param string $mysql date/datetime in MySQL format
427 *
428 * @return string date/datetime in ISO format
429 * @static
430 */
00be9182 431 public static function mysqlToIso($mysql) {
6a488035
TO
432 $year = substr($mysql, 0, 4);
433 $month = substr($mysql, 4, 2);
434 $day = substr($mysql, 6, 2);
435 $hour = substr($mysql, 8, 2);
436 $minute = substr($mysql, 10, 2);
437 $second = substr($mysql, 12, 2);
438
439 $iso = '';
440 if ($year) {
441 $iso .= "$year";
442 }
443 if ($month) {
444 $iso .= "-$month";
445 if ($day) {
446 $iso .= "-$day";
447 }
448 }
449
450 if ($hour) {
451 $iso .= " $hour";
452 if ($minute) {
453 $iso .= ":$minute";
454 if ($second) {
455 $iso .= ":$second";
456 }
457 }
458 }
459 return $iso;
460 }
461
462 /**
100fef9d 463 * Converts the date/datetime from ISO format to MySQL format
5d9f6898
EM
464 * Note that until CRM-14986/ 4.4.7 this was required whenever the pattern $dao->find(TRUE): $dao->save(); was
465 * used to update an object with a date field was used. The DAO now checks for a '-' in date field strings
466 * & runs this function if the - appears - meaning it is likely redundant in the form & BAO layers
6a488035
TO
467 *
468 * @param string $iso date/datetime in ISO format
469 *
470 * @return string date/datetime in MySQL format
471 * @static
472 */
00be9182 473 public static function isoToMysql($iso) {
6a488035
TO
474 $dropArray = array('-' => '', ':' => '', ' ' => '');
475 return strtr($iso, $dropArray);
476 }
477
478 /**
100fef9d 479 * Converts the any given date to default date format.
6a488035 480 *
f4aaa82a
EM
481 * @param array $params has given date-format
482 * @param int $dateType type of date
483 * @param string $dateParam index of params
484 *
485 * @return bool
6a488035
TO
486 * @static
487 */
00be9182 488 public static function convertToDefaultDate(&$params, $dateType, $dateParam) {
6a488035
TO
489 $now = getDate();
490 $cen = substr($now['year'], 0, 2);
491 $prevCen = $cen - 1;
492
493 $value = NULL;
a7488080 494 if (!empty($params[$dateParam])) {
6a488035
TO
495 // suppress hh:mm or hh:mm:ss if it exists CRM-7957
496 $value = preg_replace("/(\s(([01]\d)|[2][0-3])(:([0-5]\d)){1,2})$/", "", $params[$dateParam]);
497 }
498
499 switch ($dateType) {
500 case 1:
501 if (!preg_match('/^\d\d\d\d-?(\d|\d\d)-?(\d|\d\d)$/', $value)) {
502 return FALSE;
503 }
504 break;
505
506 case 2:
507 if (!preg_match('/^(\d|\d\d)[-\/](\d|\d\d)[-\/]\d\d$/', $value)) {
508 return FALSE;
509 }
510 break;
511
512 case 4:
513 if (!preg_match('/^(\d|\d\d)[-\/](\d|\d\d)[-\/]\d\d\d\d$/', $value)) {
514 return FALSE;
515 }
516 break;
517
518 case 8:
519 if (!preg_match('/^[A-Za-z]*.[ \t]?\d\d\,[ \t]?\d\d\d\d$/', $value)) {
520 return FALSE;
521 }
522 break;
523
524 case 16:
525 if (!preg_match('/^\d\d-[A-Za-z]{3}.*-\d\d$/', $value) && !preg_match('/^\d\d[-\/]\d\d[-\/]\d\d$/', $value)) {
526 return FALSE;
527 }
528 break;
529
530 case 32:
531 if (!preg_match('/^(\d|\d\d)[-\/](\d|\d\d)[-\/]\d\d\d\d/', $value)) {
532 return FALSE;
533 }
534 break;
535 }
536
537 if ($dateType == 1) {
538 $formattedDate = explode("-", $value);
539 if (count($formattedDate) == 3) {
540 $year = (int) $formattedDate[0];
541 $month = (int) $formattedDate[1];
542 $day = (int) $formattedDate[2];
543 }
544 elseif (count($formattedDate) == 1 && (strlen($value) == 8)) {
545 return TRUE;
546 }
547 else {
548 return FALSE;
549 }
550 }
551
552
553 if ($dateType == 2 || $dateType == 4) {
554 $formattedDate = explode("/", $value);
555 if (count($formattedDate) != 3) {
556 $formattedDate = explode("-", $value);
557 }
558 if (count($formattedDate) == 3) {
559 $year = (int) $formattedDate[2];
560 $month = (int) $formattedDate[0];
561 $day = (int) $formattedDate[1];
562 }
563 else {
564 return FALSE;
565 }
566 }
567 if ($dateType == 8) {
568 $dateArray = explode(' ', $value);
569 // ignore comma(,)
570 $dateArray[1] = (int) substr($dateArray[1], 0, 2);
571
572 $monthInt = 0;
573 $fullMonths = self::getFullMonthNames();
574 foreach ($fullMonths as $key => $val) {
575 if (strtolower($dateArray[0]) == strtolower($val)) {
576 $monthInt = $key;
577 break;
578 }
579 }
580 if (!$monthInt) {
581 $abbrMonths = self::getAbbrMonthNames();
582 foreach ($abbrMonths as $key => $val) {
583 if (strtolower(trim($dateArray[0], ".")) == strtolower($val)) {
584 $monthInt = $key;
585 break;
586 }
587 }
588 }
589 $year = (int) $dateArray[2];
590 $day = (int) $dateArray[1];
591 $month = (int) $monthInt;
592 }
593 if ($dateType == 16) {
594 $dateArray = explode('-', $value);
595 if (count($dateArray) != 3) {
596 $dateArray = explode('/', $value);
597 }
598
599 if (count($dateArray) == 3) {
600 $monthInt = 0;
601 $fullMonths = self::getFullMonthNames();
602 foreach ($fullMonths as $key => $val) {
603 if (strtolower($dateArray[1]) == strtolower($val)) {
604 $monthInt = $key;
605 break;
606 }
607 }
608 if (!$monthInt) {
609 $abbrMonths = self::getAbbrMonthNames();
610 foreach ($abbrMonths as $key => $val) {
611 if (strtolower(trim($dateArray[1], ".")) == strtolower($val)) {
612 $monthInt = $key;
613 break;
614 }
615 }
616 }
617 if (!$monthInt) {
618 $monthInt = $dateArray[1];
619 }
620
621 $year = (int) $dateArray[2];
622 $day = (int) $dateArray[0];
623 $month = (int) $monthInt;
624 }
625 else {
626 return FALSE;
627 }
628 }
629 if ($dateType == 32) {
630 $formattedDate = explode("/", $value);
631 if (count($formattedDate) == 3) {
632 $year = (int) $formattedDate[2];
633 $month = (int) $formattedDate[1];
634 $day = (int) $formattedDate[0];
635 }
636 else {
637 return FALSE;
638 }
639 }
640
641 $month = ($month < 10) ? "0" . "$month" : $month;
642 $day = ($day < 10) ? "0" . "$day" : $day;
643
644 $year = (int ) $year;
645 // simple heuristic to determine what century to use
646 // 00 - 20 is always 2000 - 2020
647 // 21 - 99 is always 1921 - 1999
648 if ($year < 21) {
649 $year = (strlen($year) == 1) ? $cen . '0' . $year : $cen . $year;
650 }
651 elseif ($year < 100) {
652 $year = $prevCen . $year;
653 }
654
655 if ($params[$dateParam]) {
656 $params[$dateParam] = "$year$month$day";
657 }
658 //if month is invalid return as error
659 if ($month !== '00' && $month <= 12) {
660 return TRUE;
661 }
662 return FALSE;
663 }
664
5bc392e6
EM
665 /**
666 * @param $date
667 *
668 * @return bool
669 */
00be9182 670 public static function isDate(&$date) {
6a488035
TO
671 if (CRM_Utils_System::isNull($date)) {
672 return FALSE;
673 }
674 return TRUE;
675 }
676
5bc392e6
EM
677 /**
678 * @param null $timeStamp
679 *
680 * @return bool|string
681 */
00be9182 682 public static function currentDBDate($timeStamp = NULL) {
6a488035
TO
683 return $timeStamp ? date('YmdHis', $timeStamp) : date('YmdHis');
684 }
685
5bc392e6
EM
686 /**
687 * @param $date
688 * @param null $now
689 *
690 * @return bool
691 */
00be9182 692 public static function overdue($date, $now = NULL) {
6a488035
TO
693 $mysqlDate = self::isoToMysql($date);
694 if (!$now) {
695 $now = self::currentDBDate();
696 }
697 else {
698 $now = self::isoToMysql($now);
699 }
700
701 return ($mysqlDate >= $now) ? FALSE : TRUE;
702 }
703
704 /**
100fef9d 705 * Get customized today
6a488035
TO
706 *
707 * This function is used for getting customized today. To get
708 * actuall today pass 'dayParams' as null. or else pass the day,
709 * month, year values as array values
710 * Example: $dayParams = array(
711 'day' => '25', 'month' => '10',
712 * 'year' => '2007' );
713 *
714 * @param Array $dayParams Array of the day, month, year
715 * values.
716 * @param string $format expected date format( default
717 * format is 2007-12-21 )
718 *
719 * @return string Return the customized todays date (Y-m-d)
720 * @static
721 */
00be9182 722 public static function getToday($dayParams = NULL, $format = "Y-m-d") {
6a488035
TO
723 if (is_null($dayParams) || empty($dayParams)) {
724 $today = date($format);
725 }
726 else {
727 $today = date($format, mktime(0, 0, 0,
728 $dayParams['month'],
729 $dayParams['day'],
730 $dayParams['year']
731 ));
732 }
733
734 return $today;
735 }
736
737 /**
100fef9d 738 * Find whether today's date lies in
6a488035
TO
739 * the given range
740 *
741 * @param date $startDate start date for the range
742 * @param date $endDate end date for the range
743 *
744 * @return true todays date is in the given date range
745 * @static
746 */
00be9182 747 public static function getRange($startDate, $endDate) {
6a488035
TO
748 $today = date("Y-m-d");
749 $mysqlStartDate = self::isoToMysql($startDate);
750 $mysqlEndDate = self::isoToMysql($endDate);
751 $mysqlToday = self::isoToMysql($today);
752
753 if ((isset($mysqlStartDate) && isset($mysqlEndDate)) && (($mysqlToday >= $mysqlStartDate) && ($mysqlToday <= $mysqlEndDate))) {
754 return TRUE;
755 }
756 elseif ((isset($mysqlStartDate) && !isset($mysqlEndDate)) && (($mysqlToday >= $mysqlStartDate))) {
757 return TRUE;
758 }
759 elseif ((!isset($mysqlStartDate) && isset($mysqlEndDate)) && (($mysqlToday <= $mysqlEndDate))) {
760 return TRUE;
761 }
762 return FALSE;
763 }
764
765 /**
100fef9d 766 * Get start date and end from
6a488035
TO
767 * the given relative term and unit
768 *
f4aaa82a
EM
769 * @param date $relative eg: term.unit
770 *
771 * @param $from
772 * @param $to
6a488035
TO
773 *
774 * @return array start date, end date
775 * @static
776 */
00be9182 777 public static function getFromTo($relative, $from, $to) {
6a488035
TO
778 if ($relative) {
779 list($term, $unit) = explode('.', $relative);
780 $dateRange = self::relativeToAbsolute($term, $unit);
781 $from = $dateRange['from'];
782 //Take only Date Part, Sometime Time part is also present in 'to'
783 $to = substr($dateRange['to'], 0, 8);
784 }
785
786 $from = self::processDate($from);
787 $to = self::processDate($to, '235959');
788
789 return array($from, $to);
790 }
791
792 /**
100fef9d 793 * Calculate Age in Years if greater than one year else in months
6a488035
TO
794 *
795 * @param date $birthDate Birth Date
796 *
797 * @return int array $results contains years or months
6a488035
TO
798 * @static
799 */
800 static public function calculateAge($birthDate) {
801 $results = array();
802 $formatedBirthDate = CRM_Utils_Date::customFormat($birthDate, '%Y-%m-%d');
803
804 $bDate = explode('-', $formatedBirthDate);
805 $birthYear = $bDate[0];
806 $birthMonth = $bDate[1];
807 $birthDay = $bDate[2];
808 $year_diff = date("Y") - $birthYear;
809
810 // don't calculate age CRM-3143
811 if ($birthYear == '1902') {
812 return $results;
813 }
814
815 switch ($year_diff) {
816 case 1:
817 $month = (12 - $birthMonth) + date("m");
818 if ($month < 12) {
819 if (date("d") < $birthDay) {
820 $month--;
821 }
822 $results['months'] = $month;
823 }
824 elseif ($month == 12 && (date("d") < $birthDay)) {
825 $results['months'] = $month - 1;
826 }
827 else {
828 $results['years'] = $year_diff;
829 }
830 break;
831
832 case 0:
833 $month = date("m") - $birthMonth;
834 $results['months'] = $month;
835 break;
836
837 default:
838 $results['years'] = $year_diff;
839 if ((date("m") < $birthMonth) || (date("m") == $birthMonth) && (date("d") < $birthDay)) {
840 $results['years']--;
841 }
842 }
843
844 return $results;
845 }
846
847 /**
100fef9d 848 * Calculate next payment date according to provided unit & interval
6a488035 849 *
f4aaa82a 850 * @param string $unit frequency unit like year,month, week etc..
6a488035 851 *
f4aaa82a 852 * @param int $interval frequency interval.
6a488035 853 *
f4aaa82a
EM
854 * @param array $date start date of pledge.
855 *
856 * @param bool $dontCareTime
6a488035
TO
857 *
858 * @return array $result contains new date with added interval
6a488035 859 */
00be9182 860 public static function intervalAdd($unit, $interval, $date, $dontCareTime = FALSE) {
6a488035
TO
861 if (is_array($date)) {
862 $hour = CRM_Utils_Array::value('H', $date);
863 $minute = CRM_Utils_Array::value('i', $date);
864 $second = CRM_Utils_Array::value('s', $date);
865 $month = CRM_Utils_Array::value('M', $date);
866 $day = CRM_Utils_Array::value('d', $date);
867 $year = CRM_Utils_Array::value('Y', $date);
868 }
869 else {
870 extract(date_parse($date));
871 }
872 $date = mktime($hour, $minute, $second, $month, $day, $year);
873 switch ($unit) {
874 case 'year':
875 $date = mktime($hour, $minute, $second, $month, $day, $year + $interval);
876 break;
877
878 case 'month':
879 $date = mktime($hour, $minute, $second, $month + $interval, $day, $year);
880 break;
881
882 case 'week':
883 $interval = $interval * 7;
884 $date = mktime($hour, $minute, $second, $month, $day + $interval, $year);
885 break;
886
887 case 'day':
888 $date = mktime($hour, $minute, $second, $month, $day + $interval, $year);
889 break;
890
891 case 'second':
892 $date = mktime($hour, $minute, $second + $interval, $month, $day, $year);
893 break;
894 }
895
896 $scheduleDate = explode("-", date("n-j-Y-H-i-s", $date));
897
898 $date = array();
899 $date['M'] = $scheduleDate[0];
900 $date['d'] = $scheduleDate[1];
901 $date['Y'] = $scheduleDate[2];
902 if ($dontCareTime == FALSE) {
903 $date['H'] = $scheduleDate[3];
904 $date['i'] = $scheduleDate[4];
905 $date['s'] = $scheduleDate[5];
906 }
907 return $date;
908 }
909
910 /**
100fef9d 911 * Check given format is valid for bith date.
6a488035
TO
912 * and retrun supportable birth date format w/ qf mapping.
913 *
914 * @param $format given format ( eg 'M Y', 'Y M' )
915 * return array of qfMapping and date parts for date format.
f4aaa82a
EM
916 *
917 * @return array|null|string
6a488035 918 */
00be9182 919 public static function &checkBirthDateFormat($format = NULL) {
6a488035
TO
920 $birthDateFormat = NULL;
921 if (!$format) {
922 $birthDateFormat = self::getDateFormat('birth');
923 }
924
925 $supportableFormats = array(
926 'mm/dd' => '%B %E%f',
927 'dd-mm' => '%E%f %B',
928 'yy-mm' => '%Y %B',
929 'M yy' => '%b %Y',
930 'yy' => '%Y',
931 'dd/mm/yy' => '%E%f %B %Y',
932 );
933
934 if (array_key_exists($birthDateFormat, $supportableFormats)) {
935 $birthDateFormat = array('qfMapping' => $supportableFormats[$birthDateFormat]);
936 }
937
938 return $birthDateFormat;
939 }
940
941 /**
100fef9d 942 * Resolves the given relative time interval into finite time limits
6a488035
TO
943 *
944 * @param array $relativeTerm relative time frame like this, previous, etc
945 * @param int $unit frequency unit like year, month, week etc..
946 *
947 * @return array $dateRange start date and end date for the relative time frame
948 * @static
949 */
00be9182 950 public static function relativeToAbsolute($relativeTerm, $unit) {
6a488035
TO
951 $now = getDate();
952 $from = $to = $dateRange = array();
953 $from['H'] = $from['i'] = $from['s'] = 0;
954
955 switch ($unit) {
956 case 'year':
957 switch ($relativeTerm) {
958 case 'this':
959 $from['d'] = $from['M'] = 1;
960 $to['d'] = 31;
961 $to['M'] = 12;
962 $to['Y'] = $from['Y'] = $now['year'];
963 break;
964
965 case 'previous':
966 $from['M'] = $from['d'] = 1;
967 $to['d'] = 31;
968 $to['M'] = 12;
969 $to['Y'] = $from['Y'] = $now['year'] - 1;
970 break;
971
972 case 'previous_before':
973 $from['M'] = $from['d'] = 1;
974 $to['d'] = 31;
975 $to['M'] = 12;
976 $to['Y'] = $from['Y'] = $now['year'] - 2;
977 break;
978
979 case 'previous_2':
980 $from['M'] = $from['d'] = 1;
981 $to['d'] = 31;
982 $to['M'] = 12;
983 $from['Y'] = $now['year'] - 2;
984 $to['Y'] = $now['year'] - 1;
985 break;
986
987 case 'earlier':
988 $to['d'] = 31;
989 $to['M'] = 12;
990 $to['Y'] = $now['year'] - 1;
991 unset($from);
992 break;
993
994 case 'greater':
995 $from['M'] = $from['d'] = 1;
996 $from['Y'] = $now['year'];
997 unset($to);
998 break;
999
52f15bd6 1000 case 'greater_previous':
1001 $from['d'] = 31;
1002 $from['M'] = 12;
1003 $from['Y'] = $now['year'] - 1;
1004 unset($to);
1005 break;
1006
6a488035
TO
1007 case 'ending':
1008 $to['d'] = $now['mday'];
1009 $to['M'] = $now['mon'];
1010 $to['Y'] = $now['year'];
1011 $to['H'] = 23;
1012 $to['i'] = $to['s'] = 59;
1013 $from = self::intervalAdd('year', -1, $to);
1014 $from = self::intervalAdd('second', 1, $from);
1015 break;
e902edd1 1016
1017 case 'current':
1018 $from['M'] = $from['d'] = 1;
1019 $from['Y'] = $now['year'];
1020 $to['H'] = 23;
1021 $to['i'] = $to['s'] = 59;
1022 $to['d'] = $now['mday'];
1023 $to['M'] = $now['mon'];
1024 $to['Y'] = $now['year'];
1025 break;
e2c3163d 1026
1027 case 'ending_2':
1028 $to['d'] = $now['mday'];
1029 $to['M'] = $now['mon'];
1030 $to['Y'] = $now['year'];
1031 $to['H'] = 23;
1032 $to['i'] = $to['s'] = 59;
1033 $from = self::intervalAdd('year', -2, $to);
1034 $from = self::intervalAdd('second', 1, $from);
1035 break;
1036
1037 case 'ending_3':
1038 $to['d'] = $now['mday'];
1039 $to['M'] = $now['mon'];
1040 $to['Y'] = $now['year'];
1041 $to['H'] = 23;
1042 $to['i'] = $to['s'] = 59;
1043 $from = self::intervalAdd('year', -3, $to);
1044 $from = self::intervalAdd('second', 1, $from);
1045 break;
c5670e9e 1046
1047 case 'less':
1048 $to['d'] = 31;
1049 $to['M'] = 12;
1050 $to['Y'] = $now['year'];
1051 unset($from);
1052 break;
1053
1054 case 'next':
1055 $from['M'] = $from['d'] = 1;
1056 $to['d'] = 31;
1057 $to['M'] = 12;
1058 $to['Y'] = $from['Y'] = $now['year'] + 1;
1059 break;
1060
1061 case 'starting':
1062 $from['d'] = $now['mday'];
1063 $from['M'] = $now['mon'];
1064 $from['Y'] = $now['year'];
1065 $to['d'] = $now['mday'] - 1;
1066 $to['M'] = $now['mon'];
1067 $to['Y'] = $now['year'] + 1;
1068 break;
6a488035
TO
1069 }
1070 break;
1071
1072 case 'fiscal_year':
1073 $config = CRM_Core_Config::singleton();
1074 $from['d'] = $config->fiscalYearStart['d'];
1075 $from['M'] = $config->fiscalYearStart['M'];
1076 $fYear = self::calculateFiscalYear($from['d'], $from['M']);
1077 switch ($relativeTerm) {
1078 case 'this':
1079 $from['Y'] = $fYear;
1080 $fiscalYear = mktime(0, 0, 0, $from['M'], $form['d'], $from['Y'] + 1);
1081 $fiscalEnd = explode('-', date("Y-m-d", $fiscalYear));
1082
1083 $to['d'] = $fiscalEnd['2'];
1084 $to['M'] = $fiscalEnd['1'];
1085 $to['Y'] = $fiscalEnd['0'];
1086 break;
1087
1088 case 'previous':
1089 $from['Y'] = $fYear - 1;
1090 $fiscalYear = mktime(0, 0, 0, $from['M'], $form['d'], $from['Y'] + 1);
1091 $fiscalEnd = explode('-', date("Y-m-d", $fiscalYear));
c5670e9e 1092 $to['d'] = $fiscalEnd['2'];
1093 $to['M'] = $fiscalEnd['1'];
1094 $to['Y'] = $fiscalEnd['0'];
1095 break;
6a488035 1096
c5670e9e 1097 case 'next':
1098 $from['Y'] = $fYear + 1;
1099 $fiscalYear = mktime(0, 0, 0, $from['M'], $from['d'], $from['Y'] + 1);
1100 $fiscalEnd = explode('-', date("Y-m-d", $fiscalYear));
6a488035
TO
1101 $to['d'] = $fiscalEnd['2'];
1102 $to['M'] = $fiscalEnd['1'];
1103 $to['Y'] = $fiscalEnd['0'];
1104 break;
1105 }
1106 break;
1107
1108 case 'quarter':
1109 switch ($relativeTerm) {
1110 case 'this':
1111
1112 $quarter = ceil($now['mon'] / 3);
1113 $from['d'] = 1;
1114 $from['M'] = (3 * $quarter) - 2;
1115 $to['M'] = 3 * $quarter;
1116 $to['Y'] = $from['Y'] = $now['year'];
1117 $to['d'] = date('t', mktime(0, 0, 0, $to['M'], 1, $now['year']));
1118 break;
1119
1120 case 'previous':
1121 $difference = 1;
1122 $quarter = ceil($now['mon'] / 3);
1123 $quarter = $quarter - $difference;
1124 $subtractYear = 0;
1125 if ($quarter <= 0) {
1126 $subtractYear = 1;
1127 $quarter += 4;
1128 }
1129 $from['d'] = 1;
1130 $from['M'] = (3 * $quarter) - 2;
1131 $to['M'] = 3 * $quarter;
1132 $to['Y'] = $from['Y'] = $now['year'] - $subtractYear;
1133 $to['d'] = date('t', mktime(0, 0, 0, $to['M'], 1, $to['Y']));
1134 break;
1135
1136 case 'previous_before':
1137 $difference = 2;
1138 $quarter = ceil($now['mon'] / 3);
1139 $quarter = $quarter - $difference;
d75f2f47 1140 $subtractYear = 0;
6a488035
TO
1141 if ($quarter <= 0) {
1142 $subtractYear = 1;
1143 $quarter += 4;
1144 }
1145 $from['d'] = 1;
1146 $from['M'] = (3 * $quarter) - 2;
1147 $to['M'] = 3 * $quarter;
1148 $to['Y'] = $from['Y'] = $now['year'] - $subtractYear;
1149 $to['d'] = date('t', mktime(0, 0, 0, $to['M'], 1, $to['Y']));
1150 break;
1151
1152 case 'previous_2':
1153 $difference = 2;
1154 $quarter = ceil($now['mon'] / 3);
1155 $current_quarter = $quarter;
1156 $quarter = $quarter - $difference;
1157 $subtractYear = 0;
1158 if ($quarter <= 0) {
1159 $subtractYear = 1;
1160 $quarter += 4;
1161 }
1162 $from['d'] = 1;
1163 $from['M'] = (3 * $quarter) - 2;
1164 switch ($current_quarter) {
1165 case 1:
1166 $to['M'] = (4 * $quarter);
1167 break;
1168
1169 case 2:
1170 $to['M'] = (4 * $quarter) + 3;
1171 break;
1172
1173 case 3:
1174 $to['M'] = (4 * $quarter) + 2;
1175 break;
1176
1177 case 4:
1178 $to['M'] = (4 * $quarter) + 1;
1179 break;
1180 }
1181 $to['Y'] = $from['Y'] = $now['year'] - $subtractYear;
1182 if ($to['M'] > 12) {
1183 $to['M'] = 3 * ($quarter - 3);
1184 $to['Y'] = $now['year'];
1185 }
1186 $to['d'] = date('t', mktime(0, 0, 0, $to['M'], 1, $to['Y']));
1187 break;
1188
1189 case 'earlier':
1190 $quarter = ceil($now['mon'] / 3) - 1;
d75f2f47 1191 $subtractYear = 0;
6a488035
TO
1192 if ($quarter <= 0) {
1193 $subtractYear = 1;
1194 $quarter += 4;
1195 }
1196 $to['M'] = 3 * $quarter;
1197 $to['Y'] = $from['Y'] = $now['year'] - $subtractYear;
1198 $to['d'] = date('t', mktime(0, 0, 0, $to['M'], 1, $to['Y']));
1199 unset($from);
1200 break;
1201
1202 case 'greater':
1203 $quarter = ceil($now['mon'] / 3);
1204 $from['d'] = 1;
1205 $from['M'] = (3 * $quarter) - 2;
1206 $from['Y'] = $now['year'];
1207 unset($to);
1208 break;
d75f2f47 1209
52f15bd6 1210 case 'greater_previous':
1211 $quarter = ceil($now['mon'] / 3) - 1;
d75f2f47 1212 $subtractYear = 0;
52f15bd6 1213 if ($quarter <= 0) {
1214 $subtractYear = 1;
1215 $quarter += 4;
1216 }
1217 $from['M'] = 3 * $quarter;
1218 $from['Y'] = $from['Y'] = $now['year'] - $subtractYear;
1219 $from['d'] = date('t', mktime(0, 0, 0, $from['M'], 1, $from['Y']));
1220 unset($to);
1221 break;
6a488035
TO
1222
1223 case 'ending':
1224 $to['d'] = $now['mday'];
1225 $to['M'] = $now['mon'];
1226 $to['Y'] = $now['year'];
1227 $to['H'] = 23;
1228 $to['i'] = $to['s'] = 59;
1229 $from = self::intervalAdd('month', -3, $to);
1230 $from = self::intervalAdd('second', 1, $from);
1231 break;
e902edd1 1232
1233 case 'current':
1234 $quarter = ceil($now['mon'] / 3);
1235 $from['d'] = 1;
1236 $from['M'] = (3 * $quarter) - 2;
1237 $from['Y'] = $now['year'];
1238 $to['d'] = $now['mday'];
1239 $to['M'] = $now['mon'];
1240 $to['Y'] = $now['year'];
1241 $to['H'] = 23;
1242 $to['i'] = $to['s'] = 59;
1243 break;
c5670e9e 1244
1245 case 'less':
1246 $quarter = ceil($now['mon'] / 3);
1247 $to['M'] = 3 * $quarter;
1248 $to['Y'] = $now['year'];
1249 $to['d'] = date('t', mktime(0, 0, 0, $to['M'], 1, $now['year']));
1250 unset($from);
1251 break;
1252
1253 case 'next':
1254 $difference = -1;
1255 $subtractYear = 0;
1256 $quarter = ceil($now['mon'] / 3);
1257 $quarter = $quarter - $difference;
1258 //CRM-14550 QA Fix
1259 if($quarter > 4) {
1260 $now['year'] = $now['year'] + 1;
1261 $quarter = 1;
1262 }
1263 if ($quarter <= 0) {
1264 $subtractYear = 1;
1265 $quarter += 4;
1266 }
1267 $from['d'] = 1;
1268 $from['M'] = (3 * $quarter) - 2;
1269 $to['M'] = 3 * $quarter;
1270 $to['Y'] = $from['Y'] = $now['year'] - $subtractYear;
1271 $to['d'] = date('t', mktime(0, 0, 0, $to['M'], 1, $to['Y']));
1272 break;
6a488035
TO
1273 }
1274 break;
1275
1276 case 'month':
1277 switch ($relativeTerm) {
1278 case 'this':
1279 $from['d'] = 1;
1280 $to['d'] = date('t', mktime(0, 0, 0, $now['mon'], 1, $now['year']));
1281 $from['M'] = $to['M'] = $now['mon'];
1282 $from['Y'] = $to['Y'] = $now['year'];
1283 break;
1284
1285 case 'previous':
1286 $from['d'] = 1;
1287 if ($now['mon'] == 1) {
1288 $from['M'] = $to['M'] = 12;
1289 $from['Y'] = $to['Y'] = $now['year'] - 1;
1290 }
1291 else {
1292 $from['M'] = $to['M'] = $now['mon'] - 1;
1293 $from['Y'] = $to['Y'] = $now['year'];
1294 }
1295 $to['d'] = date('t', mktime(0, 0, 0, $to['M'], 1, $to['Y']));
1296 break;
1297
1298 case 'previous_before':
1299 $from['d'] = 1;
1300 if ($now['mon'] < 3) {
1301 $from['M'] = $to['M'] = 10 + $now['mon'];
1302 $from['Y'] = $to['Y'] = $now['year'] - 1;
1303 }
1304 else {
1305 $from['M'] = $to['M'] = $now['mon'] - 2;
1306 $from['Y'] = $to['Y'] = $now['year'];
1307 }
1308 $to['d'] = date('t', mktime(0, 0, 0, $to['M'], 1, $to['Y']));
1309 break;
1310
1311 case 'previous_2':
1312 $from['d'] = 1;
1313 if ($now['mon'] < 3) {
1314 $from['M'] = 10 + $now['mon'];
1315 $from['Y'] = $now['year'] - 1;
1316 }
1317 else {
1318 $from['M'] = $now['mon'] - 2;
1319 $from['Y'] = $now['year'];
1320 }
1321
1322 if ($now['mon'] == 1) {
1323 $to['M'] = 12;
1324 $to['Y'] = $now['year'] - 1;
1325 }
1326 else {
1327 $to['M'] = $now['mon'] - 1;
1328 $to['Y'] = $now['year'];
1329 }
1330
1331 $to['d'] = date('t', mktime(0, 0, 0, $to['M'], 1, $to['Y']));
1332 break;
1333
1334 case 'earlier':
1335 //before end of past month
1336 if ($now['mon'] == 1) {
1337 $to['M'] = 12;
1338 $to['Y'] = $now['year'] - 1;
1339 }
1340 else {
1341 $to['M'] = $now['mon'] - 1;
1342 $to['Y'] = $now['year'];
1343 }
1344
1345 $to['d'] = date('t', mktime(0, 0, 0, $to['M'], 1, $to['Y']));
1346 unset($from);
1347 break;
1348
1349 case 'greater':
1350 $from['d'] = 1;
1351 $from['M'] = $now['mon'];;
1352 $from['Y'] = $now['year'];
1353 unset($to);
1354 break;
1355
52f15bd6 1356 case 'greater_previous':
1357 //from end of past month
1358 if ($now['mon'] == 1) {
1359 $from['M'] = 12;
1360 $from['Y'] = $now['year'] - 1;
1361 }
1362 else {
1363 $from['M'] = $now['mon'] - 1;
1364 $from['Y'] = $now['year'];
1365 }
1366
1367 $from['d'] = date('t', mktime(0, 0, 0, $from['M'], 1, $from['Y']));
1368 unset($to);
1369 break;
1370
6a488035
TO
1371 case 'ending':
1372 $to['d'] = $now['mday'];
1373 $to['M'] = $now['mon'];
1374 $to['Y'] = $now['year'];
1375 $to['H'] = 23;
1376 $to['i'] = $to['s'] = 59;
1377 $from = self::intervalAdd('month', -1, $to);
1378 $from = self::intervalAdd('second', 1, $from);
1379 break;
e902edd1 1380
1381 case 'current':
1382 $from['d'] = 1;
1383 $from['M'] = $now['mon'];;
1384 $from['Y'] = $now['year'];
1385 $to['d'] = $now['mday'];
1386 $to['M'] = $now['mon'];
1387 $to['Y'] = $now['year'];
1388 $to['H'] = 23;
1389 $to['i'] = $to['s'] = 59;
1390 break;
c5670e9e 1391
1392 case 'less':
1393 //CRM-14550 QA Fix
1394 $to['Y'] = $now['year'];
1395 $to['M'] = $now['mon'];
1396 $to['d'] = date('t', mktime(0, 0, 0, $now['mon'], 1, $now['year']));
1397 unset($from);
1398 break;
1399
1400 case 'next':
1401 $from['d'] = 1;
1402 if ($now['mon'] == 12) {
1403 $from['M'] = $to['M'] = 1;
1404 $from['Y'] = $to['Y'] = $now['year'] + 1;
1405 }
1406 else {
1407 $from['M'] = $to['M'] = $now['mon'] + 1;
1408 $from['Y'] = $to['Y'] = $now['year'];
1409 }
1410 $to['d'] = date('t', mktime(0, 0, 0, $to['M'], 1, $to['Y']));
1411 break;
1412
1413 case 'starting':
1414 $from['d'] = $now['mday'];
1415 $from['M'] = $now['mon'];
1416 $from['Y'] = $now['year'];
1417 $from['H'] = 00;
1418 $from['i'] = $to['s'] = 00;
1419 $to = self::intervalAdd('month', +1, $from);
1420 $to = self::intervalAdd('second',-1, $to);
1421 break;
6a488035
TO
1422 }
1423 break;
1424
1425 case 'week':
1426 switch ($relativeTerm) {
1427 case 'this':
1428 $from['d'] = $now['mday'];
1429 $from['M'] = $now['mon'];
1430 $from['Y'] = $now['year'];
1431 $from = self::intervalAdd('day', -1 * ($now['wday']), $from);
1432 $to = self::intervalAdd('day', 6, $from);
1433 break;
1434
1435 case 'previous':
1436 $from['d'] = $now['mday'];
1437 $from['M'] = $now['mon'];
1438 $from['Y'] = $now['year'];
1439 $from = self::intervalAdd('day', -1 * ($now['wday']) - 7, $from);
1440 $to = self::intervalAdd('day', 6, $from);
1441 break;
1442
1443 case 'previous_before':
1444 $from['d'] = $now['mday'];
1445 $from['M'] = $now['mon'];
1446 $from['Y'] = $now['year'];
1447 $from = self::intervalAdd('day', -1 * ($now['wday']) - 14, $from);
1448 $to = self::intervalAdd('day', 6, $from);
1449 break;
1450
1451 case 'previous_2':
1452 $from['d'] = $now['mday'];
1453 $from['M'] = $now['mon'];
1454 $from['Y'] = $now['year'];
1455 $from = self::intervalAdd('day', -1 * ($now['wday']) - 14, $from);
1456 $to = self::intervalAdd('day', 13, $from);
1457 break;
1458
1459 case 'earlier':
1460 $to['d'] = $now['mday'];
1461 $to['M'] = $now['mon'];
1462 $to['Y'] = $now['year'];
1463 $to = self::intervalAdd('day', -1 * ($now['wday']) - 1, $to);
1464 unset($from);
1465 break;
1466
1467 case 'greater':
1468 $from['d'] = $now['mday'];
1469 $from['M'] = $now['mon'];
1470 $from['Y'] = $now['year'];
1471 $from = self::intervalAdd('day', -1 * ($now['wday']), $from);
1472 unset($to);
1473 break;
1474
52f15bd6 1475 case 'greater_previous':
1476 $from['d'] = $now['mday'];
1477 $from['M'] = $now['mon'];
1478 $from['Y'] = $now['year'];
1479 $from = self::intervalAdd('day', -1 * ($now['wday']) - 1, $from);
1480 unset($to);
1481 break;
1482
6a488035
TO
1483 case 'ending':
1484 $to['d'] = $now['mday'];
1485 $to['M'] = $now['mon'];
1486 $to['Y'] = $now['year'];
1487 $to['H'] = 23;
1488 $to['i'] = $to['s'] = 59;
1489 $from = self::intervalAdd('day', -7, $to);
1490 $from = self::intervalAdd('second', 1, $from);
1491 break;
e902edd1 1492
1493 case 'current':
1494 $from['d'] = $now['mday'];
1495 $from['M'] = $now['mon'];
1496 $from['Y'] = $now['year'];
1497 $from = self::intervalAdd('day', -1 * ($now['wday']), $from);
1498 $to['d'] = $now['mday'];
1499 $to['M'] = $now['mon'];
1500 $to['Y'] = $now['year'];
1501 $to['H'] = 23;
1502 $to['i'] = $to['s'] = 59;
1503 break;
c5670e9e 1504
1505 case 'less':
1506 $to['d'] = $now['mday'];
1507 $to['M'] = $now['mon'];
1508 $to['Y'] = $now['year'];
1509 //CRM-14550 QA Fix
1510 $to = self::intervalAdd('day', -1 * ($now['wday']) + 6, $to);
1511 unset($from);
1512 break;
1513
1514 case 'next':
1515 $from['d'] = $now['mday'];
1516 $from['M'] = $now['mon'];
1517 $from['Y'] = $now['year'];
1518 $from = self::intervalAdd('day', -1 * ($now['wday']) + 7, $from);
1519 $to = self::intervalAdd('day', +6, $from);
1520 break;
1521
1522 case 'starting':
1523 $from['d'] = $now['mday'];
1524 $from['M'] = $now['mon'];
1525 $from['Y'] = $now['year'];
1526 $from['H'] = 00;
1527 $from['i'] = $to['s'] = 00;
1528 $to = self::intervalAdd('day', +7, $from);
1529 $to = self::intervalAdd('second', -1, $to);
1530 break;
6a488035
TO
1531 }
1532 break;
1533
1534 case 'day':
1535 switch ($relativeTerm) {
1536 case 'this':
1537 $from['d'] = $to['d'] = $now['mday'];
1538 $from['M'] = $to['M'] = $now['mon'];
1539 $from['Y'] = $to['Y'] = $now['year'];
1540 break;
1541
1542 case 'previous':
1543 $from['d'] = $now['mday'];
1544 $from['M'] = $now['mon'];
1545 $from['Y'] = $now['year'];
1546 $from = self::intervalAdd('day', -1, $from);
1547 $to['d'] = $from['d'];
1548 $to['M'] = $from['M'];
1549 $to['Y'] = $from['Y'];
1550 break;
1551
1552 case 'previous_before':
1553 $from['d'] = $now['mday'];
1554 $from['M'] = $now['mon'];
1555 $from['Y'] = $now['year'];
1556 $from = self::intervalAdd('day', -2, $from);
1557 $to['d'] = $from['d'];
1558 $to['M'] = $from['M'];
1559 $to['Y'] = $from['Y'];
1560 break;
1561
1562 case 'previous_2':
1563 $from['d'] = $to['d'] = $now['mday'];
1564 $from['M'] = $to['M'] = $now['mon'];
1565 $from['Y'] = $to['Y'] = $now['year'];
1566 $from = self::intervalAdd('day', -2, $from);
1567 $to = self::intervalAdd('day', -1, $to);
1568 break;
1569
1570 case 'earlier':
1571 $to['d'] = $now['mday'];
1572 $to['M'] = $now['mon'];
1573 $to['Y'] = $now['year'];
1574 unset($from);
1575 break;
1576
1577 case 'greater':
1578 $from['d'] = $now['mday'];
1579 $from['M'] = $now['mon'];;
1580 $from['Y'] = $now['year'];
1581 unset($to);
1582 break;
c5670e9e 1583
1584 case 'starting':
1585 $to['d'] = $now['mday'];
1586 $to['M'] = $now['mon'];
1587 $to['Y'] = $now['year'];
1588 $to = self::intervalAdd('day', +1, $to);
1589 $from['d'] = $to['d'];
1590 $from['M'] = $to['M'];
1591 $from['Y'] = $to['Y'];
1592 break;
1593
6a488035
TO
1594 }
1595 break;
1596 }
1597
1598 foreach (array(
1599 'from', 'to') as $item) {
1600 if (!empty($$item)) {
1601 $dateRange[$item] = self::format($$item);
1602 }
1603 else {
1604 $dateRange[$item] = NULL;
1605 }
1606 }
1607 return $dateRange;
1608 }
1609
1610 /**
100fef9d 1611 * Calculate current fiscal year based on the fiscal month and day
6a488035
TO
1612 *
1613 * @param int $fyDate Fiscal start date
1614 *
1615 * @param int $fyMonth Fiscal Start Month
1616 *
1617 * @return int $fy Current Fiscl Year
6a488035
TO
1618 * @static
1619 */
00be9182 1620 public static function calculateFiscalYear($fyDate, $fyMonth) {
6a488035
TO
1621 $date = date("Y-m-d");
1622 $currentYear = date("Y");
1623
1624 //recalculate the date because month 4::04 make the difference
1625 $fiscalYear = explode('-', date("Y-m-d", mktime(0, 0, 0, $fyMonth, $fyDate, $currentYear)));
1626 $fyDate = $fiscalYear[2];
1627 $fyMonth = $fiscalYear[1];
1628 $fyStartDate = date("Y-m-d", mktime(0, 0, 0, $fyMonth, $fyDate, $currentYear));
1629
1630 if ($fyStartDate > $date) {
1631 $fy = intval(intval($currentYear) - 1);
1632 }
1633 else {
1634 $fy = intval($currentYear);
1635 }
1636 return $fy;
1637 }
1638
1639 /**
1640 * Function to process date, convert to mysql format
1641 *
f4aaa82a
EM
1642 * @param string $date date string
1643 * @param string $time time string
1644 * @param bool|string $returnNullString 'null' needs to be returned
6a488035 1645 * so that db oject will set null in db
f4aaa82a 1646 * @param string $format expected return date format.( default is mysql )
6a488035 1647 *
f4aaa82a 1648 * @return string $mysqlDate date format that is excepted by mysql
6a488035 1649 */
00be9182 1650 public static function processDate($date, $time = NULL, $returnNullString = FALSE, $format = 'YmdHis') {
6a488035
TO
1651 $mysqlDate = NULL;
1652
1653 if ($returnNullString) {
1654 $mysqlDate = 'null';
1655 }
1656
1657 if (trim($date)) {
1658 $mysqlDate = date($format, strtotime($date . ' ' . $time));
1659 }
1660
1661 return $mysqlDate;
1662 }
1663
1664 /**
1665 * Function to convert mysql to date plugin format
1666 *
f4aaa82a
EM
1667 * @param string $mysqlDate date string
1668 *
1669 * @param null $formatType
1670 * @param null $format
1671 * @param null $timeFormat
6a488035 1672 *
f4aaa82a 1673 * @return array $date and time
6a488035 1674 */
00be9182 1675 public static function setDateDefaults($mysqlDate = NULL, $formatType = NULL, $format = NULL, $timeFormat = NULL) {
6a488035
TO
1676 // if date is not passed assume it as today
1677 if (!$mysqlDate) {
1678 $mysqlDate = date('Y-m-d G:i:s');
1679 }
1680
1681 $config = CRM_Core_Config::singleton();
1682 if ($formatType) {
1683 // get actual format
1684 $params = array('name' => $formatType);
1685 $values = array();
1686 CRM_Core_DAO::commonRetrieve('CRM_Core_DAO_PreferencesDate', $params, $values);
1687
1688 if ($values['date_format']) {
1689 $format = $values['date_format'];
1690 }
1691
1692 if (isset($values['time_format'])) {
1693 $timeFormat = $values['time_format'];
1694 }
1695 }
1696
1697 // now we set display date using js, hence we should always setdefault
1698 // 'm/d/Y' format. So that submitted value is alwats mm/dd/YY format
1699 // note that for date display we dynamically create text field
1700 /*
1701 if ( !$format ) {
1702 $format = $config->dateInputFormat;
1703 }
1704
1705 // get actual format
1706 $actualPHPFormats = CRM_Core_SelectValues::datePluginToPHPFormats( );
1707 $dateFormat = CRM_Utils_Array::value( $format, $actualPHPFormats );
1708 */
1709
1710
1711 $dateFormat = 'm/d/Y';
1712 $date = date($dateFormat, strtotime($mysqlDate));
1713
1714 if (!$timeFormat) {
1715 $timeFormat = $config->timeInputFormat;
1716 }
1717
1718 $actualTimeFormat = "g:iA";
1719 $appendZeroLength = 7;
1720 if ($timeFormat > 1) {
1721 $actualTimeFormat = "G:i";
1722 $appendZeroLength = 5;
1723 }
1724
1725 $time = date($actualTimeFormat, strtotime($mysqlDate));
1726
1727 // need to append zero for hours < 10
1728 if (strlen($time) < $appendZeroLength) {
1729 $time = '0' . $time;
1730 }
1731
1732 return array($date, $time);
1733 }
1734
1735 /**
1736 * Function get date format
1737 *
1738 * @param string $formatType Date name e.g. birth
1739 *
1740 * @return string $format
1741 */
00be9182 1742 public static function getDateFormat($formatType = NULL) {
6a488035
TO
1743 $format = NULL;
1744 if ($formatType) {
395d8dc6 1745 $format = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_PreferencesDate',
6a488035
TO
1746 $formatType, 'date_format', 'name'
1747 );
1748 }
1749
1750 if (!$format) {
1751 $config = CRM_Core_Config::singleton();
1752 $format = $config->dateInputFormat;
1753 }
1754 return $format;
1755 }
1756
cf142e47
DL
1757 /**
1758 * Get the time in UTC for the current time. You can optionally send an offset from the current time if needed
1759 *
1760 * @param $offset int the offset from the current time in seconds
1761 *
1762 * @return the time in UTC
1763 * @static
cf142e47 1764 */
00be9182 1765 public static function getUTCTime($offset = 0) {
6a488035
TO
1766 $originalTimezone = date_default_timezone_get();
1767 date_default_timezone_set('UTC');
1768 $time = time() + $offset;
1769 $now = date('YmdHis', $time);
1770 date_default_timezone_set($originalTimezone);
1771 return $now;
1772 }
1773
1774
5bc392e6
EM
1775 /**
1776 * @param $date
1777 * @param $dateType
1778 *
1779 * @return null|string
1780 */
00be9182 1781 public static function formatDate($date, $dateType) {
6a488035
TO
1782 $formattedDate = NULL;
1783 if (empty($date)) {
1784 return $formattedDate;
1785 }
1786
1787 //1. first convert date to default format.
1788 //2. append time to default formatted date (might be removed during format)
1789 //3. validate date / date time.
1790 //4. If date and time then convert to default date time format.
1791
1792 $dateKey = 'date';
1793 $dateParams = array($dateKey => $date);
1794
1795 if (CRM_Utils_Date::convertToDefaultDate($dateParams, $dateType, $dateKey)) {
1796 $dateVal = $dateParams[$dateKey];
1797 $ruleName = 'date';
1798 if ($dateType == 1) {
1799 $matches = array();
1800 if (preg_match("/(\s(([01]\d)|[2][0-3]):([0-5]\d))$/", $date, $matches)) {
1801 $ruleName = 'dateTime';
1802 if (strpos($date, '-') !== FALSE) {
1803 $dateVal .= array_shift($matches);
1804 }
1805 }
1806 }
1807
1808 // validate date.
0e6e8724 1809 $valid = CRM_Utils_Rule::$ruleName($dateVal);
6a488035
TO
1810
1811 if ($valid) {
1812 //format date and time to default.
1813 if ($ruleName == 'dateTime') {
1814 $dateVal = CRM_Utils_Date::customFormat(preg_replace("/(:|\s)?/", "", $dateVal), '%Y%m%d%H%i');
1815 //hack to add seconds
1816 $dateVal .= '00';
1817 }
1818 $formattedDate = $dateVal;
1819 }
1820 }
1821
1822 return $formattedDate;
1823 }
1824
1825}