From 29be5eb3b6f786d0eafe0dc50bdaa037cc7351f0 Mon Sep 17 00:00:00 2001 From: Sergey Bronnikov <sergeyb@tarantool.org> Date: Tue, 27 Aug 2024 15:48:17 +0300 Subject: [PATCH] datetime: forbid using non-integer values in .new() The patch forbids using non-integer values in datetime constructor `datetime.new()` for `year`, `month`, `day`, `hour`, `min`, `sec`, `usec`, `msec` and `nsec` keys. The type of `tzoffset` can be integer or string, `timestamp` can be double, and integer values allowed in timestamp if `nsec`, `usec`, or `msecs` provided. An error will be raised when a value of incorrect type is passed. Part of #10391 @TarantoolBot document Title: Update types of values passed to `datetime.new()` `datetime.new()` can accept only integer values for `year`, `month`, `day`, `hour`, `min`, `sec`, `usec`, `msec` and `nsec`. The type of `tzoffset` can be integer or string, `timestamp` can be integer or double. (cherry picked from commit cc9010a2b11477b2f16f2b2e168a6b9dcca2fb20) --- ...-10391-forbid-non-integers-datetime-new.md | 3 ++ src/lua/datetime.lua | 10 +++++++ test/app-tap/datetime.test.lua | 28 +++++++++++++------ 3 files changed, 33 insertions(+), 8 deletions(-) create mode 100644 changelogs/unreleased/gh-10391-forbid-non-integers-datetime-new.md diff --git a/changelogs/unreleased/gh-10391-forbid-non-integers-datetime-new.md b/changelogs/unreleased/gh-10391-forbid-non-integers-datetime-new.md new file mode 100644 index 0000000000..d7b560a85b --- /dev/null +++ b/changelogs/unreleased/gh-10391-forbid-non-integers-datetime-new.md @@ -0,0 +1,3 @@ +## bugfix/datetime + +- Forbid non-integers in `datetime.new()` (gh-10391). diff --git a/src/lua/datetime.lua b/src/lua/datetime.lua index 024cfb73d1..c3ee775fa2 100644 --- a/src/lua/datetime.lua +++ b/src/lua/datetime.lua @@ -504,6 +504,7 @@ end local function get_timezone(offset, msg) if type(offset) == 'number' then + check_integer(offset, 'tzoffset') return offset elseif type(offset) == 'string' then return parse_tzoffset(offset) @@ -527,31 +528,37 @@ local function datetime_new(obj) local y = obj.year if y ~= nil then check_range(y, MIN_DATE_YEAR, MAX_DATE_YEAR, 'year') + check_integer(y, 'year') ymd = true end local M = obj.month if M ~= nil then check_range(M, 1, 12, 'month') + check_integer(M, 'month') ymd = true end local d = obj.day if d ~= nil then check_range(d, 1, 31, 'day', -1) + check_integer(d, 'day') ymd = true end local h = obj.hour if h ~= nil then check_range(h, 0, 23, 'hour') + check_integer(h, 'hour') hms = true end local m = obj.min if m ~= nil then check_range(m, 0, 59, 'min') + check_integer(m, 'min') hms = true end local s = obj.sec if s ~= nil then check_range(s, 0, 60, 'sec') + check_integer(s, 'sec') hms = true end @@ -565,12 +572,15 @@ local function datetime_new(obj) end if usec ~= nil then check_range(usec, 0, 1e6, 'usec') + check_integer(usec, 'usec') nsec = usec * 1e3 elseif msec ~= nil then check_range(msec, 0, 1e3, 'msec') + check_integer(msec, 'msec') nsec = msec * 1e6 else check_range(nsec, 0, 1e9, 'nsec') + check_integer(nsec, 'nsec') end else nsec = 0 diff --git a/test/app-tap/datetime.test.lua b/test/app-tap/datetime.test.lua index 3301fc39de..ed4532efa0 100755 --- a/test/app-tap/datetime.test.lua +++ b/test/app-tap/datetime.test.lua @@ -34,9 +34,11 @@ local MAX_MSEC_RANGE = math.floor(MAX_NSEC_RANGE / 1e6) local incompat_types = 'incompatible types for datetime comparison' local only_integer_ts = 'only integer values allowed in timestamp'.. ' if nsec, usec, or msecs provided' +local only_integer_msg = function(key) + return key .. ': integer value expected, but received number' +end local only_one_of = 'only one of nsec, usec or msecs may be defined'.. ' simultaneously' -local int_ival_exp = 'sec: integer value expected, but received number' local timestamp_and_ymd = 'timestamp is not allowed if year/month/day provided' local timestamp_and_hms = 'timestamp is not allowed if hour/min/sec provided' local str_or_num_exp = 'tzoffset: string or number expected, but received' @@ -271,7 +273,7 @@ test:test("Simple date creation by attributes", function(test) end) test:test("Simple date creation by attributes - check failed", function(test) - test:plan(83) + test:plan(93) local boundary_checks = { {'year', {MIN_DATE_YEAR, MAX_DATE_YEAR}}, @@ -339,6 +341,16 @@ test:test("Simple date creation by attributes - check failed", function(test) {only_one_of, { nsec = 123456, msec = 123}}, {only_one_of, { usec = 123, msec = 123}}, {only_one_of, { nsec = 123456, usec = 123, msec = 123}}, + {only_integer_msg('nsec'), { nsec = 1.1 }}, + {only_integer_msg('msec'), { msec = 1.1 }}, + {only_integer_msg('usec'), { usec = 1.1 }}, + {only_integer_msg('tzoffset'), { tzoffset = 1.1 }}, + {only_integer_msg('year'), { year = 1.1 }}, + {only_integer_msg('month'), { month = 1.1 }}, + {only_integer_msg('day'), { day = 1.1 }}, + {only_integer_msg('hour'), { hour = 1.1 }}, + {only_integer_msg('min'), { min = 1.1 }}, + {only_integer_msg('sec'), { sec = 1.1 }}, {only_integer_ts, { timestamp = 12345.125, usec = 123}}, {only_integer_ts, { timestamp = 12345.125, msec = 123}}, {only_integer_ts, { timestamp = 12345.125, nsec = 123}}, @@ -1169,9 +1181,9 @@ test:test("Time interval operations", function(test) {only_one_of, { nsec = 123456, msec = 123}}, {only_one_of, { usec = 123, msec = 123}}, {only_one_of, { nsec = 123456, usec = 123, msec = 123}}, - {int_ival_exp, { sec = 12345.125, usec = 123}}, - {int_ival_exp, { sec = 12345.125, msec = 123}}, - {int_ival_exp, { sec = 12345.125, nsec = 123}}, + {only_integer_msg('sec'), { sec = 12345.125, usec = 123}}, + {only_integer_msg('sec'), { sec = 12345.125, msec = 123}}, + {only_integer_msg('sec'), { sec = 12345.125, nsec = 123}}, } for _, row in pairs(specific_errors) do local err_msg, obj = unpack(row) @@ -1322,9 +1334,9 @@ test:test("Time intervals creation - range checks", function(test) {only_one_of, { nsec = 123456, msec = 123}}, {only_one_of, { usec = 123, msec = 123}}, {only_one_of, { nsec = 123456, usec = 123, msec = 123}}, - {int_ival_exp, { sec = 12345.125, usec = 123}}, - {int_ival_exp, { sec = 12345.125, msec = 123}}, - {int_ival_exp, { sec = 12345.125, nsec = 123}}, + {only_integer_msg('sec'), { sec = 12345.125, usec = 123}}, + {only_integer_msg('sec'), { sec = 12345.125, msec = 123}}, + {only_integer_msg('sec'), { sec = 12345.125, nsec = 123}}, {table_expected('interval.new()', '2001-01-01'), '2001-01-01'}, {table_expected('interval.new()', 20010101), 20010101}, {range_check_error('year', 1e21, {-MAX_YEAR_RANGE, MAX_YEAR_RANGE}), -- GitLab