commit 6e77907baa3cbeebc79241cc0046a539a09e3f2c from: Sergey Bronnikov via: Sergey Kaplun date: Tue Sep 17 07:43:17 2024 UTC datetime: forbid non-integers in :set() and parse() The patch forbids using non-integer values in datetime's `:set()` 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 `:set()` and parse() `:set()` 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. `tzoffset` passed to `datetime.parse()` can be integer or string. commit - cc9010a2b11477b2f16f2b2e168a6b9dcca2fb20 commit + 6e77907baa3cbeebc79241cc0046a539a09e3f2c blob - /dev/null blob + 66aab193f07c818b41a470f1fc3fb46a0d4cc413 (mode 644) --- /dev/null +++ changelogs/unreleased/gh-10391-forbid-non-integers-datetime-set.md @@ -0,0 +1,3 @@ +## bugfix/datetime + +- Forbid non-integers in `:set()` and `datetime.parse()` (gh-10391). blob - cf835b55fea8b3e1b3540b16814d7a078a2b7921 blob + 955f4fc513507dde4c6a74129f8de56576fa66ad --- src/lua/datetime.lua +++ src/lua/datetime.lua @@ -1031,16 +1031,19 @@ local function datetime_set(self, 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 @@ -1052,16 +1055,19 @@ local function datetime_set(self, obj) 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 sec = obj.sec if sec ~= nil then check_range(sec, 0, 60, 'sec') + check_integer(sec, 'sec') hms = true end @@ -1075,12 +1081,15 @@ local function datetime_set(self, obj) end if usec ~= nil then check_range(usec, 0, 1e6, 'usec') + check_integer(usec, 'usec') self.nsec = usec * 1e3 elseif msec ~= nil then check_range(msec, 0, 1e3, 'msec') + check_integer(msec, 'msec') self.nsec = msec * 1e6 elseif nsec ~= nil then check_range(nsec, 0, 1e9, 'nsec') + check_integer(nsec, 'nsec') self.nsec = nsec end end blob - ed4532efa096e7e85834306bce3bfa86b4c63318 blob + d448a6d9b8d1b36ac911d2e52efbd0bf9d00dfa1 --- test/app-tap/datetime.test.lua +++ test/app-tap/datetime.test.lua @@ -569,7 +569,7 @@ local function couldnt_parse(txt) end test:test("Check parsing of dates with invalid attributes", function(test) - test:plan(32) + test:plan(33) local boundary_checks = { {'month', {1, 12}}, @@ -602,6 +602,17 @@ test:test("Check parsing of dates with invalid attribu assert_raises(test, couldnt_parse(txt), function() dt, len = date.parse(txt) end) end + + local specific_errors = { + { + only_integer_msg('tzoffset'), + { '1998-11-25', { format = '%Y-%m-%d', tzoffset = 1.1 } } + }, + } + for _, row in pairs(specific_errors) do + local err_msg, attribs = unpack(row) + assert_raises(test, err_msg, function() date.parse(unpack(attribs)) end) + end end) test:test("Parsing of timezone abbrevs", function(test) @@ -2009,7 +2020,7 @@ end) test:test("Time invalid :set{} operations", function(test) - test:plan(84) + test:plan(94) local boundary_checks = { {'year', {MIN_DATE_YEAR, MAX_DATE_YEAR}}, @@ -2078,6 +2089,16 @@ test:test("Time invalid :set{} operations", function(t {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}},