From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from [87.239.111.99] (localhost [127.0.0.1]) by dev.tarantool.org (Postfix) with ESMTP id E47DB6EC40; Tue, 17 Aug 2021 20:06:40 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org E47DB6EC40 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=tarantool.org; s=dev; t=1629220001; bh=0MdlJCpSan+c/KHdbQveqZIbbtHOkN2TA3ivBCMzwfQ=; h=Date:To:References:In-Reply-To:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=IBPaRaVfVfRvlUFCjtdF++Oj/3HcHDElyixD56sb7ljI/DM23b1kbdhQGXZn/BoAs zTGRmfz3pO2F5FWlWjY/tZuOf52PZRjqojAasomY5epnH1iuMkCgVnC3QHkI/ByOib cDY9FS+1lVPMdIXQN9lkI3RqanDglUJfUsY1hf14= Received: from smtpng2.i.mail.ru (smtpng2.i.mail.ru [94.100.179.3]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dev.tarantool.org (Postfix) with ESMTPS id E98C86EC40 for ; Tue, 17 Aug 2021 20:06:39 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org E98C86EC40 Received: by smtpng2.m.smailru.net with esmtpa (envelope-from ) id 1mG2Xu-00024A-R3; Tue, 17 Aug 2021 20:06:39 +0300 Date: Tue, 17 Aug 2021 20:06:37 +0300 To: Timur Safin via Tarantool-patches Message-ID: <20210817170637.x3ilanywpmgbugj5@esperanza> References: <8dccf7ee1d6db0f8fd194ab45ae16978b74ec99b.1629071531.git.tsafin@tarantool.org> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <8dccf7ee1d6db0f8fd194ab45ae16978b74ec99b.1629071531.git.tsafin@tarantool.org> X-7564579A: 646B95376F6C166E X-77F55803: 4F1203BC0FB41BD92087353F0EC44DD906AB4890CDABF0C5CB76CEE71D3E4007182A05F53808504001DBE3FCB134B83F80E77EE4369BA8EEE4BF542A3C2978E05F55555F6FB85B49 X-7FA49CB5: FF5795518A3D127A4AD6D5ED66289B5278DA827A17800CE7D9C4478D0B876341EA1F7E6F0F101C67BD4B6F7A4D31EC0BCC500DACC3FED6E28638F802B75D45FF8AA50765F7900637593B4F2A76947A308638F802B75D45FF36EB9D2243A4F8B5A6FCA7DBDB1FC311F39EFFDF887939037866D6147AF826D8CB431A42DB6C3469E2301984BB02A66A117882F4460429724CE54428C33FAD305F5C1EE8F4F765FCAA867293B0326636D2E47CDBA5A96583BD4B6F7A4D31EC0BC014FD901B82EE079FA2833FD35BB23D27C277FBC8AE2E8BAA867293B0326636D2E47CDBA5A96583BA9C0B312567BB231DD303D21008E29813377AFFFEAFD269A417C69337E82CC2E827F84554CEF50127C277FBC8AE2E8BA83251EDC214901ED5E8D9A59859A8B613439FA09F3DCB32089D37D7C0E48F6C5571747095F342E88FB05168BE4CE3AF X-C1DE0DAB: 0D63561A33F958A59C1AEE654869B754965C3C4756EA5D979E6EECBA88E40612D59269BC5F550898D99A6476B3ADF6B47008B74DF8BB9EF7333BD3B22AA88B938A852937E12ACA7567C209D01CC1E34B410CA545F18667F91A7EA1CDA0B5A7A0 X-C8649E89: 4E36BF7865823D7055A7F0CF078B5EC49A30900B95165D34315359784EE451039263EEF838B8C0A619D524053002B27690BDDD7A9670ADE0108432CB3A72B0691D7E09C32AA3244CCAFF4D3E5DB380CED7E62B85260D722F6C2483212766842283B48618A63566E0 X-D57D3AED: 3ZO7eAau8CL7WIMRKs4sN3D3tLDjz0dLbV79QFUyzQ2Ujvy7cMT6pYYqY16iZVKkSc3dCLJ7zSJH7+u4VD18S7Vl4ZUrpaVfd2+vE6kuoey4m4VkSEu530nj6fImhcD4MUrOEAnl0W826KZ9Q+tr5ycPtXkTV4k65bRjmOUUP8cvGozZ33TWg5HZplvhhXbhDGzqmQDTd6OAevLeAnq3Ra9uf7zvY2zzsIhlcp/Y7m53TZgf2aB4JOg4gkr2biojuRQ/H5n28toZ71PJg0Ix0w== X-Mailru-Sender: 689FA8AB762F7393C37E3C1AEC41BA5D44B2F3A3B60915AC944F87A7762473A0274CEFED1673C562683ABF942079399BFB559BB5D741EB966A65DFF43FF7BE03240331F90058701C67EA787935ED9F1B X-Mras: Ok Subject: Re: [Tarantool-patches] [PATCH v5 3/8] lua, datetime: display datetime X-BeenThere: tarantool-patches@dev.tarantool.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Tarantool development patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , From: Vladimir Davydov via Tarantool-patches Reply-To: Vladimir Davydov Cc: v.shpilevoy@tarantool.org Errors-To: tarantool-patches-bounces@dev.tarantool.org Sender: "Tarantool-patches" On Mon, Aug 16, 2021 at 02:59:37AM +0300, Timur Safin via Tarantool-patches wrote: > * introduced output routine for converting datetime > to their default output format. > > * use this routine for tostring() in datetime.lua > > Part of #5941 > --- > extra/exports | 1 + > src/lib/core/datetime.c | 71 ++++++++++++++++++ > src/lib/core/datetime.h | 9 +++ > src/lua/datetime.lua | 35 +++++++++ > test/app-tap/datetime.test.lua | 131 ++++++++++++++++++--------------- > test/unit/CMakeLists.txt | 2 +- > test/unit/datetime.c | 61 +++++++++++---- > 7 files changed, 236 insertions(+), 74 deletions(-) > > diff --git a/extra/exports b/extra/exports > index 80eb92abd..2437e175c 100644 > --- a/extra/exports > +++ b/extra/exports > @@ -152,6 +152,7 @@ datetime_asctime > datetime_ctime > datetime_now > datetime_strftime > +datetime_to_string > decimal_unpack > decimal_from_string > decimal_unpack > diff --git a/src/lib/core/datetime.c b/src/lib/core/datetime.c > index c48295a6f..c24a0df82 100644 > --- a/src/lib/core/datetime.c > +++ b/src/lib/core/datetime.c > @@ -29,6 +29,8 @@ > * SUCH DAMAGE. > */ > > +#include > +#include > #include > #include > > @@ -94,3 +96,72 @@ datetime_strftime(const struct datetime *date, const char *fmt, char *buf, > struct tm *p_tm = datetime_to_tm(date); > return strftime(buf, len, fmt, p_tm); > } > + > +#define SECS_EPOCH_1970_OFFSET ((int64_t)DT_EPOCH_1970_OFFSET * SECS_PER_DAY) > + > +/* NB! buf may be NULL, and we should handle it gracefully, returning /** * ... (according to our coding style) > + * calculated length of output string > + */ > +int > +datetime_to_string(const struct datetime *date, char *buf, uint32_t len) > +{ > +#define ADVANCE(sz) \ > + if (buf != NULL) { \ > + buf += sz; \ > + len -= sz; \ > + } \ > + ret += sz; Please use SNPRINT helper. > + > + int offset = date->offset; > + /* for negative offsets around Epoch date we could get > + * negative secs value, which should be attributed to > + * 1969-12-31, not 1970-01-01, thus we first shift > + * epoch to Rata Die then divide by seconds per day, > + * not in reverse > + */ > + int64_t secs = (int64_t)date->secs + offset * 60 + SECS_EPOCH_1970_OFFSET; > + assert((secs / SECS_PER_DAY) <= INT_MAX); > + dt_t dt = dt_from_rdn(secs / SECS_PER_DAY); > + > + int year, month, day, sec, ns, sign; > + dt_to_ymd(dt, &year, &month, &day); > + > + int hour = (secs / 3600) % 24, > + minute = (secs / 60) % 60; Please define on a separate line: int hour = ...; int minute = ...; > + sec = secs % 60; sec, secs, oh Please use better names. > + ns = date->nsec; > + > + int ret = 0; > + uint32_t sz = snprintf(buf, len, "%04d-%02d-%02dT%02d:%02d", > + year, month, day, hour, minute); > + ADVANCE(sz); > + if (sec || ns) { > + sz = snprintf(buf, len, ":%02d", sec); > + ADVANCE(sz); > + if (ns) { > + if ((ns % 1000000) == 0) > + sz = snprintf(buf, len, ".%03d", ns / 1000000); > + else if ((ns % 1000) == 0) > + sz = snprintf(buf, len, ".%06d", ns / 1000); > + else > + sz = snprintf(buf, len, ".%09d", ns); > + ADVANCE(sz); > + } > + } > + if (offset == 0) { > + sz = snprintf(buf, len, "Z"); > + ADVANCE(sz); > + } > + else { Bad formatting. Should be '} else {'. > + if (offset < 0) > + sign = '-', offset = -offset; Please don't abuse ','. > + else > + sign = '+'; > + > + sz = snprintf(buf, len, "%c%02d:%02d", sign, offset / 60, offset % 60); > + ADVANCE(sz); > + } > + return ret; > +} > +#undef ADVANCE > + > diff --git a/src/lib/core/datetime.h b/src/lib/core/datetime.h > index 1a8d7e34f..964e76fcc 100644 > --- a/src/lib/core/datetime.h > +++ b/src/lib/core/datetime.h > @@ -70,6 +70,15 @@ struct datetime_interval { > int32_t nsec; > }; > > +/** > + * Convert datetime to string using default format > + * @param date source datetime value > + * @param buf output character buffer > + * @param len size ofoutput buffer > + */ > +int > +datetime_to_string(const struct datetime *date, char *buf, uint32_t len); > + This should be an snprint-like function: buf and len should go first. This would allow us to use it in conjunction with SNPRINT. > /** > * Convert datetime to string using default asctime format > * "Sun Sep 16 01:03:52 1973\n\0" > diff --git a/src/lua/datetime.lua b/src/lua/datetime.lua > index ce579828f..4d946f194 100644 > --- a/src/lua/datetime.lua > +++ b/src/lua/datetime.lua > @@ -249,6 +249,37 @@ local function datetime_new(obj) > return datetime_new_dt(dt, secs, frac, offset) > end > > +local function datetime_tostring(o) Please add a comment to this function with example output. > + if ffi.typeof(o) == datetime_t then > + local sz = 48 > + local buff = ffi.new('char[?]', sz) > + local len = builtin.datetime_to_string(o, buff, sz) > + assert(len < sz) > + return ffi.string(buff) > + elseif ffi.typeof(o) == interval_t then Please define separate functions for interval and datetime. > + local ts = o.timestamp > + local sign = '+' > + > + if ts < 0 then > + ts = -ts > + sign = '-' > + end > + > + if ts < 60 then > + return ('%s%s secs'):format(sign, ts) > + elseif ts < 60 * 60 then > + return ('%+d minutes, %s seconds'):format(o.minutes, ts % 60) > + elseif ts < 24 * 60 * 60 then > + return ('%+d hours, %d minutes, %s seconds'):format( > + o.hours, o.minutes % 60, ts % 60) > + else > + return ('%+d days, %d hours, %d minutes, %s seconds'):format( > + o.days, o.hours % 24, o.minutes % 60, ts % 60) > + end > + end > +end > + > + > --[[ > Basic Extended > 20121224 2012-12-24 Calendar date (ISO 8601) > @@ -457,6 +488,7 @@ local function strftime(fmt, o) > end > > local datetime_mt = { > + __tostring = datetime_tostring, > __serialize = datetime_serialize, > __eq = datetime_eq, > __lt = datetime_lt, > @@ -466,6 +498,7 @@ local datetime_mt = { > } > > local interval_mt = { > + __tostring = datetime_tostring, > __serialize = interval_serialize, > __eq = datetime_eq, > __lt = datetime_lt, > @@ -487,6 +520,8 @@ return setmetatable( > parse_time = parse_time, > parse_zone = parse_zone, > > + tostring = datetime_tostring, > + I don't think we need this function in the module. Global tostring() is enough.