From c0bb9605c05900e5d14fa7e424e26e9a41ab0a8e Mon Sep 17 00:00:00 2001 From: Ivan Vatlin Date: Fri, 9 Aug 2024 10:27:15 +0000 Subject: [PATCH] time: `d`,`c`,`dd`,`ddd`,`dddd` pattern support for parse_format() (#22003) --- vlib/time/date_time_parser.v | 60 +++++++++++++++++++++++++++++++++--- vlib/time/format.v | 4 +-- vlib/time/parse.c.v | 5 +++ vlib/time/time_test.v | 40 ++++++++++++++++++++++++ 4 files changed, 102 insertions(+), 7 deletions(-) diff --git a/vlib/time/date_time_parser.v b/vlib/time/date_time_parser.v index 661f357bc3a381..6dda892bd60292 100644 --- a/vlib/time/date_time_parser.v +++ b/vlib/time/date_time_parser.v @@ -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 { @@ -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 @@ -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') diff --git a/vlib/time/format.v b/vlib/time/format.v index 6a83943c57fca2..dcdd15a3fb366f 100644 --- a/vlib/time/format.v +++ b/vlib/time/format.v @@ -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]) @@ -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 diff --git a/vlib/time/parse.c.v b/vlib/time/parse.c.v index 4cb2cbfa3abaca..2c41cd3ac5f236 100644 --- a/vlib/time/parse.c.v +++ b/vlib/time/parse.c.v @@ -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 diff --git a/vlib/time/time_test.v b/vlib/time/time_test.v index c5457d56716bdb..bf58b26abd9208 100644 --- a/vlib/time/time_test.v +++ b/vlib/time/time_test.v @@ -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' +}