Skip to content

Commit 8902db4

Browse files
Bruno-VdrDelta456
andauthored
time: parse_http_header_string (#26636)
* Implemented rfc2616 parse_http_header_string. * Corrected typos. * Update vlib/time/parse_test.v * Fixed YY date issue. If parsed year exceed current year, it's considered to be from the previous century. --------- Co-authored-by: Swastik Baranwal <swstkbaranwal@gmail.com>
1 parent 6a63a27 commit 8902db4

2 files changed

Lines changed: 96 additions & 0 deletions

File tree

vlib/time/parse.c.v

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,67 @@ fn check_and_extract_date(s string) !(int, int, int) {
126126
return year, month, day
127127
}
128128

129+
// Convert header string formatted as RFC 2616 to Time.
130+
pub fn parse_http_header_string(s string) !Time {
131+
return parse_rfc2616(s)
132+
}
133+
134+
// parse_rfc2616 returns the time from a date string in RFC 3339 datetime format.
135+
// Wed, 06 Nov 2024 08:49:37 GMT ; RFC 822, updated by RFC 1123
136+
// Wednesday, 06-Nov-24 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036
137+
// Wed Nov 6 08:49:37 2024 ; ANSI C's asctime() format
138+
pub fn parse_rfc2616(s string) !Time {
139+
if s == '' {
140+
return error_invalid_time(0, 'datetime string is empty')
141+
}
142+
143+
// Remove or Replace unwanted tokens.
144+
rmv := ['GMT', '', 'Monday', '', 'Tuesday', '', 'Wednesday', '', 'Thursday', '', 'Friday',
145+
'', 'Saturday', '', 'Sunday', '', 'Mon', '', 'Tue', '', 'Wed', '', 'Thu', '', 'Fri', '',
146+
'Sat', '', 'Sun', '', '-', ' ', ',', '']
147+
148+
mut f := s.replace_each(rmv)
149+
f = remove_consecutive_spaces(f)
150+
151+
if r := parse_format(f, 'DD MMM YYYY HH:mm:ss') {
152+
return r
153+
}
154+
155+
// parse_format maps YY to this century (94 maps to 2094, 20 to 2020).
156+
// if parsed year > current year, the date belongs to previous century.
157+
if r := parse_format(f, 'DD MMM YY HH:mm:ss') {
158+
return if r.year > now().year {
159+
r.add_days(-(days_per_100_years + 1))
160+
} else {
161+
r
162+
}
163+
}
164+
if r := parse_format(f, 'MMM D HH:mm:ss YYYY') {
165+
return r
166+
}
167+
return error('unable to parse date: "${f}"')
168+
}
169+
170+
// Remove consecutive spaces, only keep one.
171+
fn remove_consecutive_spaces(s string) string {
172+
mut t := s.trim_space()
173+
mut r := ''
174+
mut sp := false
175+
176+
for c in t {
177+
if c == u8(` `) {
178+
if !sp {
179+
r += ' '
180+
sp = true
181+
}
182+
} else {
183+
r += c.ascii_str()
184+
sp = false
185+
}
186+
}
187+
return r
188+
}
189+
129190
// parse_rfc3339 returns the time from a date string in RFC 3339 datetime format.
130191
// See also https://ijmacd.github.io/rfc3339-iso8601/ for a visual reference of
131192
// the differences between ISO-8601 and RFC 3339.

vlib/time/parse_test.v

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,41 @@ fn test_parse_rfc3339_offset() {
243243
}
244244
}
245245

246+
fn test_parse_rfc2616() {
247+
mut r := time.parse_rfc2616('Wed, 06 Nov 2024 08:49:37 GMT')!
248+
assert r.unix() == 1730882977
249+
250+
r = time.parse_rfc2616('Wednesday, 06-Nov-24 08:49:37 GMT')!
251+
assert r.unix() == 1730882977
252+
253+
r = time.parse_rfc2616('Wed Nov 6 08:49:37 2024')!
254+
assert r.unix() == 1730882977
255+
256+
r = time.parse_rfc2616('Thu, 19 Feb 2026 11:07:09 GMT')!
257+
assert r.unix() == 1771499229
258+
259+
r = time.parse_rfc2616('Tuesday, 19-Feb-26 11:07:09 GMT')!
260+
assert r.unix() == 1771499229
261+
262+
r = time.parse_rfc2616('Thu Feb 19 11:07:09 2026')!
263+
assert r.unix() == 1771499229
264+
265+
// This should map to 1994, not 2094.
266+
r = time.parse_rfc2616('Tuesday, 06-Nov-94 11:07:09 GMT')!
267+
assert r.unix() == 784120029
268+
269+
// This should map to 2020, not 1920.
270+
r = time.parse_rfc2616('Friday, 06-Nov-20 08:49:37 GMT')!
271+
assert r.unix() == 1604652577
272+
}
273+
274+
fn test_parse_http_header_string() {
275+
t := time.now()
276+
header := t.http_header_string()
277+
back_time := time.parse_http_header_string(header)!
278+
assert t.str() == back_time.str()
279+
}
280+
246281
fn test_ad_second_to_parse_result_in_2001() {
247282
now_tm := time.parse('2001-01-01 04:00:00')!
248283
future_tm := now_tm.add_seconds(60)

0 commit comments

Comments
 (0)