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 7/9] lua, datetime: time intervals support Date: Mon, 2 Aug 2021 03:41:03 +0300 [thread overview] Message-ID: <edcb151885365d80297d05aaae894c93288848ed.1627864075.git.tsafin@tarantool.org> (raw) In-Reply-To: <cover.1627864075.git.tsafin@tarantool.org> * created few entry points (months(N), years(N), days(N), etc.) for easier datetime arithmetic; * additions/subtractions of years/months use `dt_add_years()` and `dt_add_months()` from 3rd party c-dt library; * also there are `:add{}` and `:sub{}` methods in datetime object to add or substract more complex intervals; * introduced `is_datetime()` and `is_interval()` helpers for checking of validity of passed arguments; * human-readable stringization implemented for interval objects. Note, that additions/subtractions completed for all _reasonable_ combinations of values of date and interval types; Time + Interval => Time Interval + Time => Time Time - Time => Interval Time - Interval => Time Interval + Interval => Interval Interval - Interval => Interval Part of #5941 --- src/exports.h | 5 + src/lua/datetime.lua | 276 ++++++++++++++++++++++++++++++++- test/app-tap/datetime.test.lua | 163 ++++++++++++++++++- 3 files changed, 436 insertions(+), 8 deletions(-) diff --git a/src/exports.h b/src/exports.h index 7ac2cd012..63efe0ec7 100644 --- a/src/exports.h +++ b/src/exports.h @@ -217,8 +217,13 @@ EXPORT(curl_url_set) EXPORT(curl_version) EXPORT(curl_version_info) #endif /* EXPORT_LIBCURL_SYMBOLS */ +EXPORT(datetime_pack) EXPORT(datetime_to_string) +EXPORT(datetime_unpack) EXPORT(decimal_unpack) +EXPORT(dt_add_months) +EXPORT(dt_add_quarters) +EXPORT(dt_add_years) EXPORT(dt_dow) EXPORT(dt_from_rdn) EXPORT(dt_from_struct_tm) diff --git a/src/lua/datetime.lua b/src/lua/datetime.lua index e5b89768f..dc88a9d9d 100644 --- a/src/lua/datetime.lua +++ b/src/lua/datetime.lua @@ -50,6 +50,17 @@ ffi.cdef [[ int dt_rdn (dt_t dt); dt_dow_t dt_dow (dt_t dt); + // dt_arithmetic.h + typedef enum { + DT_EXCESS, + DT_LIMIT, + DT_SNAP + } dt_adjust_t; + + dt_t dt_add_years (dt_t dt, int delta, dt_adjust_t adjust); + dt_t dt_add_quarters (dt_t dt, int delta, dt_adjust_t adjust); + dt_t dt_add_months (dt_t dt, int delta, dt_adjust_t adjust); + // dt_parse_iso.h size_t dt_parse_iso_date (const char *str, size_t len, dt_t *dt); @@ -171,9 +182,23 @@ local DT_EPOCH_1970_OFFSET = 719163LL local datetime_t = ffi.typeof('struct datetime_t') local interval_t = ffi.typeof('struct datetime_interval_t') +ffi.cdef [[ + struct t_interval_months { + int m; + }; + + struct t_interval_years { + int y; + }; +]] +local interval_months_t = ffi.typeof('struct t_interval_months') +local interval_years_t = ffi.typeof('struct t_interval_years') local function is_interval(o) - return type(o) == 'cdata' and ffi.istype(interval_t, o) + return type(o) == 'cdata' and + (ffi.istype(interval_t, o) or + ffi.istype(interval_months_t, o) or + ffi.istype(interval_years_t, o)) end local function is_datetime(o) @@ -189,6 +214,16 @@ local function interval_new() return interval end +local function check_number(n, message, lvl) + if lvl == nil then + lvl = 2 + end + if type(n) ~= 'number' then + return error(("%s: expected number, but received %s"): + format(message, n), lvl) + end +end + local function check_date(o, message, lvl) if lvl == nil then lvl = 2 @@ -229,6 +264,56 @@ local function check_str(s, message, lvl) end end +local function interval_years_new(y) + check_number(y, "years(number)") + local o = ffi.new(interval_years_t) + o.y = y + return o +end + +local function interval_months_new(m) + check_number(m, "months(number)") + local o = ffi.new(interval_months_t) + o.m = m + return o +end + +local function interval_weeks_new(w) + check_number(w, "weeks(number)") + local o = ffi.new(interval_t) + o.secs = w * SECS_PER_DAY * 7 + return o +end + +local function interval_days_new(d) + check_number(d, "days(number)") + local o = ffi.new(interval_t) + o.secs = d * SECS_PER_DAY + return o +end + +local function interval_hours_new(h) + check_number(h, "hours(number)") + local o = ffi.new(interval_t) + o.secs = h * 60 * 60 + return o +end + +local function interval_minutes_new(m) + check_number(m, "minutes(number)") + local o = ffi.new(interval_t) + o.secs = m * 60 + return o +end + +local function interval_seconds_new(s) + check_number(s, "seconds(number)") + local o = ffi.new(interval_t) + o.nsec = s % 1 * 1e9 + o.secs = s - (s % 1) + return o +end + local function datetime_cmp(lhs, rhs) if not is_date_interval(lhs) or not is_date_interval(rhs) then @@ -290,6 +375,88 @@ local function check_range(v, range, txt) end end +-- addition or subtraction from date/time of a given interval +-- described via table direction should be +1 or -1 +local function interval_increment(self, o, direction) + assert(direction == -1 or direction == 1) + local title = direction > 0 and "datetime.add" or "datetime.sub" + check_date(self, title) + if type(o) ~= 'table' then + error(('%s - object expected'):format(title), 2) + end + + local ym_updated = false + local dhms_updated = false + + local dt = local_dt(self) + local secs, nsec + secs, nsec = self.secs, self.nsec + + local handlers = { + years = function(k, v) + check_range(v, {0, 9999}, k) + dt = builtin.dt_add_years(dt, direction * v, builtin.DT_LIMIT) + ym_updated = true + end, + + months = function(k, v) + check_range(v, {0, 12}, k) + dt = builtin.dt_add_months(dt, direction * v, builtin.DT_LIMIT) + ym_updated = true + end, + + weeks = function(k, v) + check_range(v, {0, 52}, k) + secs = secs + direction * 7 * v * SECS_PER_DAY + dhms_updated = true + end, + + days = function(k, v) + check_range(v, {0, 31}, k) + secs = secs + direction * v * SECS_PER_DAY + dhms_updated = true + end, + + hours = function(k, v) + check_range(v, {0, 23}, k) + secs = secs + direction * 60 * 60 * v + dhms_updated = true + end, + + minutes = function(k, v) + check_range(v, {0, 59}, k) + secs = secs + direction * 60 * v + end, + + seconds = function(k, v) + check_range(v, {0, 60}, k) + local s, frac = math.modf(v) + secs = secs + direction * s + nsec = nsec + direction * frac * 1e9 + dhms_updated = true + end, + } + for key, value in pairs(o) do + handlers[key](key, value) + end + + secs, nsec = _normalize_nsec(secs, nsec) + + -- .days, .hours, .minutes, .seconds + if dhms_updated then + self.secs = secs + self.nsec = nsec + end + + -- .years, .months updated + if ym_updated then + self.secs = (builtin.dt_rdn(dt) - DT_EPOCH_1970_OFFSET) * SECS_PER_DAY + + secs % SECS_PER_DAY + end + + return self +end + local datetime_index_handlers = { unixtime = function(self) return self.secs @@ -326,6 +493,18 @@ local datetime_index_handlers = { days = function(self) return (tonumber(self.secs) + self.nsec / 1e9) / (60 * 60) / 24 end, + + add = function(self) + return function(self, o) + return interval_increment(self, o, 1) + end + end, + + sub = function(self) + return function(self, o) + return interval_increment(self, o, -1) + end + end, } local datetime_index = function(self, key) @@ -480,6 +659,10 @@ local function datetime_tostring(o) local len = builtin.datetime_to_string(o, buff, sz) assert(len < sz) return ffi.string(buff) + elseif ffi.typeof(o) == interval_years_t then + return ('%+d years'):format(o.y) + elseif ffi.typeof(o) == interval_months_t then + return ('%+d months'):format(o.m) elseif ffi.typeof(o) == interval_t then local ts = o.timestamp local sign = '+' @@ -510,12 +693,20 @@ local function date_first(lhs, rhs) return rhs, lhs end end - local function error_incompatible(name) error(("datetime:%s() - incompatible type of arguments"): format(name), 3) end - +--[[ +Matrix of subtraction operands eligibility and their result type + +| | datetime | interval | interval_months | interval_years | ++-----------------+-----------+----------+-----------------+----------------+ +| datetime | interval | datetime | datetime | datetime | +| interval | | interval | | | +| interval_months | | | interval_months | | +| interval_years | | | | interval_years | +]] local function datetime_sub(lhs, rhs) check_date_interval(lhs, "operator -") local d, s = lhs, rhs @@ -524,26 +715,53 @@ local function datetime_sub(lhs, rhs) local o if left_t == datetime_t then - -- left is date, right is date or generic interval + -- 1. left is date, right is date or generic interval if (right_t == datetime_t or right_t == interval_t) then o = right_t == datetime_t and interval_new() or datetime_new() o.secs, o.nsec = _normalize_nsec(lhs.secs - rhs.secs, lhs.nsec - rhs.nsec) return o + -- 2. left is date, right is interval in months + elseif right_t == interval_months_t then + local dt = builtin.dt_add_months(local_dt(lhs), -rhs.m, builtin.DT_LIMIT) + return mk_timestamp(dt, lhs.secs % SECS_PER_DAY, + lhs.nsec, lhs.offset) + + -- 3. left is date, right is interval in years + elseif right_t == interval_years_t then + local dt = builtin.dt_add_years(local_dt(lhs), -rhs.y, builtin.DT_LIMIT) + return mk_timestamp(dt, lhs.secs % SECS_PER_DAY, + lhs.nsec, lhs.offset) else error_incompatible("operator -") end - -- both left and right are generic intervals + -- 4. both left and right are generic intervals elseif left_t == interval_t and right_t == interval_t then o = interval_new() o.secs, o.nsec = _normalize_nsec(lhs.secs - rhs.secs, lhs.nsec - rhs.nsec) return o + -- 5. both left and right are intervals in months + elseif left_t == interval_months_t and right_t == interval_months_t then + return interval_months_new(lhs.m - rhs.m) + -- 5. both left and right are intervals in years + elseif left_t == interval_years_t and right_t == interval_years_t then + return interval_years_new(lhs.y - rhs.y) else error_incompatible("operator -") end end +--[[ +Matrix of addition operands eligibility and their result type + +| | datetime | interval | interval_months | interval_years | ++-----------------+-----------+----------+-----------------+----------------+ +| datetime | datetime | datetime | datetime | datetime | +| interval | datetime | interval | | | +| interval_months | datetime | | interval_months | | +| interval_years | datetime | | | interval_years | +]] local function datetime_add(lhs, rhs) local d, s = date_first(lhs, rhs) @@ -553,16 +771,33 @@ local function datetime_add(lhs, rhs) local right_t = ffi.typeof(s) local o - -- left is date, right is date or interval + -- 1. left is date, right is date or interval if left_t == datetime_t and right_t == interval_t then o = datetime_new() o.secs, o.nsec = _normalize_nsec(d.secs + s.secs, d.nsec + s.nsec) return o - -- both left and right are generic intervals + -- 2. left is date, right is interval in months + elseif left_t == datetime_t and right_t == interval_months_t then + local dt = builtin.dt_add_months(local_dt(d), s.m, builtin.DT_LIMIT) + local secs = d.secs % SECS_PER_DAY + return mk_timestamp(dt, secs, d.nsec, d.offset or 0) + + -- 3. left is date, right is interval in years + elseif left_t == datetime_t and right_t == interval_years_t then + local dt = builtin.dt_add_years(local_dt(d), s.y, builtin.DT_LIMIT) + local secs = d.secs % SECS_PER_DAY + return mk_timestamp(dt, secs, d.nsec, d.offset or 0) + -- 4. both left and right are generic intervals elseif left_t == interval_t and right_t == interval_t then o = interval_new() o.secs, o.nsec = _normalize_nsec(d.secs + s.secs, d.nsec + s.nsec) return o + -- 5. both left and right are intervals in months + elseif left_t == interval_months_t and right_t == interval_months_t then + return interval_months_new(d.m + s.m) + -- 6. both left and right are intervals in years + elseif left_t == interval_years_t and right_t == interval_years_t then + return interval_years_new(d.y + s.y) else error_incompatible("operator +") end @@ -755,6 +990,16 @@ local datetime_mt = { __add = datetime_add, __index = datetime_index, __newindex = datetime_newindex, + + add = function(self, o) + self = interval_increment(self, o, 1) + return self + end, + + sub = function(self, o) + self = interval_increment(self, o, -1) + return self + end } local interval_mt = { @@ -768,12 +1013,29 @@ local interval_mt = { __index = datetime_index, } +local interval_tiny_mt = { + __tostring = datetime_tostring, + __serialize = interval_serialize, + __sub = datetime_sub, + __add = datetime_add, + __index = datetime_index, +} + ffi.metatype(interval_t, interval_mt) ffi.metatype(datetime_t, datetime_mt) +ffi.metatype(interval_years_t, interval_tiny_mt) +ffi.metatype(interval_months_t, interval_tiny_mt) return setmetatable( { new = datetime_new, + years = interval_years_new, + months = interval_months_new, + weeks = interval_weeks_new, + days = interval_days_new, + hours = interval_hours_new, + minutes = interval_minutes_new, + seconds = interval_seconds_new, interval = interval_new, parse = parse, diff --git a/test/app-tap/datetime.test.lua b/test/app-tap/datetime.test.lua index f7541567e..678de7311 100755 --- a/test/app-tap/datetime.test.lua +++ b/test/app-tap/datetime.test.lua @@ -6,7 +6,7 @@ local date = require('datetime') local ffi = require('ffi') -test:plan(6) +test:plan(10) test:test("Simple tests for parser", function(test) test:plan(2) @@ -203,4 +203,165 @@ test:test("Parse tiny date into seconds and other parts", function(test) test:ok(tiny.hours == 0.00848, "hours") end) +test:test("Stringization of dates and intervals", function(test) + test:plan(13) + local str = '19700101Z' + local dt = date(str) + test:ok(tostring(dt) == '1970-01-01T00:00Z', ('tostring(%s)'):format(str)) + test:ok(tostring(date.seconds(12)) == '+12 secs', '+12 seconds') + test:ok(tostring(date.seconds(-12)) == '-12 secs', '-12 seconds') + test:ok(tostring(date.minutes(12)) == '+12 minutes, 0 seconds', '+12 minutes') + test:ok(tostring(date.minutes(-12)) == '-12 minutes, 0 seconds', '-12 minutes') + test:ok(tostring(date.hours(12)) == '+12 hours, 0 minutes, 0 seconds', + '+12 hours') + test:ok(tostring(date.hours(-12)) == '-12 hours, 0 minutes, 0 seconds', + '-12 hours') + test:ok(tostring(date.days(12)) == '+12 days, 0 hours, 0 minutes, 0 seconds', + '+12 days') + test:ok(tostring(date.days(-12)) == '-12 days, 0 hours, 0 minutes, 0 seconds', + '-12 days') + test:ok(tostring(date.months(5)) == '+5 months', '+5 months') + test:ok(tostring(date.months(-5)) == '-5 months', '-5 months') + test:ok(tostring(date.years(4)) == '+4 years', '+4 years') + test:ok(tostring(date.years(-4)) == '-4 years', '-4 years') +end) + +test:test("Time interval operations", function(test) + test:plan(12) + + -- check arithmetic with leap dates + local T = date('1972-02-29') + local M = date.months(2) + local Y = date.years(1) + test:ok(tostring(T + M) == '1972-04-29T00:00Z', ('T(%s) + M(%s'):format(T, M)) + test:ok(tostring(T + Y) == '1973-03-01T00:00Z', ('T(%s) + Y(%s'):format(T, Y)) + test:ok(tostring(T + M + Y) == '1973-04-30T00:00Z', + ('T(%s) + M(%s) + Y(%s'):format(T, M, Y)) + test:ok(tostring(T + Y + M) == '1973-05-01T00:00Z', + ('T(%s) + M(%s) + Y(%s'):format(T, M, Y)) + test:ok(tostring(T:add{years = 1, months = 2}) == '1973-04-30T00:00Z', + ('T:add{years=1,months=2}(%s)'):format(T)) + + -- check average, not leap dates + T = date('1970-01-08') + test:ok(tostring(T + M) == '1970-03-08T00:00Z', ('T(%s) + M(%s'):format(T, M)) + test:ok(tostring(T + Y) == '1971-01-08T00:00Z', ('T(%s) + Y(%s'):format(T, Y)) + test:ok(tostring(T + M + Y) == '1971-03-08T00:00Z', + ('T(%s) + M(%s) + Y(%s'):format(T, M, Y)) + test:ok(tostring(T + Y + M) == '1971-03-08T00:00Z', + ('T(%s) + Y(%s) + M(%s'):format(T, Y, M)) + test:ok(tostring(T:add{years = 1, months = 2}) == '1971-03-08T00:00Z', + ('T:add{years=1,months=2}(%s)'):format(T)) + + + -- subtraction of 2 dates + local T2 = date('19700103') + local T1 = date('1970-01-01') + test:ok(tostring(T2 - T1) == '+2 days, 0 hours, 0 minutes, 0 seconds', + ('T2(%s) - T1(%s'):format(T2, T1)) + test:ok(tostring(T1 - T2) == '-2 days, 0 hours, 0 minutes, 0 seconds', + ('T2(%s) - T1(%s'):format(T2, T1)) +end) + +local function catchadd(A, B) + return pcall(function() return A + B end) +end + +--[[ +Matrix of addition operands eligibility and their result type + +| | datetime | interval | interval_months | interval_years | ++-----------------+-----------+----------+-----------------+----------------+ +| datetime | datetime | datetime | datetime | datetime | +| interval | datetime | interval | | | +| interval_months | datetime | | interval_months | | +| interval_years | datetime | | | interval_years | +]] + +test:test("Matrix of allowed time and interval additions", function(test) + test:plan(20) + + -- check arithmetic with leap dates + local T1970 = date('1970-01-01') + local T2000 = date('2000-01-01') + local I1 = date.days(1) + local M2 = date.months(2) + local M10 = date.months(10) + local Y1 = date.years(1) + local Y5 = date.years(5) + + test:ok(catchadd(T1970, I1) == true, "status: T + I") + test:ok(catchadd(T1970, M2) == true, "status: T + M") + test:ok(catchadd(T1970, Y1) == true, "status: T + Y") + test:ok(catchadd(T1970, T2000) == false, "status: T + T") + test:ok(catchadd(I1, T1970) == true, "status: I + T") + test:ok(catchadd(M2, T1970) == true, "status: M + T") + test:ok(catchadd(Y1, T1970) == true, "status: Y + T") + test:ok(catchadd(I1, Y1) == false, "status: I + Y") + test:ok(catchadd(M2, Y1) == false, "status: M + Y") + test:ok(catchadd(I1, Y1) == false, "status: I + Y") + test:ok(catchadd(Y5, M10) == false, "status: Y + M") + test:ok(catchadd(Y5, I1) == false, "status: Y + I") + test:ok(catchadd(Y5, Y1) == true, "status: Y + Y") + + test:ok(tostring(T1970 + I1) == "1970-01-02T00:00Z", "value: T + I") + test:ok(tostring(T1970 + M2) == "1970-03-01T00:00Z", "value: T + M") + test:ok(tostring(T1970 + Y1) == "1971-01-01T00:00Z", "value: T + Y") + test:ok(tostring(I1 + T1970) == "1970-01-02T00:00Z", "value: I + T") + test:ok(tostring(M2 + T1970) == "1970-03-01T00:00Z", "value: M + T") + test:ok(tostring(Y1 + T1970) == "1971-01-01T00:00Z", "value: Y + T") + test:ok(tostring(Y5 + Y1) == "+6 years", "Y + Y") + +end) + +local function catchsub_status(A, B) + return pcall(function() return A - B end) +end + +--[[ +Matrix of subtraction operands eligibility and their result type + +| | datetime | interval | interval_months | interval_years | ++-----------------+-----------+----------+-----------------+----------------+ +| datetime | interval | datetime | datetime | datetime | +| interval | | interval | | | +| interval_months | | | interval_months | | +| interval_years | | | | interval_years | +]] +test:test("Matrix of allowed time and interval subtractions", function(test) + test:plan(18) + + -- check arithmetic with leap dates + local T1970 = date('1970-01-01') + local T2000 = date('2000-01-01') + local I1 = date.days(1) + local M2 = date.months(2) + local M10 = date.months(10) + local Y1 = date.years(1) + local Y5 = date.years(5) + + test:ok(catchsub_status(T1970, I1) == true, "status: T - I") + test:ok(catchsub_status(T1970, M2) == true, "status: T - M") + test:ok(catchsub_status(T1970, Y1) == true, "status: T - Y") + test:ok(catchsub_status(T1970, T2000) == true, "status: T - T") + test:ok(catchsub_status(I1, T1970) == false, "status: I + T") + test:ok(catchsub_status(M2, T1970) == false, "status: M + T") + test:ok(catchsub_status(Y1, T1970) == false, "status: Y + T") + test:ok(catchsub_status(I1, Y1) == false, "status: I - Y") + test:ok(catchsub_status(M2, Y1) == false, "status: M - Y") + test:ok(catchsub_status(I1, Y1) == false, "status: I - Y") + test:ok(catchsub_status(Y5, M10) == false, "status: Y - M") + test:ok(catchsub_status(Y5, I1) == false, "status: Y - I") + test:ok(catchsub_status(Y5, Y1) == true, "status: Y - Y") + + test:ok(tostring(T1970 - I1) == "1969-12-31T00:00Z", "value: T - I") + test:ok(tostring(T1970 - M2) == "1969-11-01T00:00Z", "value: T - M") + test:ok(tostring(T1970 - Y1) == "1969-01-01T00:00Z", "value: T - Y") + test:ok(tostring(T1970 - T2000) == "-10957 days, 0 hours, 0 minutes, 0 seconds", + "value: T - T") + test:ok(tostring(Y5 - Y1) == "+4 years", "value: Y - Y") + + +end) + os.exit(test:check() and 0 or 1) -- 2.29.2
next prev parent reply other threads:[~2021-08-02 0:45 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 ` Timur Safin via Tarantool-patches [this message] 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 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=edcb151885365d80297d05aaae894c93288848ed.1627864075.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 7/9] lua, datetime: time intervals support' \ /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