mirror of https://github.com/readrops/Readrops.git
Revamp the way rss/atom/json dates are parsed and fix date tests
This commit is contained in:
parent
7aa0f94011
commit
272e867c8d
|
@ -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());
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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...
|
try {
|
||||||
if (Pattern.compile(DateUtils.RSS_ALTERNATIVE_DATE_FORMAT_REGEX).matcher(item.getDate()).matches())
|
newItem.setPubDate(DateUtils.stringToLocalDateTime(item.getDate()));
|
||||||
newItem.setPubDate(DateUtils.stringToDateTime(item.getDate(), DateUtils.RSS_2_DATE_FORMAT_3));
|
} catch (Exception e) {
|
||||||
else {
|
throw new ParseException();
|
||||||
try {
|
|
||||||
newItem.setPubDate(DateUtils.stringToDateTime(item.getDate(), DateUtils.RSS_2_DATE_FORMAT_2));
|
|
||||||
} catch (ParseException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} 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());
|
||||||
|
|
||||||
|
|
|
@ -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")));
|
||||||
|
}
|
||||||
|
}
|
|
@ -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)));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
package com.readrops.readropslibrary.utils;
|
||||||
|
|
||||||
|
public class ParseException extends Exception {
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue