From 66e5c4fdf1325758e03a6146703ae2fd2c68f3db Mon Sep 17 00:00:00 2001 From: Martin Fietz Date: Wed, 29 Jul 2015 18:30:29 +0200 Subject: Improve datetime parser --- .../antennapod/core/tests/util/DateUtilsTest.java | 19 +++++++++++++++ .../de/danoeh/antennapod/core/util/DateUtils.java | 28 ++++++++++++++++++---- 2 files changed, 42 insertions(+), 5 deletions(-) (limited to 'core/src') diff --git a/core/src/androidTest/java/de/danoeh/antennapod/core/tests/util/DateUtilsTest.java b/core/src/androidTest/java/de/danoeh/antennapod/core/tests/util/DateUtilsTest.java index 7429b50b3..2727b1447 100644 --- a/core/src/androidTest/java/de/danoeh/antennapod/core/tests/util/DateUtilsTest.java +++ b/core/src/androidTest/java/de/danoeh/antennapod/core/tests/util/DateUtilsTest.java @@ -13,6 +13,7 @@ public class DateUtilsTest extends AndroidTestCase { public void testParseDateWithMicroseconds() throws Exception { GregorianCalendar exp = new GregorianCalendar(2015, 2, 28, 13, 31, 4); + exp.setTimeZone(TimeZone.getTimeZone("UTC")); Date expected = new Date(exp.getTimeInMillis() + 963); Date actual = DateUtils.parse("2015-03-28T13:31:04.963870"); assertEquals(expected, actual); @@ -20,6 +21,7 @@ public class DateUtilsTest extends AndroidTestCase { public void testParseDateWithCentiseconds() throws Exception { GregorianCalendar exp = new GregorianCalendar(2015, 2, 28, 13, 31, 4); + exp.setTimeZone(TimeZone.getTimeZone("UTC")); Date expected = new Date(exp.getTimeInMillis() + 960); Date actual = DateUtils.parse("2015-03-28T13:31:04.96"); assertEquals(expected, actual); @@ -27,6 +29,7 @@ public class DateUtilsTest extends AndroidTestCase { public void testParseDateWithDeciseconds() throws Exception { GregorianCalendar exp = new GregorianCalendar(2015, 2, 28, 13, 31, 4); + exp.setTimeZone(TimeZone.getTimeZone("UTC")); Date expected = new Date(exp.getTimeInMillis() + 900); Date actual = DateUtils.parse("2015-03-28T13:31:04.9"); assertEquals(expected.getTime()/1000, actual.getTime()/1000); @@ -82,4 +85,20 @@ public class DateUtilsTest extends AndroidTestCase { 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); + } + } diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/DateUtils.java b/core/src/main/java/de/danoeh/antennapod/core/util/DateUtils.java index 7b06128f9..c0233f684 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/DateUtils.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/DateUtils.java @@ -8,6 +8,7 @@ import java.text.ParsePosition; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; +import java.util.TimeZone; /** * Parses several date formats. @@ -17,50 +18,66 @@ public class DateUtils { private static final String TAG = "DateUtils"; private static final SimpleDateFormat parser = new SimpleDateFormat("", Locale.US); + private static final TimeZone defaultTimezone = TimeZone.getTimeZone("GMT"); + static { parser.setLenient(false); + parser.setTimeZone(defaultTimezone); } public static Date parse(final String input) { 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(".")) { int start = date.indexOf('.'); int current = start+1; while(current < date.length() && Character.isDigit(date.charAt(current))) { current++; } + // even more precise than microseconds: discard further decimal places if(current - start > 4) { if(current < date.length()-1) { date = date.substring(0, start + 4) + date.substring(current); } else { 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) { if(current < date.length()-1) { date = date.substring(0, current) + StringUtils.repeat("0", 4-(current-start)) + date.substring(current); } else { date = date.substring(0, current) + StringUtils.repeat("0", 4-(current-start)); } - } } String[] patterns = { "dd MMM yy HH:mm:ss Z", "dd MMM yy HH:mm 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", + "EEEE, dd MMM yyyy 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, 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", + "EEEE, dd MMM yyyy 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", "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", "yyyy-MM-dd'T'HH:mm:ssZ", "yyyy-MM-dd'T'HH:mm:ss'Z'", "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; } @@ -117,6 +134,7 @@ public class DateUtils { public static String formatRFC3339UTC(Date date) { SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US); + format.setTimeZone(defaultTimezone); return format.format(date); } } -- cgit v1.2.3