[Feature #18033] Parse more strictly conformant with ISO-8601

* 4-digits or more is required as year
* Minutes and seconds parts are not ommittable
This commit is contained in:
Nobuyoshi Nakada 2022-11-18 14:18:27 +09:00
Родитель 635fc5f7fc
Коммит 3e49d62bc1
2 изменённых файлов: 17 добавлений и 8 удалений

Просмотреть файл

@ -67,8 +67,12 @@ class TestTime < Test::Unit::TestCase
assert_equal(t, Time.new("2020-12-25 00:56:17 +0900"))
assert_equal(t, Time.new("2020-12-25 00:57:47 +090130"))
assert_equal(t, Time.new("2020-12-25T00:56:17+09:00"))
assert_equal(Time.utc(2020, 12, 24, 15, 56, 0), Time.new("2020-12-25 00:56 +09:00"))
assert_equal(Time.utc(2020, 12, 24, 15, 0, 0), Time.new("2020-12-25 00 +09:00"))
assert_raise_with_message(ArgumentError, /missing sec part/) {
Time.new("2020-12-25 00:56 +09:00")
}
assert_raise_with_message(ArgumentError, /missing min part/) {
Time.new("2020-12-25 00 +09:00")
}
assert_equal(Time.new(2021, 12, 25, in: "+09:00"), Time.new("2021-12-25+09:00"))
@ -79,7 +83,7 @@ class TestTime < Test::Unit::TestCase
assert_raise_with_message(ArgumentError, "subsecond expected after dot: 00:56:17. ") {
Time.new("2020-12-25 00:56:17. +0900")
}
assert_raise_with_message(ArgumentError, /year must be 2 or 4\+/) {
assert_raise_with_message(ArgumentError, /year must be 4 or more/) {
Time.new("021-12-25 00:00:00.123456 +09:00")
}
assert_raise_with_message(ArgumentError, /fraction min is.*56\./) {

15
time.c
Просмотреть файл

@ -2519,8 +2519,8 @@ time_init_parse(rb_execution_context_t *ec, VALUE klass, VALUE str, VALUE zone,
if (NIL_P(year)) {
rb_raise(rb_eArgError, "can't parse: %+"PRIsVALUE, str);
}
else if (ndigits != 2 && ndigits < 4) {
rb_raise(rb_eArgError, "year must be 2 or 4+ digits: %.*s", (int)ndigits, ptr - ndigits);
else if (ndigits < 4) {
rb_raise(rb_eArgError, "year must be 4 or more digits: %.*s", (int)ndigits, ptr - ndigits);
}
do {
#define peekable_p(n) ((ptrdiff_t)(n) < (end - ptr))
@ -2538,15 +2538,20 @@ time_init_parse(rb_execution_context_t *ec, VALUE klass, VALUE str, VALUE zone,
if (!ISDIGIT(peekc_n(1))) break;
#define nofraction(x) \
if (peek('.')) { \
rb_raise(rb_eArgError, "fraction %s is not supported: %.*s", #x, \
rb_raise(rb_eArgError, "fraction " #x " is not supported: %.*s", \
(int)(ptr + 1 - time_part), time_part); \
}
#define need_colon(x) \
if (!peek(':')) { \
rb_raise(rb_eArgError, "missing " #x " part: %.*s", \
(int)(ptr + 1 - time_part), time_part); \
}
expect_two_digits(hour);
nofraction(hour);
if (!peek(':')) break;
need_colon(min);
expect_two_digits(min);
nofraction(min);
if (!peek(':')) break;
need_colon(sec);
expect_two_digits(sec);
if (peek('.')) {
ptr++;