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