/
rfc_2822.cr
130 lines (112 loc) · 2.4 KB
/
rfc_2822.cr
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
# The [RFC 2822](https://tools.ietf.org/html/rfc2822) datetime format.
#
# This is also compatible to [RFC 882](https://tools.ietf.org/html/rfc882) and [RFC 1123](https://tools.ietf.org/html/rfc1123#page-55).
struct Time::Format
module RFC_2822
# Parses a string into a `Time`.
def self.parse(string, kind = Time::Location::UTC) : Time
parser = Parser.new(string)
parser.rfc_2822
parser.time(kind)
end
# Formats a `Time` into the given *io*.
def self.format(time : Time, io : IO)
formatter = Formatter.new(time, io)
formatter.rfc_2822
io
end
# Formats a `Time` into a `String`.
def self.format(time : Time)
String.build do |io|
format(time, io)
end
end
end
module Pattern
def rfc_2822(time_zone_gmt = false, two_digit_day = false)
cfws?
short_day_name_with_comma?
if two_digit_day
day_of_month_zero_padded
else
day_of_month
end
cfws
short_month_name
cfws
full_or_short_year
folding_white_space
cfws?
hour_24_zero_padded
cfws?
char ':'
cfws?
minute
cfws?
seconds_with_colon?
folding_white_space
if time_zone_gmt
time_zone_gmt_or_rfc2822
else
time_zone_rfc2822
end
cfws?
end
end
struct Parser
def short_day_name_with_comma?
return unless current_char.ascii_letter?
short_day_name
cfws?
char ','
cfws
end
def seconds_with_colon?
if current_char == ':'
next_char
cfws?
second
end
end
# comment or folding white space
def cfws?
in_comment = false
seen_whitespace = false
loop do
case char = current_char
when .ascii_whitespace?
seen_whitespace = true
when '('
in_comment = true
when ')'
in_comment = false
else
break unless in_comment
end
break unless @reader.has_next?
next_char
end
seen_whitespace
end
def cfws
cfws? || raise "Invalid format"
end
def folding_white_space
skip_space
end
end
struct Formatter
def seconds_with_colon?
char ':'
second
end
def cfws?
end
def cfws
folding_white_space
end
def folding_white_space
io << ' '
end
end
end