コード例 #1
0
ファイル: Nibbler.cpp プロジェクト: austinwagner/task
bool Nibbler::getDate (const std::string& format, time_t& t)
{
  auto i = _cursor;

  int month  = -1;   // So we can check later.
  int day    = -1;
  int year   = -1;
  int hour   = -1;
  int minute = -1;
  int second = -1;

  // For parsing, unused.
  int wday    = -1;
  int week    = -1;

  for (unsigned int f = 0; f < format.length (); ++f)
  {
    switch (format[f])
    {
    case 'm':
    case 'M':
      if (! parseDigits(i, month, 2, format[f] == 'M'))
        return false;
      break;

    case 'd':
    case 'D':
      if (! parseDigits(i, day, 2, format[f] == 'D'))
        return false;
      break;

    case 'y':
    case 'Y':
      if (! parseDigits(i, year, format[f] == 'y' ? 2 : 4))
        return false;
      if (format[f] == 'y')
          year += 2000;
      break;

    case 'h':
    case 'H':
      if (! parseDigits(i, hour, 2, format[f] == 'H'))
        return false;
      break;

    case 'n':
    case 'N':
      if (! parseDigits(i, minute, 2, format[f] == 'N'))
        return false;
      break;

    case 's':
    case 'S':
      if (! parseDigits(i, second, 2, format[f] == 'S'))
        return false;
      break;

    // Merely parse, not extract.
    case 'v':
    case 'V':
      if (! parseDigits(i, week, 2, format[f] == 'V'))
        return false;
      break;

    // Merely parse, not extract.
    case 'a':
    case 'A':
      if (i + 3 <= _length          &&
          ! Lexer::isDigit ((*_input)[i + 0]) &&
          ! Lexer::isDigit ((*_input)[i + 1]) &&
          ! Lexer::isDigit ((*_input)[i + 2]))
      {
        wday = ISO8601d::dayOfWeek (_input->substr (i, 3).c_str ());
        i += (format[f] == 'a') ? 3 : ISO8601d::dayName (wday).size ();
      }
      else
        return false;
      break;

    case 'b':
    case 'B':
      if (i + 3 <= _length          &&
          ! Lexer::isDigit ((*_input)[i + 0]) &&
          ! Lexer::isDigit ((*_input)[i + 1]) &&
          ! Lexer::isDigit ((*_input)[i + 2]))
      {
        if (month != -1)
          return false;
        month = ISO8601d::monthOfYear (_input->substr (i, 3).c_str());
        i += (format[f] == 'b') ? 3 : ISO8601d::monthName (month).size ();
      }
      else
        return false;
      break;

    default:
      if (i + 1 <= _length &&
          (*_input)[i] == format[f])
        ++i;
      else
        return false;
      break;
    }
  }

  // By default, the most global date variables that are undefined are put to
  // the current date (for instance, the year to the current year for formats
  // that lack Y/y). If even 'second' is undefined, then the date is parsed as
  // now.
  if (year == -1)
  {
    ISO8601d now;
    year = now.year ();
    if (month == -1)
    {
      month = now.month ();
      if (day == -1)
      {
        day = now.day ();
        if (hour == -1)
        {
          hour = now.hour ();
          if (minute == -1)
          {
            minute = now.minute ();
            if (second == -1)
              second = now.second ();
          }
        }
      }
    }
  }

  // Put all remaining undefined date variables to their default values (0 or
  // 1).
  month  = (month  == -1) ? 1 : month;
  day    = (day    == -1) ? 1 : day;
  hour   = (hour   == -1) ? 0 : hour;
  minute = (minute == -1) ? 0 : minute;
  second = (second == -1) ? 0 : second;

  // Check that values are correct
  if (! ISO8601d::valid (month, day, year, hour, minute, second))
    return false;

  // Convert to epoch.
  struct tm tms {};
  tms.tm_isdst = -1;   // Requests that mktime determine summer time effect.
  tms.tm_mon   = month - 1;
  tms.tm_mday  = day;
  tms.tm_year  = year - 1900;
  tms.tm_hour  = hour;
  tms.tm_min   = minute;
  tms.tm_sec   = second;

  t = mktime (&tms);
  _cursor = i;
  return true;
}