blob: cb008a7a728a78a39a0657e55841b6ee3a35cc6e [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.ode.utils;
import java.text.ParseException;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.StringTokenizer;
public class RelativeDateParser {
private static final char YEAR_TEMPLATE_MODIFIER = 'y';
private static final char MONTH_TEMPLATE_MODIFIER = 'M';
private static final char WEEK_TEMPLATE_MODIFIER = 'w';
private static final char DAY_TEMPLATE_MODIFIER = 'd';
private static final char HOUR_TEMPLATE_MODIFIER = 'h';
private static final char MINUTE_TEMPLATE_MODIFIER = 'm';
private static final char SECOND_TEMPLATE_MODIFIER = 's';
/**
* This array of strings contains all supported "modifiers" for method <code>parseRelativeDate</code>.
* NOTE: An order of elements in this array is important and used in algorithm of above method!
*/
private static final char[] TEMPLATE_MODIFIERS_LIST = new char[] {
YEAR_TEMPLATE_MODIFIER, MONTH_TEMPLATE_MODIFIER,
WEEK_TEMPLATE_MODIFIER, DAY_TEMPLATE_MODIFIER,
HOUR_TEMPLATE_MODIFIER, MINUTE_TEMPLATE_MODIFIER,
SECOND_TEMPLATE_MODIFIER, };
/**
* Returns a date which is less than current system date/time on a specified number of days, years, minutes, weeks
* etc.<p/>
* A common template which is valid for this method is like that:<br/>
* <strong>XXXXy XXXXM XXXXw XXXXd XXXXh XXXXm XXXXs</strong>, where:
* <pre>
* XXXX - any positive number composed of four or less digits, but not less that one digit
* y - this symbol represents how many years must be subtracted from current system date
* M - this symbol represents how many months must be subtracted from current system date
* w - this symbol represents how many weeks must be subtracted rom current system date
* d - this symbol represents how many days must be subtracted from current system date
* h - this symbol represents how many hours must be subtracted from current system date
* m - this symbol represents how many minutes must be subtracted from current system date
* s - this symbol represents how many seconds must be subtracted from current system date
* </pre>
* Above symbols are called "modifiers".
* <p><em>Modifiers are case sensitive</em>.
* Modifiers separated by single space character or sequence of spaces.
* Each modifier is optional, but an order of modifiers is matter and must be exactly the same
* how its specified in template.</p>
* <p/>
* Here is a few examples of date templates and its meanings:<br/>
* <code>"4h 3m 23s"</code> - means 4 hours, 3 minutes and 23 seconds ago from current system date<br/>
* <code>"1y 2m 3w"</code> - means 1 year, 2 months and 3 weeks ago from current system date<br/>
* <code>"1m 1w 13h 5m"</code> - means 1 month, 1 week, 13 hours and 5 minutes ago from current system date<br/>
*
* @param dateTemplate a template of a date we want to be calculated
* @return a resulted <code>Date</code> object that is applies specified template
* @throws java.text.ParseException if some problems were occurred while parsing specified date template
*/
public static Date parseRelativeDate(String dateTemplate)
throws java.text.ParseException {
int[] agoValues = new int[TEMPLATE_MODIFIERS_LIST.length];
int currentModifierPointer = 0;
StringTokenizer tokens = new StringTokenizer(dateTemplate.trim());
while (tokens.hasMoreTokens()) {
String token = tokens.nextToken();
if (token.length() < 2 || token.length() > 5) {
throw new ParseException("Invalid token length. Token: "
+ token, dateTemplate.indexOf(token));
}
int modValue;
try {
modValue = Integer.parseInt(token.substring(0,
token.length() - 1));
if (modValue <= 0) {
throw new ParseException(
"Modifier value must be a positive number. Token: "
+ token, dateTemplate.indexOf(token));
}
} catch (NumberFormatException nfe) {
throw new ParseException("Can't parse integer value. Token: "
+ token, dateTemplate.indexOf(token));
}
char mod = token.charAt(token.length() - 1);
while (true) {
if (currentModifierPointer >= TEMPLATE_MODIFIERS_LIST.length) {
throw new ParseException(
"Incorrect modifier at this position. Token: "
+ token, dateTemplate.indexOf(token)
+ token.length() - 1);
} else if (mod != TEMPLATE_MODIFIERS_LIST[currentModifierPointer]) {
currentModifierPointer++;
//continue;
} else if (agoValues[currentModifierPointer] != 0) {
throw new ParseException(
"Dublicated modifier found. Token: " + token,
dateTemplate.indexOf(token) + token.length() - 1);
} else {
agoValues[currentModifierPointer++] = modValue;
break;
}
}
}//while (tokens)
final Calendar calendar = GregorianCalendar.getInstance();
for (int i = 0; i < agoValues.length; i++) {
if (agoValues[i] == 0) {
continue;
}
int calendarField = templateModifierIndexToCalendarField(i);
calendar.add(calendarField, 0 - agoValues[i]);
}
return calendar.getTime();
}
private static int templateModifierIndexToCalendarField(int modifierIndex)
throws IllegalArgumentException {
switch (modifierIndex) {
case 0:
return Calendar.YEAR;
case 1:
return Calendar.MONTH;
case 2:
return Calendar.WEEK_OF_MONTH;
case 3:
return Calendar.DAY_OF_MONTH;
case 4:
return Calendar.HOUR_OF_DAY;
case 5:
return Calendar.MINUTE;
case 6:
return Calendar.SECOND;
}
throw new IllegalArgumentException("Invalid template modifier index: "
+ modifierIndex);
}
}