Tarantool development patches archive
 help / color / mirror / Atom feed
From: Safin Timur via Tarantool-patches <tarantool-patches@dev.tarantool.org>
To: v.shpilevoy@tarantool.org, olegrok@tarantool.org
Cc: tarantool-patches@dev.tarantool.org
Subject: Re: [Tarantool-patches] [PATCH v3 2/2] lua, datetime: introduce ctime, strftime wrappers
Date: Fri, 6 Aug 2021 03:30:05 +0300	[thread overview]
Message-ID: <ef0b61bb-80d1-ff84-7620-cdcd3eb75dbb@tarantool.org> (raw)
In-Reply-To: <5817f15e9db569675ce595cfd63a03bab1875c3c.1628025689.git.tsafin@tarantool.org>

This change is now part of patch 2/9 lua:built-in module datetime, and 
there is no platform specific Lua code in the module.

Timur

On 04.08.2021 0:23, Timur Safin wrote:
> 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
>   
> 

  reply	other threads:[~2021-08-06  0:30 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 ` [Tarantool-patches] [PATCH v3 2/2] lua, datetime: introduce ctime, strftime wrappers Timur Safin via Tarantool-patches
2021-08-06  0:30   ` Safin Timur via Tarantool-patches [this message]
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=ef0b61bb-80d1-ff84-7620-cdcd3eb75dbb@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