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 092B86EC58; Wed, 4 Aug 2021 00:24:37 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 092B86EC58 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=tarantool.org; s=dev; t=1628025877; bh=o5zDjBC6RfsruLpkbA17zr0Ir0dR9t3N0h+0RD0Lq6g=; h=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=C9Gjo/tRKs3k4sv7IB4pYRoPcVFH1HEFcy3EGzTqmEAkVpFiWu9/VtStjLJlHifaJ w6mxqZSQ2FXIHNjpH/PO5NLxkhKn/CJmORYSBb5NBTfCuqSVf1qAq6Q07TS/uhQ0ZA Bx8/GUUMRngd42h29DN34JG+bwnPmtudkDeNETYo= Received: from smtp38.i.mail.ru (smtp38.i.mail.ru [94.100.177.98]) (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 F217B6EC5F for ; Wed, 4 Aug 2021 00:24:04 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org F217B6EC5F Received: by smtp38.i.mail.ru with esmtpa (envelope-from ) id 1mB1tL-0006iG-HK; Wed, 04 Aug 2021 00:24:04 +0300 To: v.shpilevoy@tarantool.org, olegrok@tarantool.org Date: Wed, 4 Aug 2021 00:23:50 +0300 Message-Id: <5817f15e9db569675ce595cfd63a03bab1875c3c.1628025689.git.tsafin@tarantool.org> X-Mailer: git-send-email 2.29.2 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-4EC0790: 10 X-7564579A: B8F34718100C35BD X-77F55803: 4F1203BC0FB41BD941C43E597735A9C354866C15C72ED952BE56FFA0EFAF5B8C182A05F538085040448CA9A09FB1F12E9FA4B45993EF623C07E19B5F910297830CB0C440215132C7 X-7FA49CB5: FF5795518A3D127A4AD6D5ED66289B5278DA827A17800CE7F65C230EDDCD559EEA1F7E6F0F101C67BD4B6F7A4D31EC0BCC500DACC3FED6E28638F802B75D45FF8AA50765F790063703E3935C5A8197E98638F802B75D45FF36EB9D2243A4F8B5A6FCA7DBDB1FC311F39EFFDF887939037866D6147AF826D8413C1EB522C8C2BDA30C89DA0EE680F6117882F4460429724CE54428C33FAD305F5C1EE8F4F765FCAA867293B0326636D2E47CDBA5A96583BD4B6F7A4D31EC0BC014FD901B82EE079FA2833FD35BB23D27C277FBC8AE2E8BAA867293B0326636D2E47CDBA5A96583BA9C0B312567BB2376E601842F6C81A19E625A9149C048EEC8105B04EFE07628A5FD2DD08EB4836CD8FC6C240DEA7642DBF02ECDB25306B2B78CF848AE20165D0A6AB1C7CE11FEE34B6F6234D9065C976136E347CC761E07C4224003CC836476EA7A3FFF5B025636E2021AF6380DFAD1A18204E546F3947CB11811A4A51E3B096D1867E19FE1407959CC434672EE6371089D37D7C0E48F6C8AA50765F79006371F24DFF1B2961425731C566533BA786AA5CC5B56E945C8DA X-B7AD71C0: AC4F5C86D027EB782CDD5689AFBDA7A213B5FB47DCBC3458F0AFF96BAACF4158235E5A14AD4A4A4625E192CAD1D9E79D94463893BF8742D083918BE1BCCE1A33 X-C1DE0DAB: C20DE7B7AB408E4181F030C43753B8186998911F362727C414F749A5E30D975C30CE973C7F71088DAF308AF9A4B82C3FF4AEB232CA0F04F49C2B6934AE262D3EE7EAB7254005DCED7532B743992DF240BDC6A1CF3F042BAD6DF99611D93F60EF03D88DA7F5FEDC25699F904B3F4130E343918A1A30D5E7FCCB5012B2E24CD356 X-C8649E89: 4E36BF7865823D7055A7F0CF078B5EC49A30900B95165D34F6CC1FD33669633633B47AA5AF9DBD834F7A29E71C77D7B27A3E39DCF77EEDF48B6FDA6ECBD3C42B1D7E09C32AA3244C4993E1C96999B04AD9A0B2A8903DCADB55E75C8D0ED9F6EE8D5DD81C2BAB7D1D X-D57D3AED: 3ZO7eAau8CL7WIMRKs4sN3D3tLDjz0dLbV79QFUyzQ2Ujvy7cMT6pYYqY16iZVKkSc3dCLJ7zSJH7+u4VD18S7Vl4ZUrpaVfd2+vE6kuoey4m4VkSEu530nj6fImhcD4MUrOEAnl0W826KZ9Q+tr5ycPtXkTV4k65bRjmOUUP8cvGozZ33TWg5HZplvhhXbhDGzqmQDTd6OAevLeAnq3Ra9uf7zvY2zzsIhlcp/Y7m53TZgf2aB4JOg4gkr2biojeDyvyeZJDJEwz58bQBMDgg== X-Mailru-Sender: B5B6A6EBBD94DAD8516C636B482E0CE476A700D7CEE0C2CA7A49F385BD572B92F5494DF53083D48C1EC9E4A2C82A33BC8C24925A86E657CE0C70AEE3C9A96FBAB3D7EE8ED63280BE112434F685709FCF0DA7A0AF5A3A8387 X-Mras: Ok Subject: [Tarantool-patches] [PATCH v3 2/2] lua, datetime: introduce ctime, strftime wrappers 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: Timur Safin via Tarantool-patches Reply-To: Timur Safin Cc: tarantool-patches@dev.tarantool.org Errors-To: tarantool-patches-bounces@dev.tarantool.org Sender: "Tarantool-patches" To make Lua code less platfrom dependent we move all platform specifics to the C level. Specifically we want to avoid dependence on `struct tm {}` layout and GLIBC `strftime` behaviour. As a bonus we have that after moving of time dependent code to C we make Lua code significantly simpler and thus may get rid of all implementation specific details with numerous typedefs and function declarations. Part of #5941 --- src/exports.h | 4 ++ src/lib/core/datetime.c | 63 +++++++++++++++++- src/lib/core/datetime.h | 23 ++++++- src/lua/datetime.lua | 139 +++++----------------------------------- 4 files changed, 104 insertions(+), 125 deletions(-) diff --git a/src/exports.h b/src/exports.h index 63efe0ec7..f4a6f98d7 100644 --- a/src/exports.h +++ b/src/exports.h @@ -218,6 +218,10 @@ EXPORT(curl_version) EXPORT(curl_version_info) #endif /* EXPORT_LIBCURL_SYMBOLS */ EXPORT(datetime_pack) +EXPORT(datetime_asctime) +EXPORT(datetime_ctime) +EXPORT(datetime_now) +EXPORT(datetime_strftime) EXPORT(datetime_to_string) EXPORT(datetime_unpack) EXPORT(decimal_unpack) diff --git a/src/lib/core/datetime.c b/src/lib/core/datetime.c index 03facb123..a921cbd11 100755 --- a/src/lib/core/datetime.c +++ b/src/lib/core/datetime.c @@ -30,6 +30,7 @@ */ #include +#include #include "trivia/util.h" #include "datetime.h" @@ -165,12 +166,35 @@ mp_encode_datetime(char *data, const struct datetime *date) return datetime_pack(data, date); } +static int +local_dt(int64_t secs) +{ + return dt_from_rdn((int)(secs / SECS_PER_DAY) + DT_EPOCH_1970_OFFSET); +} + +static struct tm * +datetime_to_tm(const struct datetime *date) +{ + static struct tm tm; + + memset(&tm, 0, sizeof(tm)); + int64_t secs = date->secs; + dt_to_struct_tm(local_dt(secs), &tm); + + int seconds_of_day = date->secs % SECS_PER_DAY; + tm.tm_hour = (seconds_of_day / 3600) % 24; + tm.tm_min = (seconds_of_day / 60) % 60; + tm.tm_sec = seconds_of_day % 60; + + return &tm; +} + int datetime_to_string(const struct datetime *date, char *buf, uint32_t len) { char * src = buf; int offset = date->offset; int64_t secs = date->secs + offset * 60; - dt_t dt = dt_from_rdn((secs / SECS_PER_DAY) + 719163); + dt_t dt = local_dt(secs); int year, month, day, sec, ns, sign; dt_to_ymd(dt, &year, &month, &day); @@ -214,6 +238,43 @@ int datetime_to_string(const struct datetime *date, char *buf, uint32_t len) return (buf - src); } +void +datetime_now(struct datetime * now) +{ + struct timeval tv; + gettimeofday(&tv, NULL); + now->secs = tv.tv_sec; + now->nsec = tv.tv_usec * 1000; + + time_t now_seconds; + time(&now_seconds); + struct tm tm; + localtime_r(&now_seconds, &tm); + now->offset = tm.tm_gmtoff / 60; +} + +char * +datetime_asctime(const struct datetime *date) +{ + struct tm *p_tm = datetime_to_tm(date); + return asctime(p_tm); +} + +char * +datetime_ctime(const struct datetime *date) +{ + time_t time = date->secs; + return ctime(&time); +} + +size_t +datetime_strftime(const struct datetime *date, const char *fmt, char *buf, + uint32_t len) +{ + struct tm *p_tm = datetime_to_tm(date); + return strftime(buf, len, fmt, p_tm); +} + int mp_snprint_datetime(char *buf, int size, const char **data, uint32_t len) { diff --git a/src/lib/core/datetime.h b/src/lib/core/datetime.h index 540bd68d9..012fb340d 100644 --- a/src/lib/core/datetime.h +++ b/src/lib/core/datetime.h @@ -42,6 +42,7 @@ extern "C" #ifndef SECS_PER_DAY #define SECS_PER_DAY 86400 +#define DT_EPOCH_1970_OFFSET 719163 #endif /** @@ -102,7 +103,27 @@ mp_encode_datetime(char *data, const struct datetime *date); * @param buf output character buffer * @param len size ofoutput buffer */ -int datetime_to_string(const struct datetime *date, char *buf, uint32_t len); +int +datetime_to_string(const struct datetime *date, char *buf, uint32_t len); + +/** + * Convert datetime to string using default asctime format + * "Sun Sep 16 01:03:52 1973\n\0" + * @param date source datetime value + * @sa datetime_ctime + */ +char * +datetime_asctime(const struct datetime *date); + +char * +datetime_ctime(const struct datetime *date); + +size_t +datetime_strftime(const struct datetime *date, const char *fmt, char *buf, + uint32_t len); + +void +datetime_now(struct datetime * now); int mp_snprint_datetime(char *buf, int size, const char **data, uint32_t len); diff --git a/src/lua/datetime.lua b/src/lua/datetime.lua index 5cad4e02f..1549735bd 100644 --- a/src/lua/datetime.lua +++ b/src/lua/datetime.lua @@ -82,90 +82,18 @@ ffi.cdef [[ int datetime_to_string(const struct datetime * date, char *buf, uint32_t len); + char * + datetime_asctime(const struct datetime *date); - // - typedef long __kernel_long_t; - typedef unsigned long __kernel_ulong_t; - // /usr/include/x86_64-linux-gnu/bits/types/time_t.h - typedef long time_t; + char * + datetime_ctime(const struct datetime *date); + size_t + datetime_strftime(const struct datetime *date, const char *fmt, char *buf, + uint32_t len); - // - typedef __kernel_long_t __kernel_time_t; - typedef __kernel_long_t __kernel_suseconds_t; - - struct timespec { - __kernel_time_t tv_sec; /* seconds */ - long tv_nsec; /* nanoseconds */ - }; - - struct timeval { - __kernel_time_t tv_sec; /* seconds */ - __kernel_suseconds_t tv_usec; /* microseconds */ - }; - - struct timezone { - int tz_minuteswest; /* minutes west of Greenwich */ - int tz_dsttime; /* type of dst correction */ - }; - - // /usr/include/x86_64-linux-gnu/sys/time.h - typedef struct timezone * __timezone_ptr_t; - - /* Get the current time of day and timezone information, - putting it into *TV and *TZ. If TZ is NULL, *TZ is not filled. - Returns 0 on success, -1 on errors. - - NOTE: This form of timezone information is obsolete. - Use the functions and variables declared in instead. */ - int gettimeofday (struct timeval *__tv, struct timezone * __tz); - - // /usr/include/x86_64-linux-gnu/bits/types/struct_tm.h - /* ISO C `broken-down time' structure. */ - struct tm - { - int tm_sec; /* Seconds. [0-60] (1 leap second) */ - int tm_min; /* Minutes. [0-59] */ - int tm_hour; /* Hours. [0-23] */ - int tm_mday; /* Day. [1-31] */ - int tm_mon; /* Month. [0-11] */ - int tm_year; /* Year - 1900. */ - int tm_wday; /* Day of week. [0-6] */ - int tm_yday; /* Days in year.[0-365] */ - int tm_isdst; /* DST. [-1/0/1]*/ - - long int tm_gmtoff; /* Seconds east of UTC. */ - const char *tm_zone;/* Timezone abbreviation. */ - }; - - // - /* Return the current time and put it in *TIMER if TIMER is not NULL. */ - time_t time (time_t *__timer); - - /* Format TP into S according to FORMAT. - Write no more than MAXSIZE characters and return the number - of characters written, or 0 if it would exceed MAXSIZE. */ - size_t strftime (char * __s, size_t __maxsize, const char * __format, - const struct tm * __tp); - - /* Parse S according to FORMAT and store binary time information in TP. - The return value is a pointer to the first unparsed character in S. */ - char *strptime (const char * __s, const char * __fmt, struct tm *__tp); - - /* Return the `struct tm' representation of *TIMER in UTC, - using *TP to store the result. */ - struct tm *gmtime_r (const time_t * __timer, struct tm * __tp); - - /* Return the `struct tm' representation of *TIMER in local time, - using *TP to store the result. */ - struct tm *localtime_r (const time_t * __timer, struct tm * __tp); - - /* Return a string of the form "Day Mon dd hh:mm:ss yyyy\n" - that is the representation of TP in this format. */ - char *asctime (const struct tm *__tp); - - /* Equivalent to `asctime (localtime (timer))'. */ - char *ctime (const time_t *__timer); + void + datetime_now(struct datetime * now); ]] @@ -921,62 +849,27 @@ local function datetime_from(o) end local function local_now() - local p_tv = ffi.new('struct timeval [1]') - local rc = builtin.gettimeofday(p_tv, nil) - assert(rc == 0) - - local secs = p_tv[0].tv_sec - local nsec = p_tv[0].tv_usec * 1000 - - local p_time = ffi.new('time_t[1]') - local p_tm = ffi.new('struct tm[1]') - builtin.time(p_time) - builtin.localtime_r(p_time, p_tm) - local ofs = p_tm[0].tm_gmtoff / 60 -- convert seconds to minutes - - return datetime_new_raw(secs, nsec, ofs) -end - -local function datetime_to_tm_ptr(o) - assert(is_datetime(o)) - local p_tm = ffi.new('struct tm[1]') - -- dt_to_struct_tm() fills only date data - builtin.dt_to_struct_tm(local_dt(o), p_tm) - - -- calculate the smaller data (hour, minute, - -- seconds) using datetime seconds value - local seconds_of_day = o.secs % 86400 - local hour = (seconds_of_day / 3600) % 24 - local minute = (seconds_of_day / 60) % 60 - p_tm[0].tm_sec = seconds_of_day % 60 - p_tm[0].tm_min = minute - p_tm[0].tm_hour = hour - - p_tm[0].tm_gmtoff = o.offset * 60 - - return p_tm + local d = datetime_new_raw(0, 0, 0) + builtin.datetime_now(d) + return d end local function asctime(o) check_date(o, "datetime:asctime()") - local p_tm = datetime_to_tm_ptr(o) - return ffi.string(builtin.asctime(p_tm)) + return ffi.string(builtin.datetime_asctime(o)) end local function ctime(o) check_date(o, "datetime:ctime()") - local p_time = ffi.new('time_t[1]') - p_time[0] = o.secs - return ffi.string(builtin.ctime(p_time)) + return ffi.string(builtin.datetime_ctime(o)) end local function strftime(fmt, o) check_date(o, "datetime.strftime()") - local p_tm = datetime_to_tm_ptr(o) - local sz = builtin.strftime(nil, 1024, fmt, p_tm) + 1 + local sz = 128 local buff = ffi.new('char[?]', sz) - builtin.strftime(buff, sz, fmt, p_tm) + builtin.datetime_strftime(o, fmt, buff, sz) return ffi.string(buff) end -- 2.29.2