Revamp the way rss/atom/json dates are parsed and fix date tests

This commit is contained in:
Shinokuni 2019-10-10 14:45:01 +02:00
parent 7aa0f94011
commit 272e867c8d
8 changed files with 101 additions and 95 deletions

View File

@ -120,7 +120,7 @@ public class ItemActivity extends AppCompatActivity {
this.itemWithFeed = itemWithFeed; this.itemWithFeed = itemWithFeed;
Item item = itemWithFeed.getItem(); Item item = itemWithFeed.getItem();
date.setText(DateUtils.formatedDateTimeByLocal(item.getPubDate())); date.setText(DateUtils.formattedDateTimeByLocal(item.getPubDate()));
if (item.getImageLink() == null) if (item.getImageLink() == null)
toolbar.setTitle(itemWithFeed.getFeedName()); toolbar.setTitle(itemWithFeed.getFeedName());

View File

@ -288,7 +288,7 @@ public class MainItemListAdapter extends PagedListAdapter<ItemWithFeed, MainItem
Item item = itemWithFeed.getItem(); Item item = itemWithFeed.getItem();
binding.itemTitle.setText(item.getTitle()); binding.itemTitle.setText(item.getTitle());
binding.itemDate.setText(DateUtils.formatedDateByLocal(item.getPubDate())); binding.itemDate.setText(DateUtils.formattedDateByLocal(item.getPubDate()));
binding.itemFeedName.setText(itemWithFeed.getFeedName()); binding.itemFeedName.setText(itemWithFeed.getFeedName());
if (item.getCleanDescription() != null) { if (item.getCleanDescription() != null) {

View File

@ -23,12 +23,12 @@ import com.readrops.readropslibrary.localfeed.atom.ATOMFeed;
import com.readrops.readropslibrary.localfeed.json.JSONFeed; import com.readrops.readropslibrary.localfeed.json.JSONFeed;
import com.readrops.readropslibrary.localfeed.rss.RSSFeed; import com.readrops.readropslibrary.localfeed.rss.RSSFeed;
import com.readrops.readropslibrary.utils.LibUtils; import com.readrops.readropslibrary.utils.LibUtils;
import com.readrops.readropslibrary.utils.ParseException;
import com.readrops.readropslibrary.utils.UnknownFormatException; import com.readrops.readropslibrary.utils.UnknownFormatException;
import org.jsoup.Jsoup; import org.jsoup.Jsoup;
import java.io.IOException; import java.io.IOException;
import java.text.ParseException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;

View File

@ -1,36 +1,51 @@
package com.readrops.app.utils; package com.readrops.app.utils;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Locale;
import org.joda.time.LocalDateTime; import org.joda.time.LocalDateTime;
import org.joda.time.format.DateTimeFormat; import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.DateTimeFormatterBuilder;
import java.util.Locale;
public final class DateUtils { public final class DateUtils {
public static final String RSS_ALTERNATIVE_DATE_FORMAT_REGEX = "^[a-zA-Z]{3}, [0-9]{2} [a-zA-Z]{3} [0-9]{4} [0-9]{2}:[0-9]{2}:[0-9]{2} Z$"; /**
* Base of common RSS 2 date formats.
* Examples :
* Fri, 04 Jan 2019 22:21:46 GMT
* Fri, 04 Jan 2019 22:21:46 +0000
*/
private static final String RSS_2_BASE_PATTERN = "EEE, dd MMM yyyy HH:mm:ss ";
public static final String RSS_2_DATE_FORMAT = "EEE, dd MMM yyyy HH:mm:ss Z"; private static final String GMT_PATTERN = "ZZZ";
public static final String RSS_2_DATE_FORMAT_2 = "EEE, dd MMM yyyy HH:mm:ss z";
public static final String RSS_2_DATE_FORMAT_3 = "EEE, dd MMM yyyy HH:mm:ss 'Z'";
public static final String ATOM_JSON_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ssX"; private static final String OFFSET_PATTERN = "Z";
public static LocalDateTime stringToDateTime(String value, String pattern) throws ParseException { /**
DateFormat formatter = new SimpleDateFormat(pattern, Locale.ENGLISH); * Date pattern for format : 2019-01-04T22:21:46+00:00
return new LocalDateTime(formatter.parse(value)); */
private static final String ATOM_JSON_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss";
public static LocalDateTime stringToLocalDateTime(String value) {
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.appendOptional(DateTimeFormat.forPattern(RSS_2_BASE_PATTERN).getParser())
.appendOptional(DateTimeFormat.forPattern(ATOM_JSON_DATE_FORMAT).getParser())
.appendOptional(DateTimeFormat.forPattern(GMT_PATTERN).getParser())
.appendOptional(DateTimeFormat.forPattern(OFFSET_PATTERN).getParser())
.toFormatter()
.withLocale(Locale.ENGLISH)
.withOffsetParsed();
return formatter.parseLocalDateTime(value);
} }
public static String formatedDateByLocal(LocalDateTime dateTime) { public static String formattedDateByLocal(LocalDateTime dateTime) {
DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.getDefault()); return DateTimeFormat.mediumDate()
.withLocale(Locale.getDefault())
return df.format(dateTime.toDate()); .print(dateTime);
} }
public static String formatedDateTimeByLocal(LocalDateTime dateTime) { public static String formattedDateTimeByLocal(LocalDateTime dateTime) {
return DateTimeFormat.forPattern("dd MMM yyyy · HH:mm") return DateTimeFormat.forPattern("dd MMM yyyy · HH:mm")
.withLocale(Locale.getDefault()) .withLocale(Locale.getDefault())
.print(dateTime); .print(dateTime);

View File

@ -9,15 +9,14 @@ import com.readrops.readropslibrary.localfeed.rss.RSSItem;
import com.readrops.readropslibrary.localfeed.rss.RSSMediaContent; import com.readrops.readropslibrary.localfeed.rss.RSSMediaContent;
import com.readrops.readropslibrary.services.freshrss.json.FreshRSSItem; import com.readrops.readropslibrary.services.freshrss.json.FreshRSSItem;
import com.readrops.readropslibrary.services.nextcloudnews.json.NextNewsItem; import com.readrops.readropslibrary.services.nextcloudnews.json.NextNewsItem;
import com.readrops.readropslibrary.utils.ParseException;
import org.joda.time.DateTimeZone; import org.joda.time.DateTimeZone;
import org.joda.time.LocalDateTime; import org.joda.time.LocalDateTime;
import org.jsoup.Jsoup; import org.jsoup.Jsoup;
import java.text.ParseException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.regex.Pattern;
public final class ItemMatcher { public final class ItemMatcher {
@ -75,31 +74,16 @@ public final class ItemMatcher {
newItem.setGuid(item.getGuid()); newItem.setGuid(item.getGuid());
newItem.setTitle(Jsoup.parse(item.getTitle()).text().trim()); newItem.setTitle(Jsoup.parse(item.getTitle()).text().trim());
// I wish I hadn't done that...
if (Pattern.compile(DateUtils.RSS_ALTERNATIVE_DATE_FORMAT_REGEX).matcher(item.getDate()).matches())
newItem.setPubDate(DateUtils.stringToDateTime(item.getDate(), DateUtils.RSS_2_DATE_FORMAT_3));
else {
try { try {
newItem.setPubDate(DateUtils.stringToDateTime(item.getDate(), DateUtils.RSS_2_DATE_FORMAT_2)); newItem.setPubDate(DateUtils.stringToLocalDateTime(item.getDate()));
} catch (ParseException e) { } catch (Exception e) {
e.printStackTrace(); throw new ParseException();
} finally {
if (newItem.getPubDate() == null) {
try {
newItem.setPubDate(DateUtils.stringToDateTime(item.getDate(), DateUtils.RSS_2_DATE_FORMAT));
} catch (ParseException e) {
e.printStackTrace();
} finally {
newItem.setPubDate(DateUtils.stringToDateTime(item.getDate(), DateUtils.ATOM_JSON_DATE_FORMAT));
}
}
}
} }
newItem.setLink(item.getLink()); newItem.setLink(item.getLink());
newItem.setFeedId(feed.getId()); newItem.setFeedId(feed.getId());
if (item.getMediaContents() != null && item.getMediaContents().size() > 0) { if (item.getMediaContents() != null && !item.getMediaContents().isEmpty()) {
for (RSSMediaContent mediaContent : item.getMediaContents()) { for (RSSMediaContent mediaContent : item.getMediaContents()) {
if (mediaContent.getMedium() != null && Utils.isTypeImage(mediaContent.getMedium())) { if (mediaContent.getMedium() != null && Utils.isTypeImage(mediaContent.getMedium())) {
newItem.setImageLink(mediaContent.getUrl()); newItem.setImageLink(mediaContent.getUrl());
@ -135,7 +119,11 @@ public final class ItemMatcher {
dbItem.setGuid(item.getId()); dbItem.setGuid(item.getId());
dbItem.setTitle(Jsoup.parse(item.getTitle()).text().trim()); dbItem.setTitle(Jsoup.parse(item.getTitle()).text().trim());
dbItem.setPubDate(DateUtils.stringToDateTime(item.getUpdated(), DateUtils.ATOM_JSON_DATE_FORMAT)); try {
dbItem.setPubDate(DateUtils.stringToLocalDateTime(item.getUpdated()));
} catch (Exception e) {
throw new ParseException();
}
dbItem.setLink(item.getUrl()); dbItem.setLink(item.getUrl());
dbItem.setFeedId(feed.getId()); dbItem.setFeedId(feed.getId());
@ -160,7 +148,11 @@ public final class ItemMatcher {
dbItem.setGuid(item.getId()); dbItem.setGuid(item.getId());
dbItem.setTitle(Jsoup.parse(item.getTitle()).text().trim()); dbItem.setTitle(Jsoup.parse(item.getTitle()).text().trim());
dbItem.setPubDate(DateUtils.stringToDateTime(item.getPubDate(), DateUtils.ATOM_JSON_DATE_FORMAT)); try {
dbItem.setPubDate(DateUtils.stringToLocalDateTime(item.getPubDate()));
} catch (Exception e) {
throw new ParseException();
}
dbItem.setLink(item.getUrl()); dbItem.setLink(item.getUrl());

View File

@ -0,0 +1,44 @@
package com.readrops.app;
import com.readrops.app.utils.DateUtils;
import org.joda.time.LocalDateTime;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class DateUtilsTest {
@Test
public void rssDateTest() {
LocalDateTime dateTime = new LocalDateTime(2019, 1, 4, 22, 21, 46);
assertEquals(0, dateTime.compareTo(DateUtils.stringToLocalDateTime("Fri, 04 Jan 2019 22:21:46 GMT")));
}
@Test
public void rssDate2Test() {
LocalDateTime dateTime = new LocalDateTime(2019, 1, 4, 22, 21, 46);
assertEquals(0, dateTime.compareTo(DateUtils.stringToLocalDateTime("Fri, 04 Jan 2019 22:21:46 +0000")));
}
@Test
public void atomJsonDateTest() {
LocalDateTime dateTime = new LocalDateTime(2019, 1, 4, 22, 21, 46);
assertEquals(0, dateTime.compareTo(DateUtils.stringToLocalDateTime("2019-01-04T22:21:46+00:00")));
}
@Test
public void atomJsonDate2Test() {
LocalDateTime dateTime = new LocalDateTime(2019, 1, 4, 22, 21, 46);
assertEquals(0, dateTime.compareTo(DateUtils.stringToLocalDateTime("2019-01-04T22:21:46-0000")));
}
}

View File

@ -1,50 +0,0 @@
package com.readrops.app;
import com.readrops.app.utils.DateUtils;
import org.joda.time.DateTimeZone;
import org.joda.time.LocalDateTime;
import org.junit.Test;
import java.text.ParseException;
import static org.junit.Assert.assertEquals;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class ExampleUnitTest {
@Test
public void rssDateTest() {
try {
LocalDateTime dateTime = new LocalDateTime(2019, 1, 4, 22, 21, 46);
assertEquals(0, dateTime.compareTo(DateUtils.stringToDateTime("Fri, 04 Jan 2019 22:21:46 +0000", DateUtils.RSS_2_DATE_FORMAT)));
assertEquals(0, dateTime.compareTo(DateUtils.stringToDateTime("Fri, 04 Jan 2019 22:21:46 GMT", DateUtils.RSS_2_DATE_FORMAT_2)));
} catch (ParseException e) {
e.printStackTrace();
}
}
@Test
public void atomJsonDateTest() {
try {
LocalDateTime dateTime = new LocalDateTime(2019, 1, 4, 22, 21, 46);
assertEquals(0, dateTime.compareTo(DateUtils.stringToDateTime("2019-01-04T22:21:46+00:00", DateUtils.ATOM_JSON_DATE_FORMAT)));
assertEquals(0, dateTime.compareTo(DateUtils.stringToDateTime("2019-01-04T22:21:46-0000", DateUtils.ATOM_JSON_DATE_FORMAT)));
} catch (ParseException e) {
e.printStackTrace();
}
}
@Test
public void timeStamptoDateTest() {
LocalDateTime localDateTime = new LocalDateTime(1367270544 * 1000L, DateTimeZone.getDefault());
assertEquals(0, localDateTime.compareTo(new LocalDateTime(2013, 4, 29, 21, 22, 24)));
}
}

View File

@ -0,0 +1,5 @@
package com.readrops.readropslibrary.utils;
public class ParseException extends Exception {
}