From: Timur Safin via Tarantool-patches <tarantool-patches@dev.tarantool.org> To: v.shpilevoy@tarantool.org, olegrok@tarantool.org Cc: tarantool-patches@dev.tarantool.org Subject: [Tarantool-patches] [PATCH v3 2/2] lua, datetime: introduce ctime, strftime wrappers Date: Wed, 4 Aug 2021 00:23:50 +0300 [thread overview] Message-ID: <5817f15e9db569675ce595cfd63a03bab1875c3c.1628025689.git.tsafin@tarantool.org> (raw) In-Reply-To: <cover.1627864075.git.tsafin@tarantool.org> 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 <string.h> +#include <time.h> #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); - // <asm-generic/posix_types.h> - 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); - // <time.h> - 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 <time.h> 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. */ - }; - - // <time.h> - /* 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
next prev parent reply other threads:[~2021-08-03 21:24 UTC|newest] Thread overview: 38+ messages / expand[flat|nested] mbox.gz Atom feed top 2021-08-02 0:40 [Tarantool-patches] [PATCH v3 0/9] Initial datetime support Timur Safin via Tarantool-patches 2021-08-02 0:40 ` [Tarantool-patches] [PATCH v3 1/9] build: add Christian Hansen c-dt to the build Timur Safin via Tarantool-patches 2021-08-04 23:58 ` Vladislav Shpilevoy via Tarantool-patches 2021-08-05 8:55 ` Safin Timur via Tarantool-patches 2021-08-08 14:34 ` Vladislav Shpilevoy via Tarantool-patches 2021-08-02 0:40 ` [Tarantool-patches] [PATCH v3 2/9] lua: built-in module datetime Timur Safin via Tarantool-patches 2021-08-04 23:58 ` Vladislav Shpilevoy via Tarantool-patches 2021-08-06 0:23 ` Safin Timur via Tarantool-patches 2021-08-06 1:30 ` Oleg Babin via Tarantool-patches 2021-08-06 13:00 ` Safin Timur via Tarantool-patches 2021-08-06 17:24 ` Safin Timur via Tarantool-patches 2021-08-08 11:26 ` Vladislav Shpilevoy via Tarantool-patches 2021-08-08 16:35 ` Safin Timur via Tarantool-patches 2021-08-10 12:20 ` Vladislav Shpilevoy via Tarantool-patches 2021-08-10 12:21 ` Igor Munkin via Tarantool-patches 2021-08-12 20:47 ` Safin Timur via Tarantool-patches 2021-08-15 20:52 ` Safin Timur via Tarantool-patches 2021-08-06 0:26 ` Safin Timur via Tarantool-patches 2021-08-08 14:34 ` Vladislav Shpilevoy via Tarantool-patches 2021-08-08 16:47 ` Safin Timur via Tarantool-patches 2021-08-02 0:40 ` [Tarantool-patches] [PATCH v3 3/9] lua, datetime: datetime tests Timur Safin via Tarantool-patches 2021-08-06 0:25 ` Safin Timur via Tarantool-patches 2021-08-02 0:41 ` [Tarantool-patches] [PATCH v3 4/9] lua, datetime: display datetime Timur Safin via Tarantool-patches 2021-08-02 0:41 ` [Tarantool-patches] [PATCH v3 5/9] box, datetime: messagepack support for datetime Timur Safin via Tarantool-patches 2021-08-03 13:38 ` Timur Safin via Tarantool-patches 2021-08-02 0:41 ` [Tarantool-patches] [PATCH v3 6/9] box, datetime: datetime comparison for indices Timur Safin via Tarantool-patches 2021-08-03 12:02 ` Serge Petrenko via Tarantool-patches 2021-08-03 12:59 ` Timur Safin via Tarantool-patches 2021-08-04 10:12 ` Timur Safin via Tarantool-patches 2021-08-02 0:41 ` [Tarantool-patches] [PATCH v3 7/9] lua, datetime: time intervals support Timur Safin via Tarantool-patches 2021-08-02 0:41 ` [Tarantool-patches] [PATCH v3 8/9] datetime: changelog for datetime module Timur Safin via Tarantool-patches 2021-08-02 0:41 ` [Tarantool-patches] [PATCH v3 9/9] lua, box, datetime: rename struct datetime_t Timur Safin via Tarantool-patches 2021-08-06 0:27 ` Safin Timur via Tarantool-patches 2021-08-03 21:23 ` [Tarantool-patches] [PATCH v3 1/2] datetime: update tests for macosx Timur Safin via Tarantool-patches 2021-08-06 0:28 ` Safin Timur via Tarantool-patches 2021-08-03 21:23 ` Timur Safin via Tarantool-patches [this message] 2021-08-06 0:30 ` [Tarantool-patches] [PATCH v3 2/2] lua, datetime: introduce ctime, strftime wrappers Safin Timur via Tarantool-patches 2021-08-03 21:26 ` [Tarantool-patches] [PATCH v3 0/9] Initial datetime support Timur Safin via Tarantool-patches
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=5817f15e9db569675ce595cfd63a03bab1875c3c.1628025689.git.tsafin@tarantool.org \ --to=tarantool-patches@dev.tarantool.org \ --cc=olegrok@tarantool.org \ --cc=tsafin@tarantool.org \ --cc=v.shpilevoy@tarantool.org \ --subject='Re: [Tarantool-patches] [PATCH v3 2/2] lua, datetime: introduce ctime, strftime wrappers' \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox