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