From 64faabe88f8f0aeb246e55ca8da82d50dbe1e056 Mon Sep 17 00:00:00 2001 From: Timur Safin <tsafin@tarantool.org> Date: Sat, 5 Mar 2022 22:36:33 +0300 Subject: [PATCH] datetime: simplify boundary checks We used to use very ugly and tricky approach to check that passed years, months and days were not exceeding supported range of values. Now we have introduced to `c-dt` library the new function `dt_from_ymd_checked` for that purpose (i.e. check that values are valid, and construct dt from them). So rewrite/simplify Lua code to use that entry as `tnt_dt_from_ymd_checked`. Part of #6731 NO_DOC=refactoring NO_CHANGELOG=refactoring --- src/lua/datetime.lua | 48 +++++++++------------------------- test/app-tap/datetime.test.lua | 30 +++++++-------------- 2 files changed, 22 insertions(+), 56 deletions(-) diff --git a/src/lua/datetime.lua b/src/lua/datetime.lua index 7b494fe92b..c581e170d3 100644 --- a/src/lua/datetime.lua +++ b/src/lua/datetime.lua @@ -42,7 +42,7 @@ typedef enum { } dt_dow_t; dt_t tnt_dt_from_rdn (int n); -dt_t tnt_dt_from_ymd (int y, int m, int d); +bool tnt_dt_from_ymd_checked(int y, int m, int d, dt_t *val); void tnt_dt_to_ymd (dt_t dt, int *y, int *m, int *d); dt_dow_t tnt_dt_dow (dt_t dt); @@ -287,38 +287,16 @@ local function check_dt(dt_v, direction, v, unit) end end -local function check_ymd_range(y, M, d) - -- Fast path. Max/min year is rather theoretical. Nobody is going to - -- actually use them. - if y > MIN_DATE_YEAR and y < MAX_DATE_YEAR then - return - end - -- Slow path. - if y < MIN_DATE_YEAR then - goto min_err - elseif y > MAX_DATE_YEAR then - goto max_err - elseif y == MIN_DATE_YEAR then - if M < MIN_DATE_MONTH then - goto min_err - elseif M == MIN_DATE_MONTH and d < MIN_DATE_DAY then - goto min_err - end - return - -- y == MAX_DATE_YEAR - elseif M > MAX_DATE_MONTH then - goto max_err - elseif M == MAX_DATE_MONTH and d > MAX_DATE_DAY then - goto max_err - else - return +local function dt_from_ymd_checked(y, M, d) + local pdt = date_dt_stash_take() + local is_valid = builtin.tnt_dt_from_ymd_checked(y, M, d, pdt) + if not is_valid then + date_dt_stash_put(pdt) + error(('date %4d-%02d-%02d is invalid'):format(y, M, d)) end -::min_err:: - error(('date %d-%02d-%02d is less than minimum allowed %s'): - format(y, M, d, MIN_DATE_TEXT)) -::max_err:: - error(('date %d-%02d-%02d is greater than maximum allowed %s'): - format(y, M, d, MAX_DATE_TEXT)) + local dt = pdt[0] + date_dt_stash_put(pdt) + return dt end -- check v value against maximum/minimum possible values @@ -619,8 +597,7 @@ local function datetime_new(obj) format(d, M, y), 3) end end - check_ymd_range(y, M, d) - dt = builtin.tnt_dt_from_ymd(y, M, d) + dt = dt_from_ymd_checked(y, M, d) end -- .hour, .minute, .second @@ -1036,7 +1013,7 @@ local function datetime_ymd_update(self, y, M, d, new_offset) format(d, M, y), 3) end end - local dt = builtin.tnt_dt_from_ymd(y, M, d) + local dt = dt_from_ymd_checked(y, M, d) datetime_update_dt(self, dt, new_offset) end @@ -1159,7 +1136,6 @@ local function datetime_set(self, obj) y = y or y0 M = M or M0 d = d or d0 - check_ymd_range(y, M, d) datetime_ymd_update(self, y, M, d, offset) end diff --git a/test/app-tap/datetime.test.lua b/test/app-tap/datetime.test.lua index 6d60aa5dd1..5036499b5f 100755 --- a/test/app-tap/datetime.test.lua +++ b/test/app-tap/datetime.test.lua @@ -15,12 +15,8 @@ test:plan(32) -- minimum supported date - -5879610-06-22 local MIN_DATE_YEAR = -5879610 -local MIN_DATE_MONTH = 6 -local MIN_DATE_DAY = 22 -- maximum supported date - 5879611-07-11 local MAX_DATE_YEAR = 5879611 -local MAX_DATE_MONTH = 7 -local MAX_DATE_DAY = 11 local SECS_PER_DAY = 86400 local AVERAGE_DAYS_YEAR = 365.25 @@ -78,14 +74,8 @@ local function range_check_3_error(name, value, range) format(value, name, range[1], range[2], range[3]) end -local function less_than_min(y, M, d) - return ('date %d-%02d-%02d is less than minimum allowed %d-%02d-%02d'): - format(y, M, d, MIN_DATE_YEAR, MIN_DATE_MONTH, MIN_DATE_DAY) -end - -local function greater_than_max(y, M, d) - return ('date %d-%02d-%02d is greater than maximum allowed %d-%02d-%02d'): - format(y, M, d, MAX_DATE_YEAR, MAX_DATE_MONTH, MAX_DATE_DAY) +local function invalid_date(y, M, d) + return ('date %d-%02d-%02d is invalid'):format(y, M, d) end local function invalid_tz_fmt_error(val) @@ -320,17 +310,17 @@ test:test("Simple date creation by attributes - check failed", function(test) {range_check_3_error('day', 32, {-1, 1, 31}), {year = 2021, month = 6, day = 32}}, {invalid_days_in_mon(31, 6, 2021), { year = 2021, month = 6, day = 31}}, - {less_than_min(-5879610, 6, 21), + {invalid_date(-5879610, 6, 21), {year = -5879610, month = 6, day = 21}}, - {less_than_min(-5879610, 1, 1), + {invalid_date(-5879610, 1, 1), {year = -5879610, month = 1, day = 1}}, {range_check_error('year', -16009610, {MIN_DATE_YEAR, MAX_DATE_YEAR}), {year = -16009610, month = 12, day = 31}}, {range_check_error('year', 16009610, {MIN_DATE_YEAR, MAX_DATE_YEAR}), {year = 16009610, month = 1, day = 1}}, - {greater_than_max(MAX_DATE_YEAR, 9, 1), + {invalid_date(MAX_DATE_YEAR, 9, 1), {year = MAX_DATE_YEAR, month = 9, day = 1}}, - {greater_than_max(MAX_DATE_YEAR, 7, 12), + {invalid_date(MAX_DATE_YEAR, 7, 12), {year = MAX_DATE_YEAR, month = 7, day = 12}}, } for _, row in pairs(specific_errors) do @@ -1610,17 +1600,17 @@ test:test("Time invalid :set{} operations", function(test) {range_check_3_error('day', 32, {-1, 1, 31}), {year = 2021, month = 6, day = 32}}, {invalid_days_in_mon(31, 6, 2021), { month = 6, day = 31}}, - {less_than_min(-5879610, 6, 21), + {invalid_date(-5879610, 6, 21), {year = -5879610, month = 6, day = 21}}, - {less_than_min(-5879610, 1, 1), + {invalid_date(-5879610, 1, 1), {year = -5879610, month = 1, day = 1}}, {range_check_error('year', -16009610, {MIN_DATE_YEAR, MAX_DATE_YEAR}), {year = -16009610, month = 12, day = 31}}, {range_check_error('year', 16009610, {MIN_DATE_YEAR, MAX_DATE_YEAR}), {year = 16009610, month = 1, day = 1}}, - {greater_than_max(MAX_DATE_YEAR, 9, 1), + {invalid_date(MAX_DATE_YEAR, 9, 1), {year = MAX_DATE_YEAR, month = 9, day = 1}}, - {greater_than_max(MAX_DATE_YEAR, 7, 12), + {invalid_date(MAX_DATE_YEAR, 7, 12), {year = MAX_DATE_YEAR, month = 7, day = 12}}, } for _, row in pairs(specific_errors) do -- GitLab