/** * parses a date string into UNIX timestamp * * if "strict dates" is set, this function uses the DateTime or IntlDateFormatter * class to parse the string according to a specific format. If it is not, we * use the conventional strtotime() function, with the enhancement that if the * non-American style format is used with slashes "d/m/Y" the string is prepared * so strtotime can parse it correctly * * @param string $string the string to parse; if not given, defaults to now * @param object $column_atts the column object; used to identify the field for * user feedback * @param bool $zero_time if set, zero the time portion of the date so it * won't interfere with date comparisons * @return int|bool UNIX timestamp or false if parse fails */ public static function parse_date($string = false, $column = '', $zero_time = false) { if (false === $string) { return false; } $string = Participants_Db::set_filter('parse_date', $string, $column); // is it already a timestamp? if (self::is_valid_timestamp($string)) { //if (WP_DEBUG and is_object($column)) error_log(__METHOD__.' tried to parse timestamp from '. $column->name); return $string; } $date = false; // if it is a default zero timestamp, treat it as "no date" if ($string === '0000-00-00 00:00:00') { return false; } /* * we have two options to parse a date string into a timestamp: the * IntlDateFormatter class or the DateTime class. The IntlDateFormatter * class can parse localized text dates, but it seems commonly unavailable, * at least on English-speaking servers. The DateTime class is widely * available, but can't parse non-English text dates. It can parse numeric * date representations, so if the intl module is not available, we try to * use DateTime. If that is not available, we use strtotime with the added trick * of swapping the date/month if they are slashes so slashed European notation * can be correctly parsed */ self::$date_mode = 'none'; $errors = false; $the_Date = false; // test for MySQL-format timestamp $is_MySQL_timestamp = preg_match('#^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}$#', $string) === 1 ? true : false; //error_log(__METHOD__.' object? '.(is_object($column)?'yes':'no').' strict dates? '.(self::plugin_setting_is_true('strict_dates', false)?'yes':'no').' timestamp? '.($is_MySQL_timestamp?'yes':'no')); if (self::plugin_setting_is_true('strict_dates', false) and is_object($column) and !$is_MySQL_timestamp) { //error_log(__METHOD__.' intl? '.(class_exists('IntlDateFormatter')?'yes':'no').' datetime? '.(class_exists('DateTime')?'yes':'no')); if (class_exists('IntlDateFormatter')) { self::$date_mode = 'Intl'; $DateFormat = new IntlDateFormatter(get_locale(), IntlDateFormatter::LONG, IntlDateFormatter::NONE, NULL, NULL, Participants_Db::get_ICU_date_format(self::$plugin_options['input_date_format'])); $DateFormat->setLenient(false); // we want it strict $timestamp = $DateFormat->parse($string); if ($DateFormat->getErrorCode() !== 0) { $errors = array('code' => $DateFormat->getErrorCode(), 'error' => $DateFormat->getErrorMessage()); } if (!$errors) { $the_Date = new DateTime(); $the_Date->setTimestamp($timestamp); } elseif (WP_DEBUG) { error_log(__METHOD__ . ' IntlDateFormatter error: format string: ' . Participants_Db::get_ICU_date_format(self::$plugin_options['input_date_format']) . ' timestamp: ' . $timestamp . ' formatter error: ' . $DateFormat->getErrorMessage()); } } if (!$the_Date && class_exists('DateTime')) { self::$date_mode = 'DateTime'; $the_Date = DateTime::createFromFormat(self::$plugin_options['input_date_format'], $string); } if (is_object($the_Date)) { $errors = $the_Date->getLastErrors(); if ($errors['warning_count'] === 0 && $errors['error_count'] === 0) { $errors = false; } } if (is_array($errors) && !empty($string)) { $the_Date = false; if (is_object(self::$validation_errors) and is_object($column)) { self::$validation_errors->add_error($column->name, sprintf(__('The date for "%s" was invalid. Please input the date with the exact format shown', 'participants-database'), $column->title)); } if (WP_DEBUG) { error_log(__METHOD__ . ' DateTime parse error: ' . implode(', ', $errors)); } } /* * if we have a valid date, convert to timestamp */ if ($the_Date) { /* * zero the time so date equality comparisons can be made */ if ($zero_time) { $the_Date->setTime(0, 0); } $date = $the_Date->format('U'); } } /* * if we haven't got a timestamp, parse the date the regular way */ if ($date === false or !self::is_valid_timestamp($date)) { $date = false; // no valid date yet if (is_object($column) && $column->form_element == 'timestamp') { if ($zero_time) { /* * we need to zero the time, we first try to do it using the DateTime class */ $the_Date = new DateTime($string); if (is_object($the_Date)) { $the_Date->setTime(0, 0); $string = $the_Date->format(self::$date_format); } else { /* * remove the time portion of the timestamp */ $string = preg_replace('# [0-9]{2}:[0-9]{2}:[0-9]{2}$#', '', $string); $string .= ' 00:00 -0'; } } } /* * @version 1.6 * Most of the time, the default PHP timezone is the current setting, but * experience has shown it's necessary to reset it for the conversion to make * sure. We also must assume that the database server and PHP server are on * the same TZ. */ date_default_timezone_set(self::get_timezone()); setlocale(LC_ALL, get_locale()); /* * @version 1.6 * added strptime method for locaized dates * * this only works for known formats...so timestamps and when "strict dates" is enabled */ if (function_exists('strptime') && (self::plugin_setting_is_true('strict_dates', false) || $is_MySQL_timestamp)) { self::$date_mode = 'strptime'; if ($is_MySQL_timestamp) { $format = '%Y-%m-%d'; } else { $format_setting = Participants_Db::plugin_setting_is_set('input_date_format') ? Participants_Db::plugin_setting('input_date_format') : get_bloginfo('date_format'); $format = Participants_Db::translate_date_format($format_setting, 'strftime'); } $date_array = strptime($string, $format); $date = mktime($date_array['tm_hour'], $date_array['tm_min'], $date_array['tm_sec'], $date_array['tm_mon'] + 1, $date_array['tm_mday'], $date_array['tm_year'] + 1900); } if ($date === false) { self::$date_mode = 'strtotime'; $date = strtotime(self::date_order_fix($string)); } } return $date; }