2 if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
3 /*********************************************************************************
4 * SugarCRM is a customer relationship management program developed by
5 * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc.
7 * This program is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU Affero General Public License version 3 as published by the
9 * Free Software Foundation with the addition of the following permission added
10 * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
11 * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
12 * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
19 * You should have received a copy of the GNU Affero General Public License along with
20 * this program; if not, see http://www.gnu.org/licenses or write to the Free
21 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24 * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
25 * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
27 * The interactive user interfaces in modified source and object code versions
28 * of this program must display Appropriate Legal Notices, as required under
29 * Section 5 of the GNU Affero General Public License version 3.
31 * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
32 * these Appropriate Legal Notices must retain the display of the "Powered by
33 * SugarCRM" logo. If the display of the logo is not reasonably feasible for
34 * technical reasons, the Appropriate Legal Notices must display the words
35 * "Powered by SugarCRM".
36 ********************************************************************************/
38 require_once('include/timezone/timezones.php');
41 * Date/time conversion class
43 * DB format - Y-m-d H:i:s (2009-12-31 23:46:12), in GMT
44 * Display format - user-defined, in user-supplied timezone
52 var $dbDayFormat = 'Y-m-d';
57 var $dbTimeFormat = 'H:i:s';
59 * DB date & time formats
63 var $dbDateTimeFormat = 'Y-m-d H:i:s';
65 protected $supported_strings = array(
78 * Map the tokens passed into this as a "format" string to
79 * PHP's internal date() format string values.
85 private $time_token_map = array(
86 'a' => 'a', // meridiem: am or pm
87 'A' => 'A', // meridiem: AM or PM
88 'd' => 'd', // days: 1 through 31
89 'h' => 'h', // hours: 01 through 12
90 'H' => 'H', // hours: 00 through 23
91 'i' => 'i', // minutes: 00 through 59
92 'm' => 'm', // month: 1 - 12
93 'Y' => 'Y', // year: four digits
94 's' => 's', // seconds
98 * The current timezone information for the current user
101 private $current_user_timezone = null;
104 * The current user timezone adjustment
107 private $current_user_adjustment = null;
109 * The target TZ for current user timezone adjustment
112 private $current_user_adjustment_tz = null;
115 * Default midnight string in user format
118 private $default_midnight = null;
121 * For testability - disallow using cache
124 public $allow_cache = true;
129 public function __construct()
131 // avoids a potential E_STRICT warning when using any date function
132 if ( function_exists('date_default_timezone_set') && function_exists('date_default_timezone_get'))
133 date_default_timezone_set(@date_default_timezone_get());
137 * Returns the current users timezone info or another user;
139 * @param User $user user object for which you want to display, null for current user
140 * @return Array of timezone info
142 public function getUserTimeZone($user = null){
143 global $timezones, $current_user;
144 $usertimezone = array();
145 if(empty($user) || (!empty($user->id) && $user->id == $current_user->id)) {
146 if(isset($this->current_user_timezone)) return $this->current_user_timezone; // current user, return saved timezone info
147 $user = $current_user;
152 if($usertimezone = $user->getPreference('timezone')) {
153 if(empty($timezones[$usertimezone])) {
154 $GLOBALS['log']->fatal('TIMEZONE:NOT DEFINED-'. $usertimezone);
155 $usertimezone = array();
157 $usertimezone = $timezones[$usertimezone];
162 if(!empty($user->id) && $user->id == $current_user->id) $this->current_user_timezone = $usertimezone; // save current_user
163 return $usertimezone;
167 * @deprecated for public use
168 * function adjustmentForUserTimeZone()
169 * this returns the adjustment for a user against the server time
171 * @param array $timezone_to_adjust pass in a timezone to adjust for
172 * @return integer number of minutes to adjust a time by to get the appropriate time for the user
174 public function adjustmentForUserTimeZone($timezone_to_adjust = null){
175 if(isset($this->current_user_adjustment) && $this->current_user_adjustment_tz == $timezone_to_adjust){
176 return $this->current_user_adjustment;
180 $this->current_user_adjustment_tz = $timezone_to_adjust;
182 if(empty($timezone_to_adjust)) {
183 $timezone = $this->getUserTimeZone();
185 $timezone = $timezone_to_adjust;
187 if(empty($timezone)) {
191 $server_offset = date('Z')/60;
192 $server_in_ds = date('I');
193 $user_in_ds = $this->inDST(date('Y-m-d H:i:s'), $timezone);
194 $user_offset = $timezone['gmtOffset'] ;
196 //compensate for ds for user
202 $adjustment += $server_offset - $user_offset;
203 if(empty($timezone_to_adjust)) $this->current_user_adjustment = $adjustment; // save current_user adj
209 * @deprecated for public use
210 * function getWeekDayName($indexOfDay)
211 * Returns a days name
213 * @param INT(WEEKDAY INDEX) $indexOfDay
214 * @return STRING representing the given weekday
216 function getWeekDayName($indexOfDay){
217 static $dow = array ( 'sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday' );
218 return $dow[$indexOfDay];
221 * @deprecated for public use
222 * function getMonthName($indexMonth)
223 * Returns a Months Name
225 * @param INT(MONTH INDEX) $indexMonth
226 * @return STRING representation of the month
228 function getMonthName($indexMonth){
229 static $months = array ( 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' );
230 return $months[$indexMonth];
234 * @deprecated for public use
235 * function getDateFromRules($year, $startMonth, $startDate, $weekday, $startTime )
236 * Converts the rules for a timezones dst into a string representation of a date for the given year
238 * @param STRING(YEAR) $year
239 * @param INT(MONTH INDEX) $startMonth
240 * @param INT(DATE INDEX) $startDate
241 * @param INT(WEEKDAY INDEX) $weekday
242 * @param INT(START TIME IN SECONDS) $startTime
245 function getDateFromRules($year, $startMonth, $startDate, $weekday, $startTime ){
246 if($weekday < 0)return date( 'Y-m-d H:i:s', strtotime("$year-$startMonth-$startDate") + $startTime);
247 $dayname = self::getWeekDayName($weekday);
248 if($startDate > 0)$startMonth--;
249 $month = self::getMonthName($startMonth);
250 $startWeek = floor($startDate/7);
251 //echo "$startWeek week $dayname - $month 1, $year<br>";
252 return date( 'Y-m-d H:i:s', strtotime( "$startWeek week $dayname", strtotime( "$month 1, $year" ) ) + $startTime );
257 * @deprecated for public use
258 * function getDSTRange($year, $zone)
260 * returns the start and end date for dst for a given timezone and year or false if that zone doesn't support dst
262 * @param STRING(Year e.g. 2005) $year
263 * @param ARRAY (TIME ZONE INFO) $zone
264 * @return ARRAY OF DATE REPRESENTING THE START AND END OF DST or FALSE if the zone doesn't support dst
266 function getDSTRange($year, $zone){
268 if(empty($zone['dstOffset'])){
272 $range['start'] = $this->getDateFromRules($year, $zone['dstMonth'], $zone['dstStartday'], $zone['dstWeekday'], $zone['dstStartTimeSec']);
273 $range['end'] = $this->getDateFromRules($year, $zone['stdMonth'], $zone['stdStartday'], $zone['stdWeekday'], $zone['stdStartTimeSec']);
278 * @deprecated for public use
280 * Is the date in DST or not
284 function inDST($date, $zone){
285 $datetime = explode(' ', $date);
286 $dateSplit = explode('-', $datetime[0]);
287 if(empty($dateSplit[2]))return false;
288 $dstRange = $this->getDSTRange($dateSplit[0], $zone);
292 $datestamp = strtotime($date);
293 $startstamp = strtotime($dstRange['start']);
294 $endstamp = strtotime($dstRange['end']);
295 if((($datestamp >= $startstamp || $datestamp < $endstamp) && $startstamp > $endstamp)
296 || ($datestamp >= $startstamp && $datestamp < $endstamp)
304 * Create regexp from datetime format
305 * @param string $format
306 * @return string Regular expression string
308 function get_regular_expression($format) {
310 $regPositions = array();
311 $ignoreNextChar = false;
313 $format_characters = str_split($format, 1);
314 foreach ($format_characters as $char) {
315 if (!$ignoreNextChar && isset($this->supported_strings[$char])) {
316 $newFormat.= '('.$this->supported_strings[$char].')';
317 $regPositions[$char] = $count;
320 $ignoreNextChar = false;
326 $ignoreNextChar = true;
330 return array('format'=>$newFormat, 'positions'=>$regPositions);
335 * Verify if the date string conforms to a format
337 * @param string $date
338 * @param string $format Format to check
339 * @param string $toformat
340 * @return bool Is the date ok?
342 public function check_matching_format($date, $format, $toformat = '') {
344 $startreg = $this->get_regular_expression($format);
345 if (!empty($toformat)) {
346 $otherreg = $this->get_regular_expression($toformat);
347 //if the other format has the same regular expression then maybe it is shifting month and day position or something similar let it go for formating
348 if ($startreg['format'] == $otherreg['format']) {
353 preg_match('@'.$startreg['format'].'@', $date, $regs);
361 * @deprecated for public use
362 * Build a true PHP format string from a user supplied format string
364 * @param string $format
367 * @see $time_token_map
369 function build_format($format)
371 $format = str_split($format, 1);
373 foreach ($format as $char) {
374 $return .= (isset($this->time_token_map[$char])) ?
375 $this->time_token_map[$char] :
382 * Convert date from one format to another
384 * @param string $date
385 * @param string $from
389 function swap_formats($date, $startFormat, $endFormat) {
390 $startreg = $this->get_regular_expression($startFormat);
391 preg_match('@'.$startreg['format'].'@', $date, $regs);
392 $newDate = $endFormat;
393 //handle 12 to 24 hour conversion
394 if (isset($startreg['positions']['h']) && !isset($startreg['positions']['H']) && !empty($regs[$startreg['positions']['h']]) && $regs[$startreg['positions']['h']] !== '' && strpos($endFormat, 'H') > -1) {
395 $startreg['positions']['H'] = sizeof($startreg['positions']) + 1;
396 $regs[$startreg['positions']['H']] = $regs[$startreg['positions']['h']];
397 if ((isset($startreg['positions']['A']) && isset($regs[$startreg['positions']['A']]) && $regs[$startreg['positions']['A']] == 'PM') || (isset($startreg['positions']['a']) && isset($regs[$startreg['positions']['a']]) && $regs[$startreg['positions']['a']] == 'pm')) {
398 if ($regs[$startreg['positions']['h']] != 12) {
399 $regs[$startreg['positions']['H']] = $regs[$startreg['positions']['h']] + 12;
402 if ((isset($startreg['positions']['A']) && isset($regs[$startreg['positions']['A']])&& $regs[$startreg['positions']['A']] == 'AM') || (isset($startreg['positions']['a']) && isset($regs[$startreg['positions']['a']]) && $regs[$startreg['positions']['a']] == 'am')) {
403 if ($regs[$startreg['positions']['h']] == 12) {
404 $regs[$startreg['positions']['H']] = 0;
408 if (!empty($startreg['positions']['H']) && !empty($regs[$startreg['positions']['H']]) && !isset($startreg['positions']['h']) && strpos($endFormat, 'h') > -1) {
409 $startreg['positions']['h'] = sizeof($startreg['positions']) + 1;
410 $regs[$startreg['positions']['h']] = $regs[$startreg['positions']['H']];
411 if (!isset($startreg['positions']['A'])) {
412 $startreg['positions']['A'] = sizeof($startreg['positions']) + 1;
413 $regs[$startreg['positions']['A']] = 'AM';
415 if (!isset($startreg['positions']['a'])) {
416 $startreg['positions']['a'] = sizeof($startreg['positions']) + 1;
417 $regs[$startreg['positions']['a']] = 'am';
419 if ($regs[$startreg['positions']['H']] > 11) {
420 $regs[$startreg['positions']['h']] = $regs[$startreg['positions']['H']] - 12;
421 if ($regs[$startreg['positions']['h']] == 0) {
422 $regs[$startreg['positions']['h']] = 12;
424 $regs[$startreg['positions']['a']] = 'pm';
425 $regs[$startreg['positions']['A']] = 'PM';
427 if ($regs[$startreg['positions']['H']] == 0) {
428 $regs[$startreg['positions']['h']] = 12;
429 $regs[$startreg['positions']['a']] = 'am';
430 $regs[$startreg['positions']['A']] = 'AM';
433 if (!empty($startreg['positions']['h'])) {
434 if (!isset($regs[$startreg['positions']['h']])) {
435 $regs[$startreg['positions']['h']] = '12';
436 } else if (strlen($regs[$startreg['positions']['h']]) < 2)
437 $regs[$startreg['positions']['h']] = '0'.$regs[$startreg['positions']['h']];
439 if (!empty($startreg['positions']['H'])) {
440 // if no hour is set or it is equal to 0, set it explicitly to "00"
441 if (empty($regs[$startreg['positions']['H']])) {
442 $regs[$startreg['positions']['H']] = '00';
443 } else if (strlen($regs[$startreg['positions']['H']]) < 2)
444 $regs[$startreg['positions']['H']] = '0'.$regs[$startreg['positions']['H']];
446 if (!empty($startreg['positions']['d'])) {
447 if (!isset($regs[$startreg['positions']['d']])) {
448 $regs[$startreg['positions']['d']] = '01';
449 } else if (strlen($regs[$startreg['positions']['d']]) < 2)
450 $regs[$startreg['positions']['d']] = '0'.$regs[$startreg['positions']['d']];
452 if (!empty($startreg['positions']['i'])) {
453 // if no minute is set or it is equal to 0, set it explicitly to "00"
454 if (empty($regs[$startreg['positions']['i']])) {
455 $regs[$startreg['positions']['i']] = '00';
456 } else if (strlen($regs[$startreg['positions']['i']]) < 2)
457 $regs[$startreg['positions']['i']] = '0'.$regs[$startreg['positions']['i']];
459 $startreg['positions']['i'] = count($startreg['positions']) + 1;
460 $regs[$startreg['positions']['i']] = '00';
463 if (!empty($startreg['positions']['m'])) {
464 if (!isset($regs[$startreg['positions']['m']])) {
465 $regs[$startreg['positions']['m']] = '01';
466 } elseif(strlen($regs[$startreg['positions']['m']]) < 2)
467 $regs[$startreg['positions']['m']] = '0'.$regs[$startreg['positions']['m']];
469 if (!empty($startreg['positions']['Y'])) {
470 if (!isset($regs[$startreg['positions']['Y']])) {
471 $regs[$startreg['positions']['Y']] = '2000';
474 if (!empty($startreg['positions']['s'])) {
475 if (!isset($regs[$startreg['positions']['s']])) {
476 $regs[$startreg['positions']['s']] = '00';
477 } else if (strlen($regs[$startreg['positions']['s']]) < 2)
478 $regs[$startreg['positions']['s']] = '0'.$regs[$startreg['positions']['s']];
480 $startreg['positions']['s'] = sizeof($startreg['positions']) + 1;
481 $regs[$startreg['positions']['s']] = '00';
483 foreach($startreg['positions'] as $key=>$val) {
484 if (isset($regs[$val])) {
485 $newDate = str_replace($key, $regs[$val], $newDate);
492 * Converts DB time string to local time string
494 * TZ conversion depends on offset parameter
496 * @param string $date Time in DB format
497 * @param bool $meridiem
498 * @param bool $offset Perform TZ conversion?
499 * @return string Time in user-defined format
501 function to_display_time($date, $meridiem = true, $offset = true) {
507 $date = $this->handle_offset($date, $this->get_db_date_time_format(), true);
509 return $this->to_display($date, $this->dbTimeFormat, $this->get_time_format($meridiem));
513 * Converts DB date string to local date string
515 * TZ conversion depens on offset parameter
517 * @param string $date Date in DB format
518 * @param bool $use_offset Perform TZ conversion?
519 * @return string Date in user-defined format
521 function to_display_date($date, $use_offset = true) {
527 $date = $this->handle_offset($date, $this->get_db_date_time_format(), true);
529 return $this->to_display($date, $this->dbDayFormat, $this->get_date_format());
533 * Convert DB datetime to local datetime
535 * TZ conversion is controlled by $offset
537 * @param string $date Original date in DB format
538 * @param bool $meridiem
539 * @param bool $offset Perform TZ conversion?
540 * @param User $user User owning the conversion formats
541 * @return string Date in display format
543 function to_display_date_time($date, $meridiem = true, $offset = true, $user = null) {
550 if($this->allow_cache) {
553 'meridiem' => $meridiem,
555 'user' => is_null($user)?null:$user->id,
558 // todo use __METHOD__ once PHP5 minimum verison is required
559 $cache_key = md5('TimeDate::to_display_date_time_' . serialize($args));
560 $cached_value = sugar_cache_retrieve($cache_key);
561 if (!is_null($cached_value)) {
562 return $cached_value;
567 $date = $this->handle_offset($date, $this->get_db_date_time_format(), true, $user);
570 $return_value = $this->to_display($date, $this->get_db_date_time_format(), $this->get_date_time_format($meridiem, $user));
572 if($this->allow_cache) {
573 sugar_cache_put($cache_key, $return_value);
575 return $return_value;
579 * Convert date from format to format
581 * No TZ conversion is performed!
583 * @param string $date
584 * @param string $fromformat Source format
585 * @param string $toformat Target format
586 * @return string Converted date
588 function to_display($date, $fromformat, $toformat) {
593 return $this->swap_formats($date, $fromformat, $toformat);
597 * Convert date from local datetime to GMT-based DB datetime
599 * Includes TZ conversion.
601 * @param string $date
602 * @return string Datetime in DB format
604 public function to_db($date) {
609 if (strlen($date) <= 10) {
610 $date = $this->merge_date_time($date, $this->get_default_midnight());
613 $date = $this->swap_formats($date, $this->get_date_time_format(), $this->get_db_date_time_format());
614 return $this->handle_offset($date, $this->get_db_date_time_format(), false, $GLOBALS['current_user']);
619 * @todo This should return the raw text to be included within a <script> tag.
620 * Having this display it's own <script> keeps it from being able to be embedded
621 * in another Javascript file to allow for better caching
624 * Get Javascript variables setup for user date format validation
625 * @todo: move to separate utility class?
627 * @return string JS code
629 function get_javascript_validation() {
630 $cal_date_format = $this->get_cal_date_format();
631 $timereg = $this->get_regular_expression($this->get_time_format());
632 $datereg = $this->get_regular_expression($this->get_date_format());
634 foreach($datereg['positions'] as $type=>$pos) {
635 if (empty($date_pos)) {
636 $date_pos.= "'$type': $pos";
638 $date_pos.= ",'$type': $pos";
642 $date_pos = '{'.$date_pos.'}';
643 if (preg_match('/\)([^\d])\(/', $timereg['format'], $match)) {
644 $time_separator = $match[1];
646 $time_separator = ":";
648 $hour_offset = $this->get_hour_offset() * 60 * 60;
650 // Add in the number formatting styles here as well, we have been handling this with individual modules.
651 require_once('modules/Currencies/Currency.php');
652 list($num_grp_sep, $dec_sep) = get_number_seperators();
654 $the_script = "<script type=\"text/javascript\">\n"
655 ."\tvar time_reg_format = '".$timereg['format']."';\n"
656 ."\tvar date_reg_format = '".$datereg['format']."';\n"
657 ."\tvar date_reg_positions = $date_pos;\n"
658 ."\tvar time_separator = '$time_separator';\n"
659 ."\tvar cal_date_format = '$cal_date_format';\n"
660 ."\tvar time_offset = $hour_offset;\n"
661 ."\tvar num_grp_sep = '$num_grp_sep';\n"
662 ."\tvar dec_sep = '$dec_sep';\n"
670 * Convert local datetime to DB date
672 * TZ conversion depends on $use_offset. If false, only format conversion is performed.
674 * @param string $date Local date
675 * @param bool $use_offset Should time and TZ be taken into account?
676 * @return string Date in DB format
678 public function to_db_date($date, $use_offset = true) {
683 if (!$use_offset && preg_match('/^[0-9]{4}-[0-9]{2}-[0-9]{2}$/',$date) ) {
684 // Already in system format
688 $date = $this->to_db($date);
689 $date = $this->swap_formats($date, $this->dbDayFormat, $this->dbDayFormat);
691 $date = $this->swap_formats($date, $this->get_date_format(), $this->dbDayFormat);
698 * Convert local datetime to DB time
700 * TZ conversion depends on $use_offset. If false, only format conversion is performed.
702 * @param string $date Local date
703 * @param bool $use_offset Should time and TZ be taken into account?
704 * @return string Time in DB format
706 public function to_db_time($date, $use_offset = true) {
712 $date =$this->to_db($date, $use_offset);
713 $date = $this->swap_formats($date, $this->get_db_date_time_format(), $this->dbTimeFormat);
715 $date = $this->swap_formats($date, $this->get_time_format(), $this->dbTimeFormat);
723 * Takes a Date & Time value in local format and converts them to DB format
726 * @param string $date
727 * @param string $time
728 * @return array Date & time in DB format
730 public function to_db_date_time($date, $time) {
731 global $current_user;
732 if(is_object($current_user)) {
733 $timeFormat = $current_user->getUserDateTimePreferences();
735 $timeFormat['date'] = $this->dbDayFormat;
736 $timeFormat['time'] = $this->dbTimeFormat;
740 $retDateTime = array();
742 // concat: ('.' breaks strtotime())
743 $time = str_replace('.',':',$time);
744 $dt = $date.' '.$time;
745 if ( preg_match('/^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}$/',$dt) ) {
746 // Already in system time format
747 return array($date, $time);
749 $newDate = $this->swap_formats($dt, $timeFormat['date'].' '.$timeFormat['time'] , $this->dbDateTimeFormat);
750 return $this->split_date_time($newDate);
754 * @deprecated for public use
755 * Get DST offset between user & event
756 * @param $user_in_dst
757 * @param $event_in_dst
759 function getUserEventOffset($user_in_dst, $event_in_dst){
760 if($user_in_dst && !$event_in_dst ){
763 if(!$user_in_dst && $event_in_dst ){
769 /**************************************************************
770 U S E Time GMT Delta Server Client U/E Delta Server GMT
771 USER IN LA and server in NY
782 User in LA and server in gmt there are no DST for server
789 ***************************************************************/
792 * handles offset values for Timezones and DST
793 * @param $date string date/time formatted in user's selected format
794 * @param $format string destination format value as passed to PHP's date() funtion
796 * @param $user object user object from which Timezone and DST
797 * @param $usetimezone string timezone name as it appears in timezones.php values will be derived
798 * @return string date formatted and adjusted for TZ and DST
800 function handle_offset($date, $format, $to = true, $user = null, $usetimezone = null) {
801 global $sugar_config;
804 // This has been commented out because it is going through the wrong code path
805 // Email module was broken and thats why its commented
806 //if($this->use_old_gmt()){
807 //return $this->handle_offset_depricated($date, $format, $to);
812 if($this->allow_cache) {
817 'user' => is_null($user)?null:$user->id,
818 'usetimezone' => $usetimezone,
820 $cache_key = md5('TimeDate::handle_offset_' . serialize($args));
821 $cached_result = sugar_cache_retrieve($cache_key);
822 if (!is_null($cached_result)) {
823 return $cached_result;
826 if (strtotime($date) == -1) {
829 $deltaServerGMT = date('Z');
831 if ( !empty($usetimezone) )
832 $timezone = $GLOBALS['timezones'][$usetimezone];
834 $timezone = $this->getUserTimeZone($user);
835 $deltaServerUser = $this->get_hour_offset($to, $timezone);
836 $event_in_ds = $this->inDST($date,$timezone );
837 $user_in_ds = $this->inDST(date('Y-m-d H:i:s'),$timezone );
838 $server_in_ds = date('I');
839 $ue = $this->getUserEventOffset($user_in_ds, $event_in_ds);
844 $result = date($format, strtotime($date) + $deltaServerUser * 3600 + ($ue + $deltaServerGMT) * $zone);
845 if($this->allow_cache) {
846 sugar_cache_put($cache_key, $result);
852 * @deprecated for public use
854 function use_old_gmt()
856 if(isset($_SESSION['GMTO'])){
857 return $_SESSION['GMTO'];
859 $db = DBManagerFactory::getInstance();
860 $fix_name = 'DST Fix';
861 $result =$db->query("Select * from versions where name='$fix_name'");
862 $valid = $db->fetchByAssoc($result);
864 $_SESSION['GMTO'] = false;
866 $_SESSION['GMTO'] = true;
868 return $_SESSION['GMTO'];
872 * @deprecated for public use
873 *This function is depricated don't use it. It is only for backwards compatibility until the admin runs the upgrade script
875 * @param unknown_type $date
876 * @param unknown_type $format
877 * @param unknown_type $to
880 private function handle_offset_depricated($date, $format, $to = true)
886 if (strtotime($date) == -1) {
893 return date($format, strtotime($date) + $this->get_hour_offset($to) * 60 * 60 + $zone);
897 * this method will take an input $date variable (expecting Y-m-d format)
898 * and get the GMT equivalent - with an hour-level granularity :
899 * return the max value of a given locale's
900 * date+time in GMT metrics (i.e., if in PDT, "2005-01-01 23:59:59" would be
901 * "2005-01-02 06:59:59" in GMT metrics)
903 function handleOffsetMax($date, $format = '', $to = true)
905 global $current_user;
906 $gmtDateTime = array($date); // for errors
907 /* check for bad date formatting */
914 if (strtotime($date) == -1) {
918 /* cn: passed $date var will be a "MAX" value, which we need to return
919 as a GMT date/time pair to provide for hour-level granularity */
920 /* this ridiculousness b/c PHP returns current time when passing "today"
921 or "tomorrow" as strtotime() args */
922 $dateNoTime = date('Y-m-d', strtotime($date));
924 /* handle timezone and daylight savings */
925 $dateWithTimeMin = $dateNoTime.' 00:00:00';
926 $dateWithTimeMax = $dateNoTime.' 23:59:59';
928 $offsetDateMin = $this->handle_offset($dateWithTimeMin, $this->dbDateTimeFormat, false);
929 $offsetDateMax = $this->handle_offset($dateWithTimeMax, $this->dbDateTimeFormat, false);
932 $exOffsetDateMax = $this->split_date_time($offsetDateMax);
933 $gmtDateTime['date'] = $exOffsetDateMax[0];
934 $gmtDateTime['time'] = $exOffsetDateMax[1];
935 $gmtDateTime['min'] = $offsetDateMin;
936 $gmtDateTime['max'] = $offsetDateMax;
943 * Get current GMT datetime in DB format
946 function get_gmt_db_datetime() {
947 return gmdate($this->get_db_date_time_format());
951 * Get current GMT date in DB format
954 function get_gmt_db_date() {
955 return gmdate($this->get_db_date_format());
959 * @deprecated for public use
960 * Convert time in strtotime format into Y-m-d H:i:s format
962 function convert_to_gmt_datetime($olddatetime) {
963 if (!empty($olddatetime)) {
964 return date('Y-m-d H:i:s', strtotime($olddatetime) - date('Z'));
969 * makes one datetime string from date string and time string
971 * @param string $date
972 * @param string $time
973 * @return string Datetime string
975 function merge_date_time($date, $time) {
976 return $date.' '.$time;
980 * Merge time without am/pm with am/pm string
982 * @param string $date
983 * @param string $format User time format
987 function merge_time_meridiem($date, $format, $mer) {
992 $fakeMerFormat = str_replace(array('a', 'A'), array('!@!', '!@!'), $format);
993 $noMerFormat = str_replace(array('a', 'A'), array('', ''), $format);
994 $newDate = $this->swap_formats($date, $noMerFormat, $fakeMerFormat);
995 return str_replace('!@!', $mer, $newDate);
999 * Returns the time portion of a datetime string
1001 * @param string $datetime
1004 public function getTimePart($datetime)
1006 return trim(array_pop($this->split_date_time($datetime)));
1010 * Returns the date portion of a datetime string
1012 * @param string $datetime
1015 public function getDatePart($datetime)
1017 return trim(array_shift($this->split_date_time($datetime)));
1021 * @deprecated for public use
1023 * This method renders a <select> HTML form element based on the
1024 * user's time format preferences, with give date's value highlighted.
1026 * If user's prefs have no AM/PM string, returns empty string.
1028 * @todo: There is hardcoded HTML in here that does not allow for localization
1029 * of the AM/PM am/pm Strings in this drop down menu. Also, perhaps
1030 * change to the substr_count function calls to strpos
1031 * @todo: move to separate utility class?
1033 * @param string $prefix Prefix for SELECT
1034 * @param string $date Date in display format
1035 * @param string $attrs Additional attributes for SELECT
1036 * @return string SELECT HTML
1038 function AMPMMenu($prefix, $date, $attrs = '') {
1040 if (substr_count($this->get_time_format(), 'a') == 0 && substr_count($this->get_time_format(), 'A') == 0) {
1043 $menu = "<select name='".$prefix."meridiem' ".$attrs.">";
1045 if (strpos($this->get_time_format(), 'a') > -1) {
1047 if (substr_count($date, 'am') > 0)
1048 $menu.= "<option value='am' selected>am";
1050 $menu.= "<option value='am'>am";
1051 if (substr_count($date, 'pm') > 0)
1052 $menu.= "<option value='pm' selected>pm";
1054 $menu.= "<option value='pm'>pm";
1058 if (substr_count($date, 'AM') > 0)
1059 $menu.= "<option value='AM' selected>AM";
1061 $menu.= "<option value='AM'>AM";
1062 if (substr_count($date, 'PM') > 0) {
1063 $menu.= "<option value='PM' selected>PM";
1065 $menu.= "<option value='PM'>PM";
1069 return $menu.'</select>';
1073 * @deprecated for public use
1074 * Get timezone offset in hours between server and timezone
1076 * @param bool $to To this timezone or from this timezone?
1080 function get_hour_offset($to = true, $timezone = null) {
1081 $timeDelta = $this->adjustmentForUserTimeZone($timezone) /60.0;
1083 return -1.0 * $timeDelta;
1085 return 1.0 * $timeDelta;
1089 * Get user-defined time format
1091 * @param bool $meridiem Should we allow AM/PM?
1095 function get_time_format($meridiem = true, $user = null) {
1096 global $current_user;
1097 global $sugar_config;
1099 if(empty($user)) $user = $current_user;
1101 if ($user instanceof User && $user->getPreference('timef')) {
1102 $timeFormat = $user->getPreference('timef');
1104 $timeFormat = $sugar_config['default_time_format'];
1107 $timeFormat = str_replace(array('a', 'A'), array('', ''), $timeFormat);
1113 * Get user-defined date format
1118 public function get_date_format($user = null) {
1119 global $current_user;
1120 global $sugar_config;
1122 if(empty($user)) $user = $current_user;
1124 if ($user instanceof User && $user->getPreference('datef')) {
1125 return $user->getPreference('datef');
1127 if(!empty($sugar_config['default_date_format'])){
1128 return $sugar_config['default_date_format'];
1135 * Get user-defined datetime format
1137 * @param bool $meridiem Should we allow AM/PM?
1141 public function get_date_time_format($meridiem = true, $user = null) {
1142 return $this->merge_date_time($this->get_date_format($user), $this->get_time_format($meridiem, $user));
1145 public function get_db_date_time_format() {
1146 return $this->merge_date_time($this->dbDayFormat, $this->dbTimeFormat);
1149 public function get_db_date_format()
1151 return $this->dbDayFormat;
1154 public function get_db_time_format()
1156 return $this->dbTimeFormat;
1160 * Get user date format it strftime terms
1162 function get_cal_date_format() {
1164 array('Y', 'm', 'd'),
1165 array('%Y', '%m', '%d'),
1166 $this->get_date_format());
1170 * Get user time format it strftime terms
1172 function get_cal_time_format() {
1174 array('a', 'A', 'h', 'H', 'i', 's'),
1175 array('%P', '%p', '%I', '%H', '%M', '%S'),
1176 $this->get_time_format());
1180 * Get user date & time format it strftime terms
1182 function get_cal_date_time_format() {
1183 return $this->merge_date_time($this->get_cal_date_format(), $this->get_cal_time_format());
1187 * Return current date format for user display
1189 * Displays format as an example for the user (i.e. something like dd/mm/yyyy)
1191 function get_user_date_format() {
1193 array('Y', 'm', 'd'),
1194 array('yyyy', 'mm', 'dd'),
1195 $this->get_date_format());
1199 * Return current time format for user display (e.g. as example under select box)
1200 * FIXME: should we be using current format as get_user_date_format() or config?
1202 function get_user_time_format() {
1203 global $sugar_config;
1204 $time_pref = $this->get_time_format();
1206 if(!empty($time_pref) && !empty($sugar_config['time_formats'][$time_pref])) {
1207 return $sugar_config['time_formats'][$time_pref];
1210 return '23:00'; //default
1212 // Commented out by Collin (doesn't seem to work properly)
1213 return $this->to_display_time('23:00:00', true, false);
1218 * @deprecated for public use
1219 * @todo: move to separate utility class?
1221 function get_microtime_string() {
1222 return sugar_microtime();
1226 * Get midnight (start of the day) in local time format
1228 * @param bool $refresh Should cached value be discarded?
1229 * @return Time string
1231 function get_default_midnight($refresh = false)
1233 if (is_null($this->default_midnight) || !$this->allow_cache || $refresh) {
1234 $time_mapping = array(
1242 $this->default_midnight = str_replace(
1243 array_keys($time_mapping),
1245 $this->get_time_format()
1248 return $this->default_midnight;
1252 * Splits datetime string into date & time parts
1253 * @param string $date Datetime string
1254 * @return array date,time
1256 protected function split_date_time($date)
1258 return explode(' ', $date);
1262 * Returns start and end of a certain local date in GMT
1263 * Example: for May 19 in PDT start would be 2010-05-19 07:00:00, end would be 2010-05-20 06:59:59
1264 * @param string $date Date in user format
1265 * @return array Start & end date in start, end
1267 public function getDayStartEndGMT($date)
1269 $datetime = $this->split_date_time($date);
1271 $dates = $this->handleOffsetMax($this->to_db_date($datetime[0], false));
1273 $result['start'] = $dates['min'];
1274 $result['end'] = $dates['max'];