示例#1
0
 /**
  * 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;
 }
 /**
  * Formats a date/time value.
  * If the value is null also null will be returned.
  * @param mixed $value Date/time value to be formatted using {@link http://php.net/manual/intldateformatter.format.php}.
  * @param string $locale Locale to be used with {@link http://php.net/manual/class.intldateformatter.php}.
  * @param integer $datetype Date format. See {@link http://php.net/manual/class.intldateformatter.php#intl.intldateformatter-constants} for valid values.
  * @param integer $timetype Time format. See {@link http://php.net/manual/class.intldateformatter.php#intl.intldateformatter-constants} for valid values.
  * @return string Formatted date/time.
  * @throws \InvalidArgumentException
  */
 protected function getFormattedDateTime($value, $locale, $datetype, $timetype)
 {
     if ($value === null) {
         return null;
     }
     $valueToUse = $value;
     // IntlDateFormatter#format() doesn't support \DateTime objects prior to PHP 5.3.4 (http://php.net/manual/intldateformatter.format.php)
     if ($valueToUse instanceof \DateTime) {
         // \DateTime::getTimestamp() would return false for year > 2038 on 32-bit systems (https://bugs.php.net/bug.php?id=50590)
         $valueToUse = floatval($valueToUse->format('U'));
     } elseif (is_string($valueToUse)) {
         $valueToUse = floatval($valueToUse);
     }
     $localeToUse = !empty($locale) ? $locale : $this->getLocale();
     $formatter = new \IntlDateFormatter($localeToUse, $datetype, $timetype, date_default_timezone_get());
     $result = $formatter->format($valueToUse);
     if ($result === false) {
         throw new \InvalidArgumentException(sprintf('The value "%s" of type %s cannot be formatted. Error: "%s".', $value, gettype($value), $formatter->getErrorMessage()));
     }
     return $result;
 }