You are here

protected function DateObject::parse in Date 7.3

Same name and namespace in other branches
  1. 7 date_api/date_api.module \DateObject::parse()
  2. 7.2 date_api/date_api.module \DateObject::parse()

Converts a date string into a date object.

Parameters

string $date: The date string to parse.

object $tz: A timezone object.

string $format: The date format string.

Return value

object Returns the date object.

1 call to DateObject::parse()
DateObject::__construct in date_api/date_api.module
Constructs a date object.

File

date_api/date_api.module, line 613
This module will make the date API available to other modules.

Class

DateObject
Extend PHP DateTime class.

Code

protected function parse($date, $tz, $format) {
  $array = date_format_patterns();
  foreach ($array as $key => $value) {

    // The letter with no preceding '\'.
    $patterns[] = "`(^|[^\\\\\\\\])" . $key . "`";

    // A single character.
    $repl1[] = '${1}(.)';

    // The.
    $repl2[] = '${1}(' . $value . ')';
  }
  $patterns[] = "`\\\\\\\\([" . implode(array_keys($array)) . "])`";
  $repl1[] = '${1}';
  $repl2[] = '${1}';
  $format_regexp = preg_quote($format);

  // Extract letters.
  $regex1 = preg_replace($patterns, $repl1, $format_regexp, 1);
  $regex1 = str_replace('A', '(.)', $regex1);
  $regex1 = str_replace('a', '(.)', $regex1);
  preg_match('`^' . $regex1 . '$`', stripslashes($format), $letters);
  array_shift($letters);
  $ampm_upper = date_ampm_options(FALSE, TRUE);
  $ampm_lower = date_ampm_options(FALSE, FALSE);
  $regex2 = strtr(preg_replace($patterns, $repl2, $format_regexp, 1), array(
    'A' => '(' . preg_quote($ampm_upper['am'], '`') . '|' . preg_quote($ampm_upper['pm'], '`') . ')',
    'a' => '(' . preg_quote($ampm_lower['am'], '`') . '|' . preg_quote($ampm_lower['pm'], '`') . ')',
  ));
  preg_match('`^' . $regex2 . '$`u', $date, $values);
  array_shift($values);

  // If we did not find all the values for the patterns in the format, abort.
  if (count($letters) != count($values)) {
    $this->errors['invalid'] = t('The value @date does not match the expected format.', array(
      '@date' => $date,
    ));
    return FALSE;
  }
  $this->granularity = array();
  $final_date = array(
    'hour' => 0,
    'minute' => 0,
    'second' => 0,
    'month' => 1,
    'day' => 1,
    'year' => 0,
  );
  foreach ($letters as $i => $letter) {
    $value = $values[$i];
    switch ($letter) {
      case 'd':
      case 'j':
        $final_date['day'] = intval($value);
        $this
          ->addGranularity('day');
        if (empty($value)) {
          $this->errors['day'] = t('The day is invalid.');
        }
        break;
      case 'n':
      case 'm':
        $final_date['month'] = intval($value);
        $this
          ->addGranularity('month');
        if (empty($value)) {
          $this->errors['month'] = t('The month is invalid.');
        }
        break;
      case 'F':
        $array_month_long = array_flip(date_month_names());
        $final_date['month'] = array_key_exists($value, $array_month_long) ? $array_month_long[$value] : -1;
        $this
          ->addGranularity('month');
        break;
      case 'M':
        $array_month = array_flip(date_month_names_abbr());
        $final_date['month'] = array_key_exists($value, $array_month) ? $array_month[$value] : -1;
        $this
          ->addGranularity('month');
        break;
      case 'Y':
        $final_date['year'] = $value;
        $this
          ->addGranularity('year');
        if (strlen($value) < 4) {
          $this->errors['year'] = t('The year is invalid. Please check that entry includes four digits.');
        }
        break;
      case 'y':
        $year = $value;

        // If no century, we add the current one ("06" => "2006").
        $final_date['year'] = str_pad($year, 4, substr(date("Y"), 0, 2), STR_PAD_LEFT);
        $this
          ->addGranularity('year');
        break;
      case 'a':
        $ampm = $value == $ampm_lower['am'] ? 'am' : 'pm';
        break;
      case 'A':
        $ampm = $value == $ampm_upper['am'] ? 'am' : 'pm';
        break;
      case 'g':
      case 'h':
      case 'G':
      case 'H':
        $final_date['hour'] = intval($value);
        $this
          ->addGranularity('hour');
        break;
      case 'i':
        $final_date['minute'] = intval($value);
        $this
          ->addGranularity('minute');
        break;
      case 's':
        $final_date['second'] = intval($value);
        $this
          ->addGranularity('second');
        break;
      case 'U':
        parent::__construct($value, $tz ? $tz : new DateTimeZone("UTC"));
        $this
          ->addGranularity('year');
        $this
          ->addGranularity('month');
        $this
          ->addGranularity('day');
        $this
          ->addGranularity('hour');
        $this
          ->addGranularity('minute');
        $this
          ->addGranularity('second');
        return $this;
    }
  }
  if (isset($ampm)) {
    if ($ampm == 'pm' && $final_date['hour'] < 12) {
      $final_date['hour'] += 12;
    }
    elseif ($ampm == 'am' && $final_date['hour'] == 12) {
      $final_date['hour'] -= 12;
    }
  }

  // Blank becomes current time, given TZ.
  parent::__construct('', $tz ? $tz : new DateTimeZone("UTC"));
  if ($tz) {
    $this
      ->addGranularity('timezone');
  }

  // SetDate expects an integer value for the year, results can be unexpected
  // if we feed it something like '0100' or '0000'.
  $final_date['year'] = intval($final_date['year']);
  $this->errors += $this
    ->arrayErrors($final_date);
  $granularity = drupal_map_assoc($this->granularity);

  // If the input year value is empty or '0000', PHP's date class will later
  // incorrectly convert it if we do setDate() here. If we don't do setDate()
  // here, it will default to the current date and we will lose any way to
  // tell that there was no date in the original input value(s). So set a
  // flag we can use later to tell that this date object was created using
  // only time values, and that the date values are artificial.
  if (empty($final_date['year'])) {
    $this->timeOnly = TRUE;
  }
  elseif (empty($this->errors)) {

    // setDate() expects a valid year, month, and day.
    // Set some defaults for dates that don't use this to
    // keep PHP from interpreting it as the last day of
    // the previous month or last month of the previous year.
    if (empty($granularity['month'])) {
      $final_date['month'] = 1;
    }
    if (empty($granularity['day'])) {
      $final_date['day'] = 1;
    }
    $this
      ->setDate($final_date['year'], $final_date['month'], $final_date['day']);
  }
  if (empty($final_date['hour']) && empty($final_date['minute']) && empty($final_date['second'])) {
    $this->dateOnly = TRUE;
  }
  if (empty($this->errors)) {
    $this
      ->setTime($final_date['hour'], $final_date['minute'], $final_date['second']);
  }
  return $this;
}