Skip to content

Commit e0ab2a8

Browse files
committed
add: format american style datetime
1 parent 849313c commit e0ab2a8

File tree

5 files changed

+125
-46
lines changed

5 files changed

+125
-46
lines changed

lib/domain/dart_rss.dart

Lines changed: 71 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,25 @@ import 'package:dart_rss/domain/atom_feed.dart';
44
import 'package:dart_rss/domain/rss1_feed.dart';
55
import 'package:dart_rss/domain/rss_feed.dart';
66
import 'package:xml/xml.dart' as xml;
7+
import 'package:intl/intl.dart';
78

89
extension SafeParseDateTime on DateTime {
910
static DateTime safeParse(String str) {
11+
const dateFormatPatterns = [
12+
'EEE, d MMM yyyy HH:mm:ss Z',
13+
];
14+
1015
try {
1116
return DateTime.parse(str);
1217
} catch (_) {
13-
return null;
18+
for (final pattern in dateFormatPatterns) {
19+
try {
20+
final format = DateFormat(pattern);
21+
return format.parse(str);
22+
} catch (_) {}
23+
}
1424
}
25+
return null;
1526
}
1627
}
1728

@@ -40,56 +51,15 @@ class WebFeed {
4051
switch (rssVersion) {
4152
case RssVersion.RSS1:
4253
final rss1Feed = Rss1Feed.parse(xmlString);
43-
return WebFeed(
44-
title: rss1Feed.title,
45-
description: rss1Feed.description,
46-
links: [rss1Feed.link],
47-
items: rss1Feed.items
48-
.map(
49-
(item) => WebFeedItem(
50-
title: item.title,
51-
body: item.description ?? item.dc?.description,
52-
updated: SafeParseDateTime.safeParse(item.dc?.date),
53-
links: [item.link],
54-
),
55-
)
56-
.toList(),
57-
);
54+
return WebFeed.fromRss1(rss1Feed);
5855
break;
5956
case RssVersion.RSS2:
6057
final rss2Feed = RssFeed.parse(xmlString);
61-
return WebFeed(
62-
title: rss2Feed.title,
63-
description: rss2Feed.description,
64-
links: [rss2Feed.link],
65-
items: rss2Feed.items
66-
.map(
67-
(item) => WebFeedItem(
68-
title: item.title,
69-
body: item.description ?? item.dc?.description,
70-
updated: SafeParseDateTime.safeParse(item.dc?.date),
71-
),
72-
)
73-
.toList(),
74-
);
58+
return WebFeed.fromRss2(rss2Feed);
7559
break;
7660
case RssVersion.Atom:
7761
final atomFeed = AtomFeed.parse(xmlString);
78-
return WebFeed(
79-
title: atomFeed.title,
80-
description: atomFeed.subtitle,
81-
links: atomFeed.links.map((atomLink) => atomLink.href).toList(),
82-
items: atomFeed.items
83-
.map(
84-
(item) => WebFeedItem(
85-
title: item.title,
86-
body: item.summary,
87-
updated: SafeParseDateTime.safeParse(item.updated),
88-
links: item.links.map((atomLink) => atomLink.href).toList(),
89-
),
90-
)
91-
.toList(),
92-
);
62+
return WebFeed.fromAtom(atomFeed);
9363
break;
9464
case RssVersion.Unknown:
9565
throw Error.safeToString(
@@ -100,6 +70,62 @@ class WebFeed {
10070
}
10171
}
10272

73+
static WebFeed fromRss1(Rss1Feed rss1feed) {
74+
return WebFeed(
75+
title: rss1feed.title ?? rss1feed.dc.title ?? '',
76+
description: rss1feed.description ?? rss1feed.dc?.description ?? '',
77+
links: [rss1feed.link],
78+
items: rss1feed.items
79+
.map(
80+
(item) => WebFeedItem(
81+
title: item.title ?? item.dc?.title ?? '',
82+
body: item.description ?? item.dc?.description ?? '',
83+
updated: SafeParseDateTime.safeParse(item.dc?.date),
84+
links: [item.link],
85+
),
86+
)
87+
.toList(),
88+
);
89+
}
90+
91+
static WebFeed fromRss2(RssFeed rssFeed) {
92+
return WebFeed(
93+
title: rssFeed.title ?? rssFeed.dc.title ?? '',
94+
description: rssFeed.description ?? rssFeed.dc.description ?? '',
95+
links: [rssFeed.link],
96+
items: rssFeed.items
97+
.map(
98+
(item) => WebFeedItem(
99+
title: item.title ?? item.dc.title ?? '',
100+
body: item.description ?? item.dc.description ?? '',
101+
updated: SafeParseDateTime.safeParse(item.pubDate) ??
102+
SafeParseDateTime.safeParse(item.dc.date),
103+
links: [item.link],
104+
),
105+
)
106+
.toList(),
107+
);
108+
}
109+
110+
static WebFeed fromAtom(AtomFeed atomFeed) {
111+
return WebFeed(
112+
title: atomFeed.title,
113+
description: atomFeed.subtitle,
114+
links: atomFeed.links.map((atomLink) => atomLink.href).toList(),
115+
items: atomFeed.items
116+
.map(
117+
(item) => WebFeedItem(
118+
title: item.title,
119+
body: item.summary ?? item.content,
120+
updated: SafeParseDateTime.safeParse(item.updated) ??
121+
SafeParseDateTime.safeParse(item.published),
122+
links: item.links.map((atomLink) => atomLink.href).toList(),
123+
),
124+
)
125+
.toList(),
126+
);
127+
}
128+
103129
static Future<WebFeed> fromUrl(String url) async {
104130
final response = await http.get(url);
105131
return fromXmlString(response.body);

pubspec.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,7 @@ dependencies:
88
xml: ^3.0.0
99
http: ^0.11.0
1010
meta: ^1.0.0
11+
intl: any
12+
1113
dev_dependencies:
1214
test: ^1.0.0

test/real_rss_test.dart

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import 'package:dart_rss/dart_rss.dart';
2+
import 'package:test/test.dart';
3+
4+
void main() {
5+
group('Can this library use for real rss xml?', () {
6+
const testFeeds = {
7+
'pub.dev feed': 'https://pub.dev/feed.atom',
8+
'Flutter Weekly':
9+
'https://us17.campaign-archive.com/feed?u=c8d8d18b6e2c6316ddc1d48a0&id=47548a283b',
10+
'jQuery blog': 'http://blog.jquery.com/feed/', // <- not use ISO8601
11+
'hatena sample': 'https://b.hatena.ne.jp/sample/bookmark.rss', // <- RSS1
12+
};
13+
14+
for (final title in testFeeds.keys) {
15+
final url = testFeeds[title];
16+
test(title, () async {
17+
// given
18+
final feed = await WebFeed.fromUrl(url);
19+
20+
// then
21+
expect(feed.title.isNotEmpty, true);
22+
expect(feed.items.first.updated is DateTime, true);
23+
expect(feed.items.first.links.isNotEmpty, true);
24+
});
25+
}
26+
});
27+
}

test/safe_parse_date_time_test.dart

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import 'package:dart_rss/dart_rss.dart';
2+
import 'package:test/test.dart';
3+
4+
void main() {
5+
group('about SafeParseDateTime, ', () {
6+
test('it can parse ISO-8601', () {
7+
final date = SafeParseDateTime.safeParse('2018-04-06T13:02:47Z');
8+
9+
expect(date.year, 2018);
10+
expect(date.month, 4);
11+
expect(date.day, 6);
12+
});
13+
14+
test('it can parse American-English-Format', () {
15+
final date =
16+
SafeParseDateTime.safeParse('Tue, 02 Jul 2019 16:47:24 +0000');
17+
18+
expect(date.year, 2019);
19+
expect(date.month, 7);
20+
expect(date.day, 2);
21+
});
22+
});
23+
}

test/webfeed_test.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,8 @@ void main() {
9191
rss2Feed.items.first.body,
9292
'Lorem ipsum dolor sit amet, consectetur adipiscing elit',
9393
);
94-
expect(rss2Feed.items.first.updated, null);
94+
expect(rss2Feed.items.first.updated,
95+
DateTime.parse('2018-03-26 14:00:00.000'));
9596
});
9697
});
9798
}

0 commit comments

Comments
 (0)