language =& $this->Application->recallObject('lang.current'); } /** * Sets mixed format (date + time) for field if not set directly * * @param Array $field_options options of field * @param Array $format separate formats for date & time * @param string $type destination key in field_options to store mixed format */ function SetMixedFormat(&$field_options, &$format, $type) { if (!isset($field_options[$type])) { // default value is date+sepatator+time $field_options[$type] = '_regional_DateTimeFormat'; } if ($field_options[$type] == '_regional_DateTimeFormat') { $field_options[$type] = $format['date'].$field_options['date_time_separator'].$format['time']; } else if(preg_match('/_regional_(.*)/', $field_options[$type], $regs)) { $field_options[$type] = $this->language->GetDBField($regs[1]); } $format['mixed'] = $field_options[$type]; } /** * Returns separate formats for date,time,combined for input & display formats * * @param Array $field_options options of field * @param string $type type of requested information = {mixed,date,time} * @return Array display & input formats */ function GetSeparateFormats(&$field_options, $type) { if ($type == 'mixed') { if (!isset($field_options['date_time_separator'])) $field_options['date_time_separator'] = ' '; $display_format = Array (); $input_format = Array (); list ($display_format['date'], $input_format['date']) = $this->GetSeparateFormats($field_options, 'date'); list ($display_format['time'], $input_format['time']) = $this->GetSeparateFormats($field_options, 'time'); $this->SetMixedFormat($field_options, $display_format, 'format'); $this->SetMixedFormat($field_options, $input_format, 'input_format'); return Array ($display_format, $input_format); } else { // 1. set display format if (isset($field_options[$type.'_format'])) { $format = $field_options[$type.'_format']; } else { $format = $this->language->GetDBField(ucfirst($type).'Format'); } // 2. set input format if (isset($field_options['input_'.$type.'_format'])) { $input_format = $field_options['input_'.$type.'_format']; } else { $input_format = $this->language->GetDBField('Input'.ucfirst($type).'Format'); } return Array ($format, $input_format); } } function PrepareOptions($field_name, &$field_options, &$object) { list ($display_format, $input_format) = $this->GetSeparateFormats($field_options, 'mixed'); $field_options['sub_fields'] = Array('date' => $field_name.'_date', 'time' => $field_name.'_time'); if (!isset($field_options['use_timezone'])) { // apply timezone from server $field_options['use_timezone'] = true; } $add_fields = Array(); // 1. add DATE virtual field $opts = Array('master_field' => $field_name, 'formatter'=>'kDateFormatter', 'format' => $display_format['date'], 'input_format' => $input_format['date']); if ( isset($field_options['default']) ) $opts['default'] = $field_options['default']; if ( isset($field_options['required']) ) $opts['required'] = $field_options['required']; if ( isset($field_options['use_timezone']) ) $opts['use_timezone'] = $field_options['use_timezone']; $add_fields[$field_name.'_date'] = $opts; // 2. add TIME virtual field $opts['format'] = $display_format['time']; $opts['input_format'] = $input_format['time']; $add_fields[$field_name.'_time'] = $opts; $filter_type = getArrayValue($field_options, 'filter_type'); if($filter_type == 'range') { $opts['format'] = $field_options['format']; $add_fields[$field_name.'_rangefrom'] = $opts; $add_fields[$field_name.'_rangeto'] = $opts; } if ( !isset($object->VirtualFields[$field_name]) ) { // adding caluclated field to format date directly in the query if ( !isset($object->CalculatedFields) || !is_array($object->CalculatedFields) ) { $object->CalculatedFields = Array(); } $object->CalculatedFields[$field_name.'_formatted'] = 'FROM_UNIXTIME('.'`%1$s`.'.$field_name.' + '.$this->Application->TimeZoneAdjustment().', \''.$this->SQLFormat($field_options['format']).'\')'; $opts['format'] = $field_options['format']; $opts['required'] = 0; unset($opts['master_field']); $add_fields[$field_name.'_formatted'] = $opts; } $add_fields = array_merge_recursive2($add_fields, $object->VirtualFields); $object->setVirtualFields($add_fields); } function UpdateSubFields($field, $value, &$options, &$object) { if ( $sub_fields = getArrayValue($options, 'sub_fields') ) { if( isset($value) && $value ) { $object->SetDBField( $sub_fields['date'], $value ); $object->SetDBField( $sub_fields['time'], $value ); } } } function UpdateMasterFields($field, $value, &$options, &$object) { // when in master field - set own value from sub_fields if ( $sub_fields = getArrayValue($options, 'sub_fields') ) { // if date is not empty, but time is empty - set time to 0, otherwise master field fomratter will complain // when we have only date field on form, we need time hidden field always empty, don't ask me why! if ( $object->GetDBField($sub_fields['date']) != '' && $object->GetDBField($sub_fields['time']) == '' ) { $empty_time = getArrayValue($options,'empty_time'); if($empty_time === false) $empty_time = adodb_mktime(0,0,0); $object->SetDBField($sub_fields['time'], $empty_time); } $input_format['date'] = $object->Fields[ $sub_fields['date'] ]['input_format']; $input_format['time'] = $object->Fields[ $sub_fields['time'] ]['input_format']; $object->SetField($field, $object->GetField($sub_fields['date'], $input_format['date']).$options['date_time_separator'].$object->GetField($sub_fields['time'], $input_format['time'])); } // when in one of sub_fields - call update for master_field to update its value from sub_fields [are you following ? :) ] elseif ($master_field = getArrayValue($options, 'master_field') ) { $opt = $object->GetFieldOptions($master_field); $this->UpdateMasterFields($master_field, null, $opt, $object); } } //function Format($value, $options, &$errors) function Format($value, $field_name, &$object, $format=null) { if ( is_null($value) ) return ''; if ( !is_numeric($value) ) return $value; // for leaving badly formatted date on the form settype($value, 'int'); if ( !is_int($value) ) return $value; $options = $object->GetFieldOptions($field_name); if ( isset($format) ) $options['format'] = $format; if (!$options['use_timezone']) { return adodb_gmdate($options['format'], $value); } return adodb_date($options['format'], $value + $this->Application->TimeZoneAdjustment()); } function HumanFormat($format) { $patterns = Array('/m/', '/n/', '/d/', '/j/', '/y/', '/Y/', '/h|H/', '/g|G/', '/i/', '/s/', '/a|A/'); $replace = Array( 'mm', 'm', 'dd', 'd', 'yy', 'yyyy', 'hh', 'h', 'mm', 'ss', 'AM'); $res = preg_replace($patterns, $replace, $format); return $res; } function SQLFormat($format) { $mapping = Array( '/%/' => '%%', '/(? '%p', // Lowercase Ante meridiem and Post meridiem => MySQL provides only uppercase '/(? '%p', // Uppercase Ante meridiem and Post meridiem '/(? '%d', // Day of the month, 2 digits with leading zeros '/(? '%a', // A textual representation of a day, three letters '/(? '%M', // A full textual representation of a month, such as January or March '/(? '%l', // 12-hour format of an hour without leading zeros '/(? '%k', // 24-hour format of an hour without leading zeros '/(? '%h', // 12-hour format of an hour with leading zeros '/(? '%H', // 24-hour format of an hour with leading zeros '/(? '%i', // Minutes with leading zeros '/(? 'N/A', // Whether or not the date is in daylights savings time '/(? 'N/A', // English ordinal suffix for the day of the month, 2 characters, see below '/jS/' => '%D', // MySQL can't return separate suffix, but could return date with suffix '/(? '%e', // Day of the month without leading zeros '/(? '%W', // A full textual representation of the day of the week '/(? 'N/A', // Whether it's a leap year '/(? '%m', // Numeric representation of a month, with leading zeros '/(? '%b', // A short textual representation of a month, three letters '/(? '%c', // Numeric representation of a month, without leading zeros '/(? 'N/A', // Difference to Greenwich time (GMT) in hours '/(? 'N/A', // RFC 2822 formatted date '/(? '%s', // Seconds, with leading zeros // S and jS moved before j - see above '/(? 'N/A', // Number of days in the given month '/(? 'N/A', // Timezone setting of this machine '/(? 'N/A', // Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) '/(? '%w', // Numeric representation of the day of the week '/(? '%v', // ISO-8601 week number of year, weeks starting on Monday (added in PHP 4.1.0) '/(? '%Y', // A full numeric representation of a year, 4 digits '/(? '%y', // A two digit representation of a year '/(? 'N/A', // The day of the year (starting from 0) => MySQL starts from 1 '/(? 'N/A', // Timezone offset in seconds. The offset for timezones west of UTC is always negative, and for those east of UTC is always positive. ); $patterns = array_keys($mapping); $replacements = array_values($mapping); $res = preg_replace($patterns, $replacements, $format); return $res; } /** * Converts formatted date+time to timestamp and validates format * * @param mixed $value * @param string $field_name * @param kDBItem $object * @return string */ function Parse($value, $field_name, &$object) { $options = $object->GetFieldOptions($field_name); $dt_separator = getArrayValue($options,'date_time_separator'); if($dt_separator) $value = trim($value, $dt_separator); if($value == '') return NULL; //return strtotime($value); $format = $options['input_format']; if ($dt_separator) $format = trim($format, $dt_separator); $error_field = isset($this->Fields[$field_name]['error_field']) ? $this->Fields[$field_name]['error_field'] : $field_name; $object->FieldErrors[$error_field]['params'] = Array( $this->HumanFormat($format), adodb_date($format) ); $object->FieldErrors[$error_field]['value'] = $value; $hour = 0; $minute = 0; $second = 0; $month = 1; $day = 1; $year = 1970; $patterns['n'] = '([0-9]{1,2})'; $patterns['m'] = '([0-9]{1,2})'; $patterns['d'] = '([0-9]{1,2})'; $patterns['j'] = '([0-9]{1,2})'; $patterns['Y'] = '([0-9]{4})'; $patterns['y'] = '([0-9]{2})'; $patterns['G'] = '([0-9]{1,2})'; $patterns['g'] = '([0-9]{1,2})'; $patterns['H'] = '([0-9]{2})'; $patterns['h'] = '([0-9]{2})'; $patterns['i'] = '([0-9]{2})'; $patterns['s'] = '([0-9]{2})'; $patterns['a'] = '(am|pm)'; $patterns['A'] = '(AM|PM)'; $holders_mask = eregi_replace('[a-zA-Z]{1}', '([a-zA-Z]{1})', $format); if (!ereg($holders_mask, $format, $holders)) { $object->SetError($field_name, 'bad_date_format'); return $value; } $values_mask = '/^'.str_replace('/','\/',$format).'$/'; foreach ($patterns as $key => $val) { $values_mask = ereg_replace($key, $val, $values_mask); } // echo " values_mask : $values_mask
"; if (!preg_match($values_mask, $value, $values)) { $object->SetError($field_name, 'bad_date_format'); return $value; } for ($i = 1; $i < count($holders); $i++) { switch ($holders[$i]) { case 'n': case 'm': $month = $values[$i]; $month = ereg_replace("^0{1}", '', $month); break; case 'd': $day = $values[$i]; $day = ereg_replace("^0{1}", '', $day); break; case 'Y': $year = $values[$i]; break; case 'y': $year = $values[$i] >= 70 ? 1900 + $values[$i] : 2000 + $values[$i]; break; case 'H': case 'h': case 'G': case 'g': $hour = $values[$i]; $hour = ereg_replace("^0{1}", '', $hour); break; case 'i': $minute = $values[$i]; $minute = ereg_replace("^0{1}", '', $minute); break; case 's': $second = $values[$i]; $second = ereg_replace("^0{1}", '', $second); break; case 'a': case 'A': if ($hour <= 12) { // if AM/PM used with 24-hour - could happen :) if ($values[$i] == 'pm' || $values[$i] == 'PM') { $hour += 12; if ($hour == 24) $hour = 12; } elseif ($values[$i] == 'am' || $values[$i] == 'AM') { if ($hour == 12) $hour = 0; } } break; } } //echo "day: $day, month: $month, year: $year, hour: $hour, minute: $minute
"; /*if (!($year >= 1970 && $year <= 2037)) { $object->SetError($field_name, 'bad_date_format'); return $value; }*/ if (!($month >= 1 && $month <= 12)) { $object->SetError($field_name, 'bad_date_format'); return $value; } $months_days = Array ( 1 => 31,2 => 28, 3 => 31, 4 => 30,5 => 31,6 => 30, 7 => 31, 8 => 31,9 => 30,10 => 31,11 => 30,12 => 31); if ($year % 4 == 0) $months_days[2] = 29; if (!($day >=1 && $day <= $months_days[$month])) { $object->SetError($field_name, 'bad_date_format'); return $value; } if (!($hour >=0 && $hour <= 23)) { $object->SetError($field_name, 'bad_date_format'); return $value; } if (!($minute >=0 && $minute <= 59)) { $object->SetError($field_name, 'bad_date_format'); return $value; } if (!($second >=0 && $second <= 59)) { $object->SetError($field_name, 'bad_date_format'); return $value; } if (!$options['use_timezone']) { return adodb_gmmktime($hour, $minute, $second, $month, $day, $year); } return adodb_mktime($hour, $minute, $second, $month, $day, $year) - $this->Application->TimeZoneAdjustment(); } function GetSample($field, &$options, &$object) { return $this->Format( adodb_mktime(), $field, $object, $options['input_format']); } }