Package jodd.datetime.format

Source Code of jodd.datetime.format.AbstractFormatter

// Copyright (c) 2003-2014, Jodd Team (jodd.org). All Rights Reserved.

package jodd.datetime.format;

import jodd.datetime.DateTimeStamp;
import jodd.datetime.JDateTime;
import jodd.util.CharUtil;

/**
* Abstract formatter for easier {@link JdtFormatter} implementations.
* <p>
* For setting date and time, default formatter parses input String against
* specified format. It extracts parts of input string upon patterns
* and then each part is converted to a number for a date/time information.
* It doesn't ignore any non-number character. If conversion fails,
* <code>null</code> is returned.
*
* <p>
* Getting date time is also user friendly. Specified format may not only
* contains patterns but also any text. To remove errors in decoding when
* text may be recognize as one of patterns, format text may be quoted
* with the special escape sign. Double quote in the text will be decoded
* as a single quote, of course.
* <p>
*
* It is not necessary to have parsers for all patterns.
*/
public abstract class AbstractFormatter implements JdtFormatter {

  /**
   * Available patterns list. Used by {@link #findPattern(char[], int)}
   * when parsing date time format. Each formatter will have its own set of
   * patterns, in strictly defined order.
   */
  protected char[][] patterns;

  /**
   * Escape character.
   */
  protected char escapeChar = '\'';


  /**
   * Converts String array of patterns to char arrays.
   */
  protected void preparePatterns(String[] spat) {
    patterns = new char[spat.length][];
    for (int i = 0; i < spat.length; i++) {
      patterns[i] = spat[i].toCharArray();
    }
  }

  /**
   * Finds the longest pattern in provided format starting from specified position.
   * All available patterns are stored in {@link #patterns}.
   *
   * @param format  date time format to examine
   * @param i         starting index
   *
   * @return  0-based index of founded pattern, or <code>-1</code> if pattern not found
   */
  protected int findPattern(char[] format, int i) {
    int frmtc_len = format.length;
    boolean match;
    int n, lastn = -1;
    int maxLen = 0;
    for (n = 0; n < patterns.length; n++) {
      char[] curr = patterns[n];          // current pattern from the pattern list
      if (i > frmtc_len - curr.length) {
        continue;
      }
      match = true;
      int delta = 0;
      while (delta < curr.length) {          // match given pattern
        if (curr[delta] != format[i + delta]) {
          match = false;              // no match, go to next
          break;
        }
        delta++;
      }
      if (match == true) {                // match
        if (patterns[n].length > maxLen) {    // find longest match
          lastn = n;
          maxLen = patterns[n].length;
        }
      }
    }
    return lastn;
  }

  // ---------------------------------------------------------------- convert

  /**
   * Creates a date-time string for founded pattern. Founded patterns
   * is identified by its {@link #patterns} index.
   *
   * @param patternIndex      index of founded pattern
   * @param jdt               date time information
   */
  protected abstract String convertPattern(int patternIndex, JDateTime jdt);

  /**
   * {@inheritDoc}
   * @see JdtFormatter#convert(JDateTime, String)
   */
  public String convert(JDateTime jdt, String format) {
    char[] fmtc = format.toCharArray();
    int fmtc_len = fmtc.length;
    StringBuilder result = new StringBuilder(fmtc_len);

    int i = 0;
    while (i < fmtc_len) {
      if (fmtc[i] == escapeChar) {            // quote founded
        int end = i + 1;
        while (end < fmtc_len) {
          if (fmtc[end] == escapeChar) {        // second quote founded
            if (end + 1 < fmtc_len) {
              end++;
              if (fmtc[end] == escapeChar) {  // skip double quotes
                result.append(escapeChar)// and continue
              } else {
                break;
              }
            }
          } else {
            result.append(fmtc[end]);
          }
          end++;
        }
        i = end;
        continue;      // end of quoted string, continue the main loop
      }

      int n = findPattern(fmtc, i);
      if (n != -1) {      // pattern founded
        result.append(convertPattern(n, jdt));
        i += patterns[n].length;
      } else {
        result.append(fmtc[i]);
        i++;
      }
    }
    return result.toString();
  }

  // ---------------------------------------------------------------- parse

  /**
   * Parses value for matched pattern. Founded patterns
   * is identified by its {@link #patterns} index.
   * Note that value may represent both integer and decimals.
   * May throw {@link NumberFormatException}.
   *
   * @param patternIndex      index of founded pattern
   * @param value             value to parse, no spaces or tabs
   * @param destination       destination to modify
   */
  protected abstract void parseValue(int patternIndex, String value, DateTimeStamp destination);

  /**
   * {@inheritDoc}
   * @see JdtFormatter#parse(String, String)
   */
  public DateTimeStamp parse(String value, String format) {
    char[] valueChars = value.toCharArray();
    char[] formatChars = format.toCharArray();

    int i = 0, j = 0;
    int valueLen = valueChars.length;
    int formatLen = formatChars.length;

    // detect if separators are used
    boolean useSeparators = true;

    if (valueLen == formatLen) {
      useSeparators = false;

      for (char valueChar : valueChars) {
        if (CharUtil.isDigit(valueChar) == false) {
          useSeparators = true;
          break;
        }
      }
    }

    DateTimeStamp time = new DateTimeStamp();
    StringBuilder sb = new StringBuilder();
    while (true) {
      int n = findPattern(formatChars, i);
      if (n != -1) {          // pattern founded
        int patternLen = patterns[n].length;
        i += patternLen;
        sb.setLength(0);
        if (useSeparators == false) {
          for (int k = 0; k < patternLen; k++) {
            sb.append(valueChars[j++]);
          }
        } else {
          char next = 0xFFFF;
          if (i < formatLen) {
            next = formatChars[i];      // next = delimiter
          }
          while ((j < valueLen) && (valueChars[j] != next)) {
            char scj = valueChars[j];
            if ((scj != ' ') && (scj != '\t')) {    // ignore surrounding whitespaces
              sb.append(valueChars[j]);
            }
            j++;
          }
        }

        parseValue(n, sb.toString(), time);
      } else  {
        if (!useSeparators) {
          throw new IllegalArgumentException("Invalid value: " + value);
        }
        if (formatChars[i] == valueChars[j]) {
          j++;
        }
        i++;
      }
      if ((i == formatLen) || (j == valueLen)) {
        break;
      }
    }
    return time;
  }


  // ---------------------------------------------------------------- util

  /**
   * Prints values 00 - 99.
   */
  protected String print2(int value) {
    if (value < 0) {
      throw new IllegalArgumentException("Value must be positive: " + value);
    }
    if (value < 10) {
      return '0' + Integer.toString(value);
    }
    if (value < 100) {
      return Integer.toString(value);
    }
    throw new IllegalArgumentException("Value too big: " + value);
  }

  /**
   * Prints values 00 - 999.
   */
  protected String print3(int value) {
    if (value < 0) {
      throw new IllegalArgumentException("Value must be positive: " + value);
    }
    if (value < 10) {
      return "00" + Integer.toString(value);
    }
    if (value < 100) {
      return '0' + Integer.toString(value);
    }
    if (value < 1000) {
      return Integer.toString(value);
    }
    throw new IllegalArgumentException("Value too big: " + value);
  }

  /**
   * Prints 4 digits and optional minus sign.
   */
  protected String printPad4(int value) {
    char[] result = new char[4];
    int count = 0;

    if (value < 0) {
      result[count++] = '-';
      value = -value;
    }

    String str = Integer.toString(value);

    if (value < 10) {
      result[count++] = '0';
      result[count++] = '0';
      result[count++] = '0';
      result[count++] = str.charAt(0);
    } else if (value < 100) {
      result[count++] = '0';
      result[count++] = '0';
      result[count++] = str.charAt(0);
      result[count++] = str.charAt(1);
    } else if (value < 1000) {
      result[count++] = '0';
      result[count++] = str.charAt(0);
      result[count++] = str.charAt(1);
      result[count++] = str.charAt(2);
    } else {
      if (count > 0) {
        return '-' + str;
      }
      return str;
    }
    return new String(result, 0, count);
  }
}
TOP

Related Classes of jodd.datetime.format.AbstractFormatter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.