Skip to content

Commit 2eea59c

Browse files
authored
time: fix and cleanup int validity checks (#18885)
1 parent 8c8d21d commit 2eea59c

File tree

2 files changed

+41
-22
lines changed

2 files changed

+41
-22
lines changed

vlib/time/date_time_parser.v

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -31,23 +31,23 @@ fn (mut p DateTimeParser) peek(length int) !string {
3131
}
3232

3333
fn (mut p DateTimeParser) must_be_int(length int) !int {
34-
val := p.next(length) or { return err }
34+
val := p.next(length)!
35+
if !val.contains_only('0123456789') {
36+
return error('expected int, found: ${val}')
37+
}
3538
return val.int()
3639
}
3740

3841
fn (mut p DateTimeParser) must_be_int_with_minimum_length(min int, max int, allow_leading_zero bool) !int {
3942
mut length := max + 1 - min
4043
mut val := ''
4144
for _ in 0 .. length {
42-
maybe_int := p.peek(1) or { break }
43-
if maybe_int == '0' || maybe_int == '1' || maybe_int == '2' || maybe_int == '4'
44-
|| maybe_int == '5' || maybe_int == '6' || maybe_int == '7' || maybe_int == '8'
45-
|| maybe_int == '9' {
46-
p.next(1)!
47-
val += maybe_int
48-
} else {
45+
tok := p.peek(1) or { break }
46+
if !tok.contains_only('0123456789') {
4947
break
5048
}
49+
p.next(1)!
50+
val += tok
5151
}
5252
if val.len < min {
5353
return error('expected int with a minimum length of ${min}, found: ${val.len}')
@@ -59,22 +59,26 @@ fn (mut p DateTimeParser) must_be_int_with_minimum_length(min int, max int, allo
5959
}
6060

6161
fn (mut p DateTimeParser) must_be_single_int_with_optional_leading_zero() !int {
62-
mut val := p.next(1) or { return err }
62+
mut val := p.next(1)!
6363
if val == '0' {
64-
val += p.next(1) or { '' }
64+
next := p.next(1) or { '' }
65+
if !next.contains_only('0123456789') {
66+
return error('expected int, found: ${next}')
67+
}
68+
val += next
6569
}
6670
return val.int()
6771
}
6872

6973
fn (mut p DateTimeParser) must_be_string(must string) ! {
70-
val := p.next(must.len) or { return err }
74+
val := p.next(must.len)!
7175
if val != must {
7276
return error('invalid string: "${val}"!="${must}" at: ${p.current_pos_datetime}')
7377
}
7478
}
7579

7680
fn (mut p DateTimeParser) must_be_string_one_of(oneof []string) !string {
77-
for _, must in oneof {
81+
for must in oneof {
7882
val := p.peek(must.len) or { continue }
7983
if val == must {
8084
return must
@@ -84,7 +88,7 @@ fn (mut p DateTimeParser) must_be_string_one_of(oneof []string) !string {
8488
}
8589

8690
fn (mut p DateTimeParser) must_be_valid_month() !int {
87-
for _, v in long_months {
91+
for v in long_months {
8892
if p.current_pos_datetime + v.len < p.datetime.len {
8993
month_name := p.datetime[p.current_pos_datetime..p.current_pos_datetime + v.len]
9094
if v == month_name {
@@ -97,8 +101,8 @@ fn (mut p DateTimeParser) must_be_valid_month() !int {
97101
}
98102

99103
fn (mut p DateTimeParser) must_be_valid_week_day(letters int) !string {
100-
val := p.next(letters) or { return err }
101-
for _, v in long_days {
104+
val := p.next(letters)!
105+
for v in long_days {
102106
if v[0..letters] == val {
103107
return v
104108
}
@@ -151,7 +155,7 @@ fn (mut p DateTimeParser) parse() !Time {
151155
tokens := extract_tokens(p.format) or {
152156
return error_invalid_time(0, 'malformed format string: ${err}')
153157
}
154-
for _, token in tokens {
158+
for token in tokens {
155159
match token {
156160
'YYYY' {
157161
year_ = p.must_be_int(4) or {

vlib/time/parse.c.v

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
// that can be found in the LICENSE file.
44
module time
55

6+
import strconv
7+
68
// parse_rfc3339 returns time from a date string in RFC 3339 datetime format.
79
// See also https://ijmacd.github.io/rfc3339-iso8601/ for a visual reference of
810
// the differences between ISO-8601 and RFC 3339.
@@ -79,12 +81,25 @@ pub fn parse(s string) !Time {
7981
minute_ := hms[1]
8082
second_ := hms[2]
8183
//
82-
iyear := ymd[0].int()
83-
imonth := ymd[1].int()
84-
iday := ymd[2].int()
85-
ihour := hour_.int()
86-
iminute := minute_.int()
87-
isecond := second_.int()
84+
iyear := strconv.atoi(ymd[0]) or {
85+
return error_invalid_time(0, 'invalid year format: ${ymd[0]}')
86+
}
87+
imonth := strconv.atoi(ymd[1]) or {
88+
return error_invalid_time(0, 'invalid month format: ${ymd[1]}')
89+
}
90+
iday := strconv.atoi(ymd[2]) or {
91+
return error_invalid_time(0, 'invalid day format: ${ymd[2]}')
92+
}
93+
ihour := strconv.atoi(hour_) or {
94+
return error_invalid_time(0, 'invalid hour format: ${hour_}')
95+
}
96+
iminute := strconv.atoi(minute_) or {
97+
return error_invalid_time(0, 'invalid minute format: ${minute_}')
98+
}
99+
isecond := strconv.atoi(second_) or {
100+
return error_invalid_time(0, 'invalid second format: ${second_}')
101+
}
102+
88103
// eprintln('>> iyear: $iyear | imonth: $imonth | iday: $iday | ihour: $ihour | iminute: $iminute | isecond: $isecond')
89104
if iyear > 9999 || iyear < -9999 {
90105
return error_invalid_time(3, 'year must be between -10000 and 10000')

0 commit comments

Comments
 (0)