This repository has been archived by the owner on Jan 11, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 90
/
Rfc822.vala
144 lines (135 loc) · 3.37 KB
/
Rfc822.vala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
namespace FeedReader.Rfc822 {
/**
* Parse a date string in RFC 822 format
* Note that we don't use Time.strptime because it uses the current locale
* to parse month names, but RFC 822 specifically requires months to be
* written in English.
* See: https://www.w3.org/Protocols/rfc822/#z28
* And: https://groups.yahoo.com/neo/groups/rss-public/conversations/topics/536
* */
public static DateTime? parseDate(string? str)
{
if (str == null)
return null;
Regex re;
try {
re = new Regex("""
# We don't care about the day of the week
\s*(?:(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun),\s*)?
(?<day>\d{1,2})\s+
(?<month>Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s+
# The standard specifies 2-digit years but 4 digit years are
# recommended now.
# This pattern will also accept 3-digit years, so we'll have to
# check for that separately
(?<year>\d{2,4})\s+
(?<hour>\d{2})
:(?<minute>\d{2})
(?::(?<second>\d{2}))?\s+
(?<zone>UT|GMT|EST|EDT|MST|MDT|PST|PDT|[A-Z]|(?:[+-]\d{4}))
""",
RegexCompileFlags.CASELESS | RegexCompileFlags.EXTENDED,
RegexMatchFlags.ANCHORED);
} catch (RegexError e) {
stderr.printf("RFC822 regex failed to parse: %s\n", e.message);
assert(false);
return null;
}
MatchInfo info;
if (!re.match(str, 0, out info))
return null;
var dayStr = info.fetch_named("day");
var day = int.parse(dayStr);
var monthStr = info.fetch_named("month").ascii_down();
int month;
switch(monthStr) {
case "jan":
month = 1;
break;
case "feb":
month = 2;
break;
case "mar":
month = 3;
break;
case "apr":
month = 4;
break;
case "may":
month = 5;
break;
case "jun":
month = 6;
break;
case "jul":
month = 7;
break;
case "aug":
month = 8;
break;
case "sep":
month = 9;
break;
case "oct":
month = 10;
break;
case "nov":
month = 11;
break;
case "dec":
month = 12;
break;
default:
// The regex should make this impossible
assert(false);
return null;
}
var yearStr = info.fetch_named("year");
var year = int.parse(yearStr);
// Two-digit years from 00 to 49 should be interpreted as 2000 to 2049
if (year >= 0 && year <= 49)
year += 2000;
// Two-digit years from 50 to 99 should be interpreted as 1950 to 1999
else if (year >= 50 && year < 100)
year += 1900;
var hourStr = info.fetch_named("hour");
var hour = int.parse(hourStr);
var minuteStr = info.fetch_named("minute");
var minute = int.parse(minuteStr);
var secondStr = info.fetch_named("second");
var second = secondStr == null || secondStr == "" ? 0 : int.parse(secondStr);
var zoneStr = info.fetch_named("zone");
TimeZone zone;
switch(zoneStr.ascii_up()) {
// Note sure if new TimeZone(zoneStr) would always work for these,
// so specifically handle the cases the spec requires
case "EDT":
zone = new TimeZone("-04");
break;
case "CDT":
case "EST":
zone = new TimeZone("-05");
break;
case "CST":
case "MDT":
zone = new TimeZone("-06");
break;
case "MST":
case "PDT":
zone = new TimeZone("-07");
break;
case "PST":
zone = new TimeZone("-08");
break;
case "GMT":
case "UT":
case "Z":
zone = new TimeZone.utc();
break;
default:
zone = new TimeZone(zoneStr);
break;
}
return new DateTime(zone, year, month, day, hour, minute, second);
}
}