net-commonlib/src/main/java/com/streamsets/pipeline/lib/parser/net/syslog/SyslogDecoder.java
public static long parseRfc5424Date(LoadingCache<String, Long> cache, String tsStr) throws OnRecordErrorException {

    boolean includesTimezone = true;
    long ts;
    int curPos = 0;
    int msgLen = tsStr.length();
    if (msgLen <= RFC5424_PREFIX_LEN) {
      throw new OnRecordErrorException(Errors.SYSLOG_09, tsStr);
    }
    String timestampPrefix = tsStr.substring(curPos, RFC5424_PREFIX_LEN);
    try {
      ts = cache.get(timestampPrefix);
    } catch (ExecutionException ex) {
      Throwable cause = Throwables.getRootCause(ex);
      if (cause instanceof IllegalArgumentException) {
        throw new OnRecordErrorException(Errors.SYSLOG_05, cause, timestampPrefix, cause);
      } else {
        // I don't believe this will ever occur
        throw new IllegalStateException(
            Utils.format(Errors.SYSLOG_05.getMessage(), cause, timestampPrefix),
            cause);
      }
    }
    curPos += RFC5424_PREFIX_LEN;
    // look for the optional fractional seconds
    if (tsStr.charAt(curPos) == '.') {
      // figure out how many numeric digits
      boolean foundEnd = false;
      int endMillisPos = curPos + 1;
      if (msgLen <= endMillisPos) {
        throw new OnRecordErrorException(Errors.SYSLOG_06, tsStr);
      }
      // FIXME: TODO: ensure we handle all bad formatting cases
      while (!foundEnd && endMillisPos < msgLen) {
        char curDigit = tsStr.charAt(endMillisPos);
        if (curDigit >= '0' && curDigit <= '9') {
          endMillisPos++;
        } else {
          foundEnd = true;
        }
      }
      includesTimezone = foundEnd;
      if (!includesTimezone) {
        endMillisPos--;
      }
      // if they had a valid fractional second, append it rounded to millis
      final int fractionalPositions = endMillisPos - (curPos + 1);
      if (fractionalPositions > 0) {
        long milliseconds = Long.parseLong(tsStr.substring(curPos + 1, endMillisPos));
        if (fractionalPositions > 3) {
          milliseconds /= Math.pow(10, (fractionalPositions - 3));
        } else if (fractionalPositions < 3) {
          milliseconds *= Math.pow(10, (3 - fractionalPositions));
        }
        ts += milliseconds;
      } else {
        throw new OnRecordErrorException(Errors.SYSLOG_07, tsStr);
      }
      curPos = endMillisPos;
    }
    // look for timezone
    if (includesTimezone) {
      char tzFirst = tsStr.charAt(curPos);
      // UTC
      if (tzFirst == 'Z') {
        // no-op
      } else if (tzFirst == '+' || tzFirst == '-') {
        if (msgLen <= curPos + 5) {
          throw new OnRecordErrorException(Errors.SYSLOG_08, tsStr);
        }
        int polarity;
        if (tzFirst == '+') {
          polarity = +1;
        } else {
          polarity = -1;
        }

        char[] h = new char[5];
        for (int i = 0; i < 5; i++) {
          h[i] = tsStr.charAt(curPos + 1 + i);
        }

        if (h[0] >= '0' && h[0] <= '9'
            && h[1] >= '0' && h[1] <= '9'
            && h[2] == ':'
            && h[3] >= '0' && h[3] <= '9'
            && h[4] >= '0' && h[4] <= '9') {
          try {
            int hourOffset = Integer.parseInt(tsStr.substring(curPos + 1, curPos + 3));
            int minOffset = Integer.parseInt(tsStr.substring(curPos + 4, curPos + 6));
            ts -= polarity * ((hourOffset * 60L) + minOffset) * 60000L;
          } catch (NumberFormatException nfe) {
            throw new OnRecordErrorException(Errors.SYSLOG_08, tsStr, nfe);
          }
        } else {
          throw new OnRecordErrorException(Errors.SYSLOG_08, tsStr);
        }
      }
    }
    return ts;
  }
public static long parseRfc5424Date(LoadingCache<String, Long> cache, String tsStr) throws OnRecordErrorException {

    boolean includesTimezone = true;
    long ts;
    int curPos = 0;
    int msgLen = tsStr.length();
    if (msgLen <= RFC5424_PREFIX_LEN) {
      throw new OnRecordErrorException(Errors.SYSLOG_09, tsStr);
    }
    String timestampPrefix = tsStr.substring(curPos, RFC5424_PREFIX_LEN);
    try {
      ts = cache.get(timestampPrefix);
    } catch (ExecutionException ex) {
      Throwable cause = Throwables.getRootCause(ex);
      if (cause instanceof IllegalArgumentException) {
        throw new OnRecordErrorException(Errors.SYSLOG_05, cause, timestampPrefix, cause);
      } else {
        // I don't believe this will ever occur
        throw new IllegalStateException(
            Utils.format(Errors.SYSLOG_05.getMessage(), cause, timestampPrefix),
            cause);
      }
    }
    curPos += RFC5424_PREFIX_LEN;
    // look for the optional fractional seconds
    if (tsStr.charAt(curPos) == '.') {
      // figure out how many numeric digits
      boolean foundEnd = false;
      int endMillisPos = curPos + 1;
      if (msgLen <= endMillisPos) {
        throw new OnRecordErrorException(Errors.SYSLOG_06, tsStr);
      }
      // FIXME: TODO: ensure we handle all bad formatting cases
      while (!foundEnd && endMillisPos < msgLen) {
        char curDigit = tsStr.charAt(endMillisPos);
        if (curDigit >= '0' && curDigit <= '9') {
          endMillisPos++;
        } else {
          foundEnd = true;
        }
      }
      includesTimezone = foundEnd;
      if (!includesTimezone) {
        endMillisPos--;
      }
      // if they had a valid fractional second, append it rounded to millis
      final int fractionalPositions = endMillisPos - (curPos + 1);
      if (fractionalPositions > 0) {
        long milliseconds = Long.parseLong(tsStr.substring(curPos + 1, endMillisPos));
        if (fractionalPositions > 3) {
          milliseconds /= Math.pow(10, (fractionalPositions - 3));
        } else if (fractionalPositions < 3) {
          milliseconds *= Math.pow(10, (3 - fractionalPositions));
        }
        ts += milliseconds;
      } else {
        throw new OnRecordErrorException(Errors.SYSLOG_07, tsStr);
      }
      curPos = endMillisPos;
    }
    // look for timezone
    if (includesTimezone) {
      char tzFirst = tsStr.charAt(curPos);
      // UTC
      if (tzFirst == 'Z') {
        // no-op
      } else if (tzFirst == '+' || tzFirst == '-') {
        if (msgLen <= curPos + 5) {
          throw new OnRecordErrorException(Errors.SYSLOG_08, tsStr);
        }
        int polarity;
        if (tzFirst == '+') {
          polarity = +1;
        } else {
          polarity = -1;
        }

        char[] h = new char[5];
        for (int i = 0; i < 5; i++) {
          h[i] = tsStr.charAt(curPos + 1 + i);
        }

        if (h[0] >= '0' && h[0] <= '9'
            && h[1] >= '0' && h[1] <= '9'
            && h[2] == ':'
            && h[3] >= '0' && h[3] <= '9'
            && h[4] >= '0' && h[4] <= '9') {
          try {
            int hourOffset = Integer.parseInt(tsStr.substring(curPos + 1, curPos + 3));
            int minOffset = Integer.parseInt(tsStr.substring(curPos + 4, curPos + 6));
            ts -= polarity * ((hourOffset * 60L) + minOffset) * 60000L;
          } catch (NumberFormatException nfe) {
            throw new OnRecordErrorException(Errors.SYSLOG_08, tsStr, nfe);
          }
        } else {
          throw new OnRecordErrorException(Errors.SYSLOG_08, tsStr);
        }
      }
    }
    return ts;
  }
Parse date in RFC 5424 format. Uses an LRU cache to speed up parsing for
multiple messages that occur in the same second.
@param tsStr
@return Typical (for Java) milliseconds since UNIX epoch