Improve datetime parser
This commit is contained in:
parent
af2ded8fe0
commit
66e5c4fdf1
|
@ -13,6 +13,7 @@ public class DateUtilsTest extends AndroidTestCase {
|
||||||
|
|
||||||
public void testParseDateWithMicroseconds() throws Exception {
|
public void testParseDateWithMicroseconds() throws Exception {
|
||||||
GregorianCalendar exp = new GregorianCalendar(2015, 2, 28, 13, 31, 4);
|
GregorianCalendar exp = new GregorianCalendar(2015, 2, 28, 13, 31, 4);
|
||||||
|
exp.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||||
Date expected = new Date(exp.getTimeInMillis() + 963);
|
Date expected = new Date(exp.getTimeInMillis() + 963);
|
||||||
Date actual = DateUtils.parse("2015-03-28T13:31:04.963870");
|
Date actual = DateUtils.parse("2015-03-28T13:31:04.963870");
|
||||||
assertEquals(expected, actual);
|
assertEquals(expected, actual);
|
||||||
|
@ -20,6 +21,7 @@ public class DateUtilsTest extends AndroidTestCase {
|
||||||
|
|
||||||
public void testParseDateWithCentiseconds() throws Exception {
|
public void testParseDateWithCentiseconds() throws Exception {
|
||||||
GregorianCalendar exp = new GregorianCalendar(2015, 2, 28, 13, 31, 4);
|
GregorianCalendar exp = new GregorianCalendar(2015, 2, 28, 13, 31, 4);
|
||||||
|
exp.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||||
Date expected = new Date(exp.getTimeInMillis() + 960);
|
Date expected = new Date(exp.getTimeInMillis() + 960);
|
||||||
Date actual = DateUtils.parse("2015-03-28T13:31:04.96");
|
Date actual = DateUtils.parse("2015-03-28T13:31:04.96");
|
||||||
assertEquals(expected, actual);
|
assertEquals(expected, actual);
|
||||||
|
@ -27,6 +29,7 @@ public class DateUtilsTest extends AndroidTestCase {
|
||||||
|
|
||||||
public void testParseDateWithDeciseconds() throws Exception {
|
public void testParseDateWithDeciseconds() throws Exception {
|
||||||
GregorianCalendar exp = new GregorianCalendar(2015, 2, 28, 13, 31, 4);
|
GregorianCalendar exp = new GregorianCalendar(2015, 2, 28, 13, 31, 4);
|
||||||
|
exp.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||||
Date expected = new Date(exp.getTimeInMillis() + 900);
|
Date expected = new Date(exp.getTimeInMillis() + 900);
|
||||||
Date actual = DateUtils.parse("2015-03-28T13:31:04.9");
|
Date actual = DateUtils.parse("2015-03-28T13:31:04.9");
|
||||||
assertEquals(expected.getTime()/1000, actual.getTime()/1000);
|
assertEquals(expected.getTime()/1000, actual.getTime()/1000);
|
||||||
|
@ -82,4 +85,20 @@ public class DateUtilsTest extends AndroidTestCase {
|
||||||
assertEquals(expected, actual);
|
assertEquals(expected, actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testAsctime() throws Exception {
|
||||||
|
GregorianCalendar exp = new GregorianCalendar(2011, 4, 25, 12, 33, 00);
|
||||||
|
exp.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||||
|
Date expected = new Date(exp.getTimeInMillis());
|
||||||
|
Date actual = DateUtils.parse("Wed, 25 May 2011 12:33:00");
|
||||||
|
assertEquals(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testMultipleConsecutiveSpaces() throws Exception {
|
||||||
|
GregorianCalendar exp = new GregorianCalendar(2010, 2, 23, 6, 6, 26);
|
||||||
|
exp.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||||
|
Date expected = new Date(exp.getTimeInMillis());
|
||||||
|
Date actual = DateUtils.parse("Tue, 23 Mar 2010 01:06:26 -0500");
|
||||||
|
assertEquals(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import java.text.ParsePosition;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses several date formats.
|
* Parses several date formats.
|
||||||
|
@ -17,50 +18,66 @@ public class DateUtils {
|
||||||
private static final String TAG = "DateUtils";
|
private static final String TAG = "DateUtils";
|
||||||
|
|
||||||
private static final SimpleDateFormat parser = new SimpleDateFormat("", Locale.US);
|
private static final SimpleDateFormat parser = new SimpleDateFormat("", Locale.US);
|
||||||
|
private static final TimeZone defaultTimezone = TimeZone.getTimeZone("GMT");
|
||||||
|
|
||||||
static {
|
static {
|
||||||
parser.setLenient(false);
|
parser.setLenient(false);
|
||||||
|
parser.setTimeZone(defaultTimezone);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Date parse(final String input) {
|
public static Date parse(final String input) {
|
||||||
if(input == null) {
|
if(input == null) {
|
||||||
throw new IllegalArgumentException("Date most not be null");
|
throw new IllegalArgumentException("Date must not be null");
|
||||||
}
|
}
|
||||||
String date = input.replace('/', '-');
|
String date = input.trim().replace('/', '-').replaceAll("( ){2,}+", " ");
|
||||||
|
|
||||||
|
// if datetime is more precise than seconds, make sure the value is in ms
|
||||||
if(date.contains(".")) {
|
if(date.contains(".")) {
|
||||||
int start = date.indexOf('.');
|
int start = date.indexOf('.');
|
||||||
int current = start+1;
|
int current = start+1;
|
||||||
while(current < date.length() && Character.isDigit(date.charAt(current))) {
|
while(current < date.length() && Character.isDigit(date.charAt(current))) {
|
||||||
current++;
|
current++;
|
||||||
}
|
}
|
||||||
|
// even more precise than microseconds: discard further decimal places
|
||||||
if(current - start > 4) {
|
if(current - start > 4) {
|
||||||
if(current < date.length()-1) {
|
if(current < date.length()-1) {
|
||||||
date = date.substring(0, start + 4) + date.substring(current);
|
date = date.substring(0, start + 4) + date.substring(current);
|
||||||
} else {
|
} else {
|
||||||
date = date.substring(0, start + 4);
|
date = date.substring(0, start + 4);
|
||||||
}
|
}
|
||||||
|
// less than 4 decimal places: pad to have a consistent format for the parser
|
||||||
} else if(current - start < 4) {
|
} else if(current - start < 4) {
|
||||||
if(current < date.length()-1) {
|
if(current < date.length()-1) {
|
||||||
date = date.substring(0, current) + StringUtils.repeat("0", 4-(current-start)) + date.substring(current);
|
date = date.substring(0, current) + StringUtils.repeat("0", 4-(current-start)) + date.substring(current);
|
||||||
} else {
|
} else {
|
||||||
date = date.substring(0, current) + StringUtils.repeat("0", 4-(current-start));
|
date = date.substring(0, current) + StringUtils.repeat("0", 4-(current-start));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
String[] patterns = {
|
String[] patterns = {
|
||||||
"dd MMM yy HH:mm:ss Z",
|
"dd MMM yy HH:mm:ss Z",
|
||||||
"dd MMM yy HH:mm Z",
|
"dd MMM yy HH:mm Z",
|
||||||
"EEE, dd MMM yyyy HH:mm:ss Z",
|
"EEE, dd MMM yyyy HH:mm:ss Z",
|
||||||
|
"EEE, dd MMM yyyy HH:mm:ss",
|
||||||
"EEE, dd MMMM yyyy HH:mm:ss Z",
|
"EEE, dd MMMM yyyy HH:mm:ss Z",
|
||||||
|
"EEE, dd MMMM yyyy HH:mm:ss",
|
||||||
|
"EEEE, dd MMM yyyy HH:mm:ss Z",
|
||||||
"EEEE, dd MMM yy HH:mm:ss Z",
|
"EEEE, dd MMM yy HH:mm:ss Z",
|
||||||
|
"EEEE, dd MMM yyyy HH:mm:ss",
|
||||||
|
"EEEE, dd MMM yy HH:mm:ss",
|
||||||
"EEE MMM d HH:mm:ss yyyy",
|
"EEE MMM d HH:mm:ss yyyy",
|
||||||
"EEE, dd MMM yyyy HH:mm Z",
|
"EEE, dd MMM yyyy HH:mm Z",
|
||||||
|
"EEE, dd MMM yyyy HH:mm",
|
||||||
"EEE, dd MMMM yyyy HH:mm Z",
|
"EEE, dd MMMM yyyy HH:mm Z",
|
||||||
|
"EEE, dd MMMM yyyy HH:mm",
|
||||||
|
"EEEE, dd MMM yyyy HH:mm Z",
|
||||||
"EEEE, dd MMM yy HH:mm Z",
|
"EEEE, dd MMM yy HH:mm Z",
|
||||||
|
"EEEE, dd MMM yyyy HH:mm",
|
||||||
|
"EEEE, dd MMM yy HH:mm",
|
||||||
"EEE MMM d HH:mm yyyy",
|
"EEE MMM d HH:mm yyyy",
|
||||||
"yyyy-MM-dd'T'HH:mm:ss",
|
"yyyy-MM-dd'T'HH:mm:ss",
|
||||||
"yyyy-MM-dd'T'HH:mm:ss.SSS",
|
|
||||||
"yyyy-MM-dd'T'HH:mm:ss.SSS Z",
|
"yyyy-MM-dd'T'HH:mm:ss.SSS Z",
|
||||||
|
"yyyy-MM-dd'T'HH:mm:ss.SSS",
|
||||||
"yyyy-MM-dd'T'HH:mm:ssZ",
|
"yyyy-MM-dd'T'HH:mm:ssZ",
|
||||||
"yyyy-MM-dd'T'HH:mm:ss'Z'",
|
"yyyy-MM-dd'T'HH:mm:ss'Z'",
|
||||||
"yyyy-MM-ddZ",
|
"yyyy-MM-ddZ",
|
||||||
|
@ -77,7 +94,7 @@ public class DateUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.d(TAG, "Could not parse date string \"" + input + "\"");
|
Log.d(TAG, "Could not parse date string \"" + input + "\" [" + date + "]");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,6 +134,7 @@ public class DateUtils {
|
||||||
|
|
||||||
public static String formatRFC3339UTC(Date date) {
|
public static String formatRFC3339UTC(Date date) {
|
||||||
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
|
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
|
||||||
|
format.setTimeZone(defaultTimezone);
|
||||||
return format.format(date);
|
return format.format(date);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue