/*
* Copyright 2006 Robert Hanson <iamroberthanson AT gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.autosauler.ballance.client.utils;
import java.util.Date;
/**
* This is a simple regular expression based parser for date notations. While
* our aim is to fully support in the future the JDK date parser, currently only
* numeric notations and literals are supported such as
* <code>dd/MM/yyyy HH:mm:ss.SSSS</code>. Each entity is parsed with the same
* number of digits, i.e. for <code>dd</code> two digits will be parsed while
* for <code>d</code> only one will be parsed.
*
* @author <a href="mailto:g.georgovassilis@gmail.com">George Georgovassilis</a>
*
*/
public class SimpleDateParser {
@SuppressWarnings("unused")
private final static String DAY_IN_MONTH = "d";
@SuppressWarnings("unused")
private final static String MONTH = "M";
@SuppressWarnings("unused")
private final static String YEAR = "y";
@SuppressWarnings("unused")
private final static String LITERAL = "\\";
private final static int DATE_PATTERN = 0;
private final static int REGEX_PATTERN = 1;
private final static int COMPONENT = 2;
private final static int REGEX = 0;
private final static int INSTRUCTION = 1;
private final static String[] TOKENS[] = {
{ "SSSS", "(\\d\\d\\d\\d)", DateLocale.TOKEN_MILLISECOND },
{ "SSS", "(\\d\\d\\d)", DateLocale.TOKEN_MILLISECOND },
{ "SS", "(\\d\\d)", DateLocale.TOKEN_MILLISECOND },
{ "S", "(\\d)", DateLocale.TOKEN_MILLISECOND },
{ "ss", "(\\d\\d)", DateLocale.TOKEN_SECOND },
{ "s", "(\\d)", DateLocale.TOKEN_SECOND },
{ "mm", "(\\d\\d)", DateLocale.TOKEN_MINUTE },
{ "m", "(\\d)", DateLocale.TOKEN_MINUTE },
{ "HH", "(\\d\\d)", DateLocale.TOKEN_HOUR_24 },
{ "H", "(\\d)", DateLocale.TOKEN_HOUR_24 },
{ "dd", "(\\d\\d)", DateLocale.TOKEN_DAY_OF_MONTH },
{ "d", "(\\d)", DateLocale.TOKEN_DAY_OF_MONTH },
{ "MM", "(\\d\\d)", DateLocale.TOKEN_MONTH },
{ "M", "(\\d)", DateLocale.TOKEN_MONTH },
{ "yyyy", "(\\d\\d\\d\\d)", DateLocale.TOKEN_YEAR },
{ "yyy", "(\\d\\d\\d)", DateLocale.TOKEN_YEAR },
{ "yy", "(\\d\\d)", DateLocale.TOKEN_YEAR },
{ "y", "(\\d)", DateLocale.TOKEN_YEAR } };
private static void _parse(String format, String[] args) {
if (format.length() == 0) {
return;
}
if (format.startsWith("'")) {
format = format.substring(1);
int end = format.indexOf("'");
if (end == -1) {
throw new IllegalArgumentException("Unmatched single quotes.");
}
args[REGEX] += Pattern.quote(format.substring(0, end));
format = format.substring(end + 1);
}
for (int i = 0; i < TOKENS.length; i++) {
String[] row = TOKENS[i];
String datePattern = row[DATE_PATTERN];
if (!format.startsWith(datePattern)) {
continue;
}
format = format.substring(datePattern.length());
args[REGEX] += row[REGEX_PATTERN];
args[INSTRUCTION] += row[COMPONENT];
_parse(format, args);
return;
}
args[REGEX] += Pattern.quote("" + format.charAt(0));
format = format.substring(1);
_parse(format, args);
};
@SuppressWarnings("deprecation")
private static void load(Date date, String text, String component) {
if (component.equals(DateLocale.TOKEN_MILLISECOND)) {
// TODO: implement
}
if (component.equals(DateLocale.TOKEN_SECOND)) {
date.setSeconds(Integer.parseInt(text));
}
if (component.equals(DateLocale.TOKEN_MINUTE)) {
date.setMinutes(Integer.parseInt(text));
}
if (component.equals(DateLocale.TOKEN_HOUR_24)) {
date.setHours(Integer.parseInt(text));
}
if (component.equals(DateLocale.TOKEN_DAY_OF_MONTH)) {
date.setDate(Integer.parseInt(text));
}
if (component.equals(DateLocale.TOKEN_MONTH)) {
date.setMonth(Integer.parseInt(text) - 1);
}
if (component.equals(DateLocale.TOKEN_YEAR)) {
// TODO: fix for short patterns
date.setYear(Integer.parseInt(text) - 1900);
}
}
public static Date parse(String input, String pattern) {
return new SimpleDateParser(pattern).parse(input);
}
private final Pattern regularExpression;
private String instructions = "";
public SimpleDateParser(String format) {
String[] args = new String[] { "", "" };
_parse(format, args);
regularExpression = new Pattern(args[REGEX]);
instructions = args[INSTRUCTION];
}
public Date parse(String input) {
@SuppressWarnings("deprecation")
Date date = new Date(0, 0, 0, 0, 0, 0);
String matches[] = regularExpression.match(input);
if (matches == null) {
throw new IllegalArgumentException(input + " does not match "
+ regularExpression.pattern());
}
if (matches.length - 1 != instructions.length()) {
throw new IllegalArgumentException("Different group count - "
+ input + " does not match " + regularExpression.pattern());
}
for (int group = 0; group < instructions.length(); group++) {
String match = matches[group + 1];
load(date, match, "" + instructions.charAt(group));
}
return date;
}
}