/**
  * Converts a date string to a timestamp.
  * @param string $value the date string to be parsed
  * @param string $pattern the pattern that the date string is following
  * @param array $defaults the default values for year, month, day, hour, minute and second.
  * The default values will be used in case when the pattern doesn't specify the
  * corresponding fields. For example, if the pattern is 'MM/dd/yyyy' and this
  * parameter is array('minute'=>0, 'second'=>0), then the actual minute and second
  * for the parsing result will take value 0, while the actual hour value will be
  * the current hour obtained by date('H'). This parameter has been available since version 1.1.5.
  * @return integer timestamp for the date string. False if parsing fails.
  */
 public static function parse($value, $pattern = 'MM/dd/yyyy', $defaults = array())
 {
     $tokens = self::tokenize($pattern);
     $i = 0;
     $n = strlen($value);
     foreach ($tokens as $token) {
         switch ($token) {
             case 'yyyy':
                 if (($year = self::parseInteger($value, $i, 4, 4)) === false) {
                     return false;
                 }
                 $i += 4;
                 break;
             case 'yy':
                 if (($year = self::parseInteger($value, $i, 1, 2)) === false) {
                     return false;
                 }
                 $i += strlen($year);
                 break;
             case 'MM':
                 if (($month = self::parseInteger($value, $i, 2, 2)) === false) {
                     return false;
                 }
                 $i += 2;
                 break;
             case 'M':
                 if (($month = self::parseInteger($value, $i, 1, 2)) === false) {
                     return false;
                 }
                 $i += strlen($month);
                 break;
             case 'dd':
                 if (($day = self::parseInteger($value, $i, 2, 2)) === false) {
                     return false;
                 }
                 $i += 2;
                 break;
             case 'd':
                 if (($day = self::parseInteger($value, $i, 1, 2)) === false) {
                     return false;
                 }
                 $i += strlen($day);
                 break;
             case 'h':
             case 'H':
                 if (($hour = self::parseInteger($value, $i, 1, 2)) === false) {
                     return false;
                 }
                 $i += strlen($hour);
                 break;
             case 'hh':
             case 'HH':
                 if (($hour = self::parseInteger($value, $i, 2, 2)) === false) {
                     return false;
                 }
                 $i += 2;
                 break;
             case 'm':
                 if (($minute = self::parseInteger($value, $i, 1, 2)) === false) {
                     return false;
                 }
                 $i += strlen($minute);
                 break;
             case 'mm':
                 if (($minute = self::parseInteger($value, $i, 2, 2)) === false) {
                     return false;
                 }
                 $i += 2;
                 break;
             case 's':
                 if (($second = self::parseInteger($value, $i, 1, 2)) === false) {
                     return false;
                 }
                 $i += strlen($second);
                 break;
             case 'ss':
                 if (($second = self::parseInteger($value, $i, 2, 2)) === false) {
                     return false;
                 }
                 $i += 2;
                 break;
             case 'a':
                 if (($ampm = self::parseAmPm($value, $i)) === false) {
                     return false;
                 }
                 if (isset($hour)) {
                     if ($hour == 12 && $ampm === 'am') {
                         $hour = 0;
                     } else {
                         if ($hour < 12 && $ampm === 'pm') {
                             $hour += 12;
                         }
                     }
                 }
                 $i += 2;
                 break;
             default:
                 $tn = strlen($token);
                 if ($i >= $n || substr($value, $i, $tn) !== $token) {
                     return false;
                 }
                 $i += $tn;
                 break;
         }
     }
     if ($i < $n) {
         return false;
     }
     if (!isset($year)) {
         $year = isset($defaults['year']) ? $defaults['year'] : date('Y');
     }
     if (!isset($month)) {
         $month = isset($defaults['month']) ? $defaults['month'] : date('n');
     }
     if (!isset($day)) {
         $day = isset($defaults['day']) ? $defaults['day'] : date('j');
     }
     if (strlen($year) === 2) {
         if ($year >= 70) {
             $year += 1900;
         } else {
             $year += 2000;
         }
     }
     $year = (int) $year;
     $month = (int) $month;
     $day = (int) $day;
     if (!isset($hour) && !isset($minute) && !isset($second) && !isset($defaults['hour']) && !isset($defaults['minute']) && !isset($defaults['second'])) {
         $hour = $minute = $second = 0;
     } else {
         if (!isset($hour)) {
             $hour = isset($defaults['hour']) ? $defaults['hour'] : date('H');
         }
         if (!isset($minute)) {
             $minute = isset($defaults['minute']) ? $defaults['minute'] : date('i');
         }
         if (!isset($second)) {
             $second = isset($defaults['second']) ? $defaults['second'] : date('s');
         }
         $hour = (int) $hour;
         $minute = (int) $minute;
         $second = (int) $second;
     }
     if (Timestamp::isValidDate($year, $month, $day) && Timestamp::isValidTime($hour, $minute, $second)) {
         return Timestamp::getTimestamp($hour, $minute, $second, $month, $day, $year);
     } else {
         return false;
     }
 }