src/com/darkyen/TimePattern.java
/**
	 * Parse time token at positionRef[0] and move positionRef[0] to the first character after the pattern.
	 * @return parsed time token or null (in which case positionRef[0] may contain bogus)
	 */
Parse time token at positionRef[0] and move positionRef[0] to the first character after the pattern.
@return parsed time token or null (in which case positionRef[0] may contain bogus)
Parse time token at positionRef [ 0 ] and move positionRef [ 0 ] to the first character after the pattern . @return parsed time token or null ( in which case positionRef [ 0 ] may contain bogus )
private static TimeToken parseTimeToken(CharSequence source, int[] positionRef, List<ParseError> parseErrors) {
		/*
		Format in pseudo regex:
		[lt0]?<u>' '?('"'[^"]+'"')?'s'?
    	1. Pattern itself may be prefixed with one of specified characters.
    		This signifies which mode is used.
    		If this leads to the format not being printed and the {{pattern}} is on each side surrounded by space,
    		one space is then dropped, to prevent unsightly double-spaces (start or end of string is treated as space too).
        	- 'l' OMIT_LEADING
        	- 't' OMIT_TRAILING
        	- '0' OMIT_ZERO
        2. TimeUnit - letter which specifies which unit this pattern is about
    	3. Then an optional space character, which, if present, denotes that there should be a space between the number and unit string
    	4. Then, optionally, arbitrary string enclosed in " quotes (the string may not contain ").
    		This string will be used instead of the default unit (which is the unit-letter itself).
    	5. Then, optionally, single letter 's' to denote that the unit string should have s appended, if the value is not 1.
    	Whole time token specifier X is enclosed in {{X}}.
		 */
		if (!parse(source, positionRef, "{{")) {
			return null;
		}
		TimeTokenMode mode = TimeTokenMode.ALWAYS;
		if (parse(source, positionRef, "l")) {
			mode = TimeTokenMode.OMIT_LEADING;
		} else if (parse(source, positionRef, "t")) {
			mode = TimeTokenMode.OMIT_TRAILING;
		} else if (parse(source, positionRef, "0")) {
			mode = TimeTokenMode.OMIT_ZERO;
		}
		TimeUnit unit = null;
		for (TimeUnit u : TimeUnit.UNITS) {
			if (parse(source, positionRef, u.unit)) {
				unit = u;
				break;
			}
		}
		if (unit == null) {
			if (mode != TimeTokenMode.ALWAYS) {
				parseErrors.add(new ParseError(positionRef[0], "Time unit character expected (one of 'w', 'd', 'h', 'm' or 's')"));
			} else {
				parseErrors.add(new ParseError(positionRef[0], "Time unit or mode character expected (time unit is one of 'w', 'd', 'h', 'm' or 's' and mode is one of 'l', 't' or '0')"));
			}
			return null;
		}
		final boolean spaceBeforeUnit = parse(source, positionRef, " ");
		final String unitText;
		final int unitTextStartIndex = positionRef[0];
		if (parse(source, positionRef, "\"")) {
			final StringBuilder unitTextSb = new StringBuilder();
			parsingUnitText:
			{
				while (positionRef[0] < source.length()) {
					final char c = source.charAt(positionRef[0]++);
					if (c == '"') {
						break parsingUnitText;
					} else {
						unitTextSb.append(c);
					}
				}
				parseErrors.add(new ParseError(unitTextStartIndex, "Unit description text string is not closed"));
				return null;
			}
			unitText = unitTextSb.toString();
		} else {
			unitText = unit.unit;
		}
		final boolean pluralize = parse(source, positionRef, "s");
		if (!parse(source, positionRef, "}}")) {
			parseErrors.add(new ParseError(positionRef[0], "Closing '}}' expected"));
			return null;
		}
		return new TimeToken(unit, mode, unitText, spaceBeforeUnit, pluralize ? "s" : null);
	}
private static TimeToken parseTimeToken ( CharSequence source , int [ ] positionRef , List < ParseError > parseErrors ) { /*
		Format in pseudo regex:
		[lt0]?<u>' '?('"'[^"]+'"')?'s'?

    	1. Pattern itself may be prefixed with one of specified characters.
    		This signifies which mode is used.
    		If this leads to the format not being printed and the {{pattern}} is on each side surrounded by space,
    		one space is then dropped, to prevent unsightly double-spaces (start or end of string is treated as space too).
        	- 'l' OMIT_LEADING
        	- 't' OMIT_TRAILING
        	- '0' OMIT_ZERO
        2. TimeUnit - letter which specifies which unit this pattern is about
    	3. Then an optional space character, which, if present, denotes that there should be a space between the number and unit string
    	4. Then, optionally, arbitrary string enclosed in " quotes (the string may not contain ").
    		This string will be used instead of the default unit (which is the unit-letter itself).
    	5. Then, optionally, single letter 's' to denote that the unit string should have s appended, if the value is not 1.

    	Whole time token specifier X is enclosed in {{X}}.
		 */ if ( ! parse ( source , positionRef , "{{" ) ) { return null ; } TimeTokenMode mode = TimeTokenMode . ALWAYS ; if ( parse ( source , positionRef , "l" ) ) { mode = TimeTokenMode . OMIT_LEADING ; } else if ( parse ( source , positionRef , "t" ) ) { mode = TimeTokenMode . OMIT_TRAILING ; } else if ( parse ( source , positionRef , "0" ) ) { mode = TimeTokenMode . OMIT_ZERO ; } TimeUnit unit = null ; for ( TimeUnit u : TimeUnit . UNITS ) { if ( parse ( source , positionRef , u . unit ) ) { unit = u ; break ; } } if ( unit == null ) { if ( mode != TimeTokenMode . ALWAYS ) { parseErrors . add ( new ParseError ( positionRef [ 0 ] , "Time unit character expected (one of 'w', 'd', 'h', 'm' or 's')" ) ) ; } else { parseErrors . add ( new ParseError ( positionRef [ 0 ] , "Time unit or mode character expected (time unit is one of 'w', 'd', 'h', 'm' or 's' and mode is one of 'l', 't' or '0')" ) ) ; } return null ; } final boolean spaceBeforeUnit = parse ( source , positionRef , " " ) ; final String unitText ; final int unitTextStartIndex = positionRef [ 0 ] ; if ( parse ( source , positionRef , "\"" ) ) { final StringBuilder unitTextSb = new StringBuilder ( ) ; parsingUnitText : { while ( positionRef [ 0 ] < source . length ( ) ) { final char c = source . charAt ( positionRef [ 0 ] ++ ) ; if ( c == '"' ) { break parsingUnitText ; } else { unitTextSb . append ( c ) ; } } parseErrors . add ( new ParseError ( unitTextStartIndex , "Unit description text string is not closed" ) ) ; return null ; } unitText = unitTextSb . toString ( ) ; } else { unitText = unit . unit ; } final boolean pluralize = parse ( source , positionRef , "s" ) ; if ( ! parse ( source , positionRef , "}}" ) ) { parseErrors . add ( new ParseError ( positionRef [ 0 ] , "Closing '}}' expected" ) ) ; return null ; } return new TimeToken ( unit , mode , unitText , spaceBeforeUnit , pluralize ? "s" : null ) ; }
Parse time token at positionRef[0] and move positionRef[0] to the first character after the pattern.
Parse time token at positionRef [ 0 ] and move positionRef [ 0 ] to the first character after the pattern .
// No unit specified // String is unclosed!