Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

time: d,c,dd,ddd,dddd pattern support for parse_format() #22003

Merged
merged 7 commits into from
Aug 9, 2024
60 changes: 55 additions & 5 deletions vlib/time/date_time_parser.v
Original file line number Diff line number Diff line change
Expand Up @@ -101,14 +101,43 @@ fn (mut p DateTimeParser) must_be_valid_three_letter_month() !int {
return error_invalid_time(0, 'invalid three letter month, at: ${p.current_pos_datetime}')
}

fn (mut p DateTimeParser) must_be_valid_week_day(letters int) !string {
val := p.next(letters)!
fn (mut p DateTimeParser) must_be_valid_week_day() !string {
for v in long_days {
if v[0..letters] == val {
return v
if p.current_pos_datetime + v.len < p.datetime.len {
weekday := p.datetime[p.current_pos_datetime..p.current_pos_datetime + v.len]
if v == weekday {
p.current_pos_datetime += v.len
return weekday
}
}
}
return error_invalid_time(0, 'invalid month name, at: ${p.current_pos_datetime}')
return error_invalid_time(0, 'invalid weekday, at: ${p.current_pos_datetime}')
}

fn (mut p DateTimeParser) must_be_valid_two_letter_week_day() !int {
if p.current_pos_datetime + 2 < p.datetime.len {
letters := p.datetime[p.current_pos_datetime..p.current_pos_datetime + 2]
for d := 1; d <= long_days.len; d++ {
if days_string[(d - 1) * 3..d * 3 - 1] == letters {
p.current_pos_datetime += 2
return d
}
}
}
return error_invalid_time(0, 'invalid two letter weekday, at: ${p.current_pos_datetime}')
}

fn (mut p DateTimeParser) must_be_valid_three_letter_week_day() !int {
if p.current_pos_datetime + 3 < p.datetime.len {
letters := p.datetime[p.current_pos_datetime..p.current_pos_datetime + 3]
for d := 1; d <= long_days.len; d++ {
if days_string[(d - 1) * 3..d * 3] == letters {
p.current_pos_datetime += 3
return d
}
}
}
return error_invalid_time(0, 'invalid three letter weekday, at: ${p.current_pos_datetime}')
}

fn extract_tokens(s string) ![]string {
Expand All @@ -133,9 +162,15 @@ fn extract_tokens(s string) ![]string {
// YY - 2 digit year, 00..99
// M - month, 1..12
// MM - month, 2 digits, 01..12
// MMM - month, three letters, Jan..Dec
// MMMM - name of month
// D - day of the month, 1..31
// DD - day of the month, 01..31
// d - day of week, 0..6
// c - day of week, 1..7
// dd - day of week, Su..Sa
// ddd - day of week, Sun..Sat
// dddd - day of week, Sunday..Saturday
// H - hour, 0..23
// HH - hour, 00..23
// h - hour, 0..23
Expand Down Expand Up @@ -206,6 +241,21 @@ fn (mut p DateTimeParser) parse() !Time {
return error_invalid_time(0, 'day must be between 01 and 31')
}
}
'd' {
p.must_be_int(1) or { return err }
}
'c' {
p.must_be_int(1) or { return err }
}
'dd' {
p.must_be_valid_two_letter_week_day() or { return err }
}
'ddd' {
p.must_be_valid_three_letter_week_day() or { return err }
}
'dddd' {
p.must_be_valid_week_day() or { return err }
}
'H' {
hour_ = p.must_be_int_with_minimum_length(1, 2, true) or {
return error_invalid_time(0, 'end of string reached before hours where specified')
Expand Down
4 changes: 2 additions & 2 deletions vlib/time/format.v
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@ pub fn (t Time) custom_format(s string) string {
int(is_leap_year(t.year))))
}
'd' {
sb.write_string(t.day_of_week().str())
sb.write_string('${t.day_of_week() % 7}')
}
'dd' {
sb.write_string(long_days[t.day_of_week() - 1][0..2])
Expand Down Expand Up @@ -472,7 +472,7 @@ pub fn (t Time) custom_format(s string) string {
sb.write_string(ordinal_suffix((t.month % 4) + 1))
}
'c' {
sb.write_string('${t.day_of_week() + 1}')
sb.write_string('${t.day_of_week()}')
}
'N' {
// TODO: integrate BC
Expand Down
5 changes: 5 additions & 0 deletions vlib/time/parse.c.v
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,11 @@ pub fn parse(s string) !Time {
// MMMM - name of month
// D - day of the month, 1..31
// DD - day of the month, 01..31
// d - day of week, 0..6
// c - day of week, 1..7
// dd - day of week, Su..Sa
// ddd - day of week, Sun..Sat
// dddd - day of week, Sunday..Saturday
// H - hour, 0..23
// HH - hour, 00..23
// h - hour, 0..23
Expand Down
40 changes: 40 additions & 0 deletions vlib/time/time_test.v
Original file line number Diff line number Diff line change
Expand Up @@ -396,3 +396,43 @@ fn test_parse_three_letters_month() {
tm_tm := time.parse_format(tm_s, format)!
assert tm_tm.month == tm.month
}

fn test_parse_ordinal_weekday_d() {
format := 'd MMM DD HH:mm:ss YYYY'
dt := '0 Jan 01 00:00:00 1970'
tm := time.parse_format(dt, format)!
tm_s := tm.custom_format(format)
assert tm_s == '4 Jan 01 00:00:00 1970'
}

fn test_parse_ordinal_weekday_c() {
format := 'c MMM DD HH:mm:ss YYYY'
dt := '7 Jan 01 00:00:00 1970'
tm := time.parse_format(dt, format)!
tm_s := tm.custom_format(format)
assert tm_s == '4 Jan 01 00:00:00 1970'
}

fn test_parse_two_letters_weekday() {
format := 'dd MMM DD HH:mm:ss YYYY'
dt := 'Su Jan 01 00:00:00 1970'
tm := time.parse_format(dt, format)!
tm_s := tm.custom_format(format)
assert tm_s == 'Th Jan 01 00:00:00 1970'
}

fn test_parse_three_letters_weekday() {
format := 'ddd MMM DD HH:mm:ss YYYY'
dt := 'Sun Jan 01 00:00:00 1970'
tm := time.parse_format(dt, format)!
tm_s := tm.custom_format(format)
assert tm_s == 'Thu Jan 01 00:00:00 1970'
}

fn test_parse_weekday() {
format := 'dddd MMM DD HH:mm:ss YYYY'
dt := 'Sunday Jan 01 00:00:00 1970'
tm := time.parse_format(dt, format)!
tm_s := tm.custom_format(format)
assert tm_s == 'Thursday Jan 01 00:00:00 1970'
}
Loading