String s = input;
Calendar calendar = new GregorianCalendar(timeZone);
//Find if there is any time information in the date
Matcher matcher = getTimeComponent.matcher(s);
//Remove the time information in order to not confuse the date parsing
s = matcher.replaceFirst("").trim();
// handle date with format "2009-01-12 at 03:36:38" by removing trailing " at";
if ( s.endsWith( " at" )){
s = s.substring(0,s.length()-3).trim();
}
//Find if the date contains letters
matcher = hasLettersPattern.matcher(s);
if(matcher.find()) {
//We have a date with letters, could be age-based or time based (with a literal month)
//Try to determine if it is age-based or time-based
matcher = isAgeBasedPattern.matcher(s);
if(matcher.find()) {
//Age Based date
matcher = todayPattern.matcher(s);
if(matcher.find()) {
//Nothing to do for today as we base our initial date on the current one
} else {
matcher = yesterdayPattern.matcher(s);
if(matcher.find()) {
calendar.add(Calendar.DATE, -1);
} else {
//We're in the real "ago" case, let's remove " ago" if it's there
s = s.replaceAll("ago","").trim();
matcher = agoSpacerPattern.matcher(s);
s = matcher.replaceAll("$1 $2");
matcher = agoTimeRangePattern.matcher(s);
boolean seenHoursAsLowerCaseH = false;
while(matcher.find()) {
String unit = matcher.group(2);
if(unit.equals("h")) {
seenHoursAsLowerCaseH = true;
}
String lUnit = unit.toLowerCase();
float value = Float.parseFloat(matcher.group(1));
int intValue = (int) value;
if(lUnit.startsWith("sec")) {
calendar.add(Calendar.SECOND, -intValue);
} else if(lUnit.startsWith("min") || (unit.equals("m") && seenHoursAsLowerCaseH)) {
calendar.add(Calendar.MINUTE, -intValue);
int seconds = (int) ((value - intValue)*60f);
calendar.add(Calendar.SECOND, -seconds);
} else if(lUnit.startsWith("h")) {
calendar.add(Calendar.HOUR_OF_DAY, -intValue);
int seconds = (int) ((value - intValue)*3600f);
calendar.add(Calendar.SECOND, -seconds);
} else if(lUnit.startsWith("d")) {
calendar.add(Calendar.DATE, -intValue);
int seconds = (int) ((value - intValue)*86400f);
calendar.add(Calendar.SECOND, -seconds);
} else if(lUnit.startsWith("w")) {
calendar.add(Calendar.WEEK_OF_YEAR, -intValue);
//604800 seconds in a week
int seconds = (int) ((value - intValue)*640800f);
calendar.add(Calendar.SECOND, -seconds);
} //The month case when m is not a minute
else if(lUnit.startsWith("m")) {
calendar.add(Calendar.MONTH, -intValue);
//about 720 hours per month
int hours = (int) ((value - intValue)*720f);
calendar.add(Calendar.HOUR_OF_DAY, -hours);
} else if(lUnit.startsWith("y")) {
calendar.add(Calendar.YEAR, -intValue);
//about 8760 hours per year
int hours = (int) ((value - intValue)*8760);
calendar.add(Calendar.HOUR_OF_DAY, -hours);
} else {
//System.out.println("Unit not matched : " + unit);
}
}
}
}
//System.out.println(input + " > " + calendar.getTime());
} else {
//Time based date
//System.out.println("DL : " + s);
matcher = timeBasedDateWithLettersPattern.matcher(s);
if(matcher.find()) {
int day = Integer.parseInt(matcher.group(1));
calendar.set(Calendar.DAY_OF_MONTH,day);
String monthStr = " " + matcher.group(2).toLowerCase();
int month = -1;
for(int i = 0 ; i < MONTHS_LIST.length ; i++) {
if(MONTHS_LIST[i].indexOf(monthStr) != -1) {
month = i;
}
}
if(month > -1) {
calendar.set(Calendar.MONTH,month);
}
boolean hasYear = matcher.group(3) != null;
if(hasYear) {
int year = Integer.parseInt(matcher.group(3));
if(year < 100) {
year += 2000;
}
calendar.set(Calendar.YEAR,year);
}
calendar.set(Calendar.HOUR_OF_DAY,0);
calendar.set(Calendar.MINUTE,0);
calendar.set(Calendar.SECOND,0);
calendar.set(Calendar.MILLISECOND,0);
//System.out.println(input + " > " + calendar.getTime() + "( " + calendar.getTimeZone() + " )");
} else {
matcher = timeBasedDateWithLettersPatternMonthFirst.matcher(s);
if(matcher.find()) {
int day = Integer.parseInt(matcher.group(2));
calendar.set(Calendar.DAY_OF_MONTH,day);
String monthStr = " " + matcher.group(1).toLowerCase();
int month = -1;
for(int i = 0 ; i < MONTHS_LIST.length ; i++) {
if(MONTHS_LIST[i].indexOf(monthStr) != -1) {
month = i;
}
}
if(month > -1) {
calendar.set(Calendar.MONTH,month);
}
boolean hasYear = matcher.group(3) != null;
if(hasYear) {
int year = Integer.parseInt(matcher.group(3));
if(year < 100) {
year += 2000;
}
calendar.set(Calendar.YEAR,year);
}
calendar.set(Calendar.HOUR_OF_DAY,0);
calendar.set(Calendar.MINUTE,0);
calendar.set(Calendar.SECOND,0);
calendar.set(Calendar.MILLISECOND,0);
//System.out.println(input + " > " + calendar.getTime() + "( " + calendar.getTimeZone() + " )");
} else {
System.err.println("Unparseable date : " + input);
}
}
}
} else {
//We have a date with only numbers
//System.out.println("DN : " + s );//+ "(" + input + ")");
//Let's assume a default order of m/d and switch if it doesn't make sense
matcher = numbersOnlyDatePattern.matcher(s);
if(matcher.find()) {
try {
String g1 = matcher.group(1);
String g2 = matcher.group(2);
String g3 = matcher.group(3);
int i1 = Integer.parseInt(g1);
int i2 = Integer.parseInt(g2);
if(g3 != null) {
int i3 = Integer.parseInt(g3);
int day = i1;
int month = i2;
int year = i3;
if(month > 12) {
day = i2;
month = i1;
}
if(year < 100) {
year += 2000;
}
if(g1.length() == 4) {
year = i1;
day = i3;
}
calendar.set(Calendar.YEAR,year);
calendar.set(Calendar.MONTH,month-1);
calendar.set(Calendar.DAY_OF_MONTH,day);
} else {
//2 numbers only, we assume it's day and month
int month = i1;
int day = i2;
if(month > 12) {
day = i1;
month = i2;
}
if(month > 12) {
//TODO : fire an exception ?
System.err.println("Unparseable date : " + input);
} else {
calendar.set(Calendar.MONTH, month-1);
calendar.set(Calendar.DAY_OF_MONTH, day);
}
}
calendar.set(Calendar.HOUR_OF_DAY,0);
calendar.set(Calendar.MINUTE,0);
calendar.set(Calendar.SECOND,0);
calendar.set(Calendar.MILLISECOND,0);
} catch (Exception e) {
e.printStackTrace();
}
}
//System.out.println(input + " > " + calendar.getTime());
}
//Extract the time information
matcher = getTimeComponent.matcher(input);
if(matcher.find()) {
try {
int hours = Integer.parseInt(matcher.group(1));
int minutes = Integer.parseInt(matcher.group(2));
calendar.set(Calendar.MINUTE,minutes);
boolean amPMModifier = matcher.group(5) != null;
boolean hasSeconds = matcher.group(4) != null;
if(hasSeconds) {
int seconds = Integer.parseInt(matcher.group(4));
calendar.set(Calendar.SECOND, seconds);
}
if(amPMModifier) {
String amPm = matcher.group(5).trim().toLowerCase();
if(amPm.equals("am")) {
calendar.set(Calendar.AM_PM,Calendar.AM);
} else {
calendar.set(Calendar.AM_PM,Calendar.PM);
}