<HTML><BODY><div><div>Hi!</div><div> </div><div>I looked trhough the patchset.</div><div> </div><div>I also compiled the bracnch and tested by hand.</div><div> </div><div>Example:</div><div> </div><div><div><span style="font-family:"Andale Mono","Lucida Console",Monaco,monospace;">tarantool> datetime = require('datetime')<br>---<br>...</span></div><div><span style="font-family:"Andale Mono","Lucida Console",Monaco,monospace;">tarantool> datetime.new('2020-01-02 02:00')<br>---<br>- 1970-01-01T00:00Z<br>...</span></div><div><span style="font-family:"Andale Mono","Lucida Console",Monaco,monospace;">tarantool> datetime.new('2020-01-02 02:00+0300')<br>---<br>- 1970-01-01T00:00Z<br>...</span></div><div><span style="font-family:"Andale Mono","Lucida Console",Monaco,monospace;">tarantool> datetime.new('2020-01-02 02:00:11+0300')<br>---<br>- 1970-01-01T00:00Z<br>...</span></div><div><span style="font-family:"Andale Mono","Lucida Console",Monaco,monospace;">tarantool> datetime.new('2020-01-02T02:00:11+0300')<br>---<br>- 1970-01-01T00:00Z<br>...</span></div><div> </div><div> </div><div>The code looks like as broken.</div><div> </div><div>Also my notes:</div><div> </div><ol><li>tostring has to return datetime string with seconds and timezone</li><li>also the other databases try to avoid to use «Z» symbol in datetime-format, so I thing we should use «+00:00» instead «Z»</li></ol><div> </div><div>Yesterday we approved the following API:</div><div> </div><div><span style="font-family:"Andale Mono","Lucida Console",Monaco,monospace;">T:add{year=XXX, month=YYY, ...}</span></div><div><span style="font-family:"Andale Mono","Lucida Console",Monaco,monospace;">T:sub{year=XXX, month=YYY, ...}</span></div><div><span style="font-family:"Andale Mono","Lucida Console",Monaco,monospace;">T:set{year=XXX, …, tz=’+03:00’}<br>T:strftime(‘%F %D %z’)</span></div><div> </div><div>I want to see a test set for the API.<br><br>Also we approved the following methods:</div><div> </div><span style="font-family:"Andale Mono","Lucida Console",Monaco,monospace;">T:sec() — 35</span><div><span style="font-family:"Andale Mono","Lucida Console",Monaco,monospace;">T:min() — 12<br>T:day() — 19<br>T:wday() — 5<br>T:yday() — 231<br>T:year() — 2021<br>T:month() — 8<br>T:hour() — 23</span></div><div><span style="font-family:"Andale Mono","Lucida Console",Monaco,monospace;">T:tz() — ‘+03:00’</span></div><div> </div><div>It would be nice to see test set for each of the functions.</div><div> </div><div>Also it would be nice to rename ambigouos items «secs» to «epoch» or «timestamp»</div><div>Datetime object must have methods to return integer and float timestamp:</div><div> </div><div><span style="font-family:"Andale Mono","Lucida Console",Monaco,monospace;">T:epoch()</span></div><div><span style="font-family:"Andale Mono","Lucida Console",Monaco,monospace;">T:timestamp()</span></div><div> </div></div><blockquote style="border-left:1px solid #0857A6; margin:10px; padding:0 0 0 10px;">Четверг, 19 августа 2021, 5:58 +03:00 от Timur Safin via Tarantool-patches <tarantool-patches@dev.tarantool.org>:<br> <div id=""><div class="js-helper js-readmsg-msg"><div><div id="style_16293419320499136407_BODY">* storage hints implemented for datetime_t values;<br>* proper comparison for indices of datetime type.<br><br>Part of #5941<br>Part of #5946<br><br>@TarantoolBot document<br><br>Title: Storage support for datetime values<br><br>It's now possible to store datetime values in spaces and create<br>indexed datetime fields.<br><br>Please refer to <a href="https://github.com/tarantool/tarantool/discussions/6244" target="_blank">https://github.com/tarantool/tarantool/discussions/6244</a><br>for more detailed description of a storage schema.<br>---<br> src/box/field_def.c | 35 +++++++++-------<br> src/box/field_def.h | 1 +<br> src/box/tuple_compare.cc | 77 +++++++++++++++++++++++++++++++++++<br> src/lib/core/datetime.c | 9 ++++<br> src/lib/core/datetime.h | 11 +++++<br> test/engine/datetime.result | 77 +++++++++++++++++++++++++++++++++++<br> test/engine/datetime.test.lua | 35 ++++++++++++++++<br> test/unit/datetime.c | 3 +-<br> 8 files changed, 232 insertions(+), 16 deletions(-)<br> create mode 100644 test/engine/datetime.result<br> create mode 100644 test/engine/datetime.test.lua<br><br>diff --git a/src/box/field_def.c b/src/box/field_def.c<br>index 51acb8025..cd5db942e 100644<br>--- a/src/box/field_def.c<br>+++ b/src/box/field_def.c<br>@@ -70,6 +70,7 @@ const uint32_t field_mp_type[] = {<br> (1U << MP_BIN) | (1U << MP_BOOL),<br> /* [FIELD_TYPE_DECIMAL] = */ 0, /* only MP_DECIMAL is supported */<br> /* [FIELD_TYPE_UUID] = */ 0, /* only MP_UUID is supported */<br>+ /* [FIELD_TYPE_DATETIME] = */ 0, /* only MP_DATETIME is supported */<br> /* [FIELD_TYPE_ARRAY] = */ 1U << MP_ARRAY,<br> /* [FIELD_TYPE_MAP] = */ (1U << MP_MAP),<br> };<br>@@ -83,9 +84,11 @@ const uint32_t field_ext_type[] = {<br> /* [FIELD_TYPE_INTEGER] = */ 0,<br> /* [FIELD_TYPE_BOOLEAN] = */ 0,<br> /* [FIELD_TYPE_VARBINARY] = */ 0,<br>- /* [FIELD_TYPE_SCALAR] = */ (1U << MP_DECIMAL) | (1U << MP_UUID),<br>+ /* [FIELD_TYPE_SCALAR] = */ (1U << MP_DECIMAL) | (1U << MP_UUID) |<br>+ (1U << MP_DATETIME),<br> /* [FIELD_TYPE_DECIMAL] = */ 1U << MP_DECIMAL,<br> /* [FIELD_TYPE_UUID] = */ 1U << MP_UUID,<br>+ /* [FIELD_TYPE_DATETIME] = */ 1U << MP_DATETIME,<br> /* [FIELD_TYPE_ARRAY] = */ 0,<br> /* [FIELD_TYPE_MAP] = */ 0,<br> };<br>@@ -102,6 +105,7 @@ const char *field_type_strs[] = {<br> /* [FIELD_TYPE_SCALAR] = */ "scalar",<br> /* [FIELD_TYPE_DECIMAL] = */ "decimal",<br> /* [FIELD_TYPE_UUID] = */ "uuid",<br>+ /* [FIELD_TYPE_DATETIME] = */ "datetime",<br> /* [FIELD_TYPE_ARRAY] = */ "array",<br> /* [FIELD_TYPE_MAP] = */ "map",<br> };<br>@@ -128,20 +132,21 @@ field_type_by_name_wrapper(const char *str, uint32_t len)<br> * values can be stored in the j type.<br> */<br> static const bool field_type_compatibility[] = {<br>- /* ANY UNSIGNED STRING NUMBER DOUBLE INTEGER BOOLEAN VARBINARY SCALAR DECIMAL UUID ARRAY MAP */<br>-/* ANY */ true, false, false, false, false, false, false, false, false, false, false, false, false,<br>-/* UNSIGNED */ true, true, false, true, false, true, false, false, true, false, false, false, false,<br>-/* STRING */ true, false, true, false, false, false, false, false, true, false, false, false, false,<br>-/* NUMBER */ true, false, false, true, false, false, false, false, true, false, false, false, false,<br>-/* DOUBLE */ true, false, false, true, true, false, false, false, true, false, false, false, false,<br>-/* INTEGER */ true, false, false, true, false, true, false, false, true, false, false, false, false,<br>-/* BOOLEAN */ true, false, false, false, false, false, true, false, true, false, false, false, false,<br>-/* VARBINARY*/ true, false, false, false, false, false, false, true, true, false, false, false, false,<br>-/* SCALAR */ true, false, false, false, false, false, false, false, true, false, false, false, false,<br>-/* DECIMAL */ true, false, false, true, false, false, false, false, true, true, false, false, false,<br>-/* UUID */ true, false, false, false, false, false, false, false, false, false, true, false, false,<br>-/* ARRAY */ true, false, false, false, false, false, false, false, false, false, false, true, false,<br>-/* MAP */ true, false, false, false, false, false, false, false, false, false, false, false, true,<br>+ /* ANY UNSIGNED STRING NUMBER DOUBLE INTEGER BOOLEAN VARBINARY SCALAR DECIMAL UUID DATETIME ARRAY MAP */<br>+/* ANY */ true, false, false, false, false, false, false, false, false, false, false, false, false, false,<br>+/* UNSIGNED */ true, true, false, true, false, true, false, false, true, false, false, false, false, false,<br>+/* STRING */ true, false, true, false, false, false, false, false, true, false, false, false, false, false,<br>+/* NUMBER */ true, false, false, true, false, false, false, false, true, false, false, false, false, false,<br>+/* DOUBLE */ true, false, false, true, true, false, false, false, true, false, false, false, false, false,<br>+/* INTEGER */ true, false, false, true, false, true, false, false, true, false, false, false, false, false,<br>+/* BOOLEAN */ true, false, false, false, false, false, true, false, true, false, false, false, false, false,<br>+/* VARBINARY*/ true, false, false, false, false, false, false, true, true, false, false, false, false, false,<br>+/* SCALAR */ true, false, false, false, false, false, false, false, true, false, false, false, false, false,<br>+/* DECIMAL */ true, false, false, true, false, false, false, false, true, true, false, false, false, false,<br>+/* UUID */ true, false, false, false, false, false, false, false, false, false, true, false, false, false,<br>+/* DATETIME */ true, false, false, false, false, false, false, false, true, false, false, true, false, false,<br>+/* ARRAY */ true, false, false, false, false, false, false, false, false, false, false, false, true, false,<br>+/* MAP */ true, false, false, false, false, false, false, false, false, false, false, false, false, true,<br> };<br> <br> bool<br>diff --git a/src/box/field_def.h b/src/box/field_def.h<br>index c5cfe5e86..619ea19fe 100644<br>--- a/src/box/field_def.h<br>+++ b/src/box/field_def.h<br>@@ -61,6 +61,7 @@ enum field_type {<br> FIELD_TYPE_SCALAR,<br> FIELD_TYPE_DECIMAL,<br> FIELD_TYPE_UUID,<br>+ FIELD_TYPE_DATETIME,<br> FIELD_TYPE_ARRAY,<br> FIELD_TYPE_MAP,<br> field_type_MAX<br>diff --git a/src/box/tuple_compare.cc b/src/box/tuple_compare.cc<br>index 43cd29ce9..2478498ba 100644<br>--- a/src/box/tuple_compare.cc<br>+++ b/src/box/tuple_compare.cc<br>@@ -36,6 +36,7 @@<br> #include "lib/core/decimal.h"<br> #include "lib/core/mp_decimal.h"<br> #include "uuid/mp_uuid.h"<br>+#include "lib/core/mp_datetime.h"<br> #include "lib/core/mp_extension_types.h"<br> <br> /* {{{ tuple_compare */<br>@@ -76,6 +77,7 @@ enum mp_class {<br> MP_CLASS_STR,<br> MP_CLASS_BIN,<br> MP_CLASS_UUID,<br>+ MP_CLASS_DATETIME,<br> MP_CLASS_ARRAY,<br> MP_CLASS_MAP,<br> mp_class_max,<br>@@ -99,6 +101,8 @@ static enum mp_class mp_ext_classes[] = {<br> /* .MP_UNKNOWN_EXTENSION = */ mp_class_max, /* unsupported */<br> /* .MP_DECIMAL = */ MP_CLASS_NUMBER,<br> /* .MP_UUID = */ MP_CLASS_UUID,<br>+ /* .MP_ERROR = */ mp_class_max,<br>+ /* .MP_DATETIME = */ MP_CLASS_DATETIME,<br> };<br> <br> static enum mp_class<br>@@ -390,6 +394,19 @@ mp_compare_uuid(const char *field_a, const char *field_b)<br> return memcmp(field_a + 2, field_b + 2, UUID_PACKED_LEN);<br> }<br> <br>+static int<br>+mp_compare_datetime(const char *lhs, const char *rhs)<br>+{<br>+ struct datetime lhs_dt, rhs_dt;<br>+ struct datetime *ret;<br>+ ret = mp_decode_datetime(&lhs, &lhs_dt);<br>+ assert(ret != NULL);<br>+ ret = mp_decode_datetime(&rhs, &rhs_dt);<br>+ assert(ret != NULL);<br>+ (void)ret;<br>+ return datetime_compare(&lhs_dt, &rhs_dt);<br>+}<br>+<br> typedef int (*mp_compare_f)(const char *, const char *);<br> static mp_compare_f mp_class_comparators[] = {<br> /* .MP_CLASS_NIL = */ NULL,<br>@@ -398,6 +415,7 @@ static mp_compare_f mp_class_comparators[] = {<br> /* .MP_CLASS_STR = */ mp_compare_str,<br> /* .MP_CLASS_BIN = */ mp_compare_bin,<br> /* .MP_CLASS_UUID = */ mp_compare_uuid,<br>+ /* .MP_CLASS_DATETIME=*/ mp_compare_datetime,<br> /* .MP_CLASS_ARRAY = */ NULL,<br> /* .MP_CLASS_MAP = */ NULL,<br> };<br>@@ -478,6 +496,8 @@ tuple_compare_field(const char *field_a, const char *field_b,<br> return mp_compare_decimal(field_a, field_b);<br> case FIELD_TYPE_UUID:<br> return mp_compare_uuid(field_a, field_b);<br>+ case FIELD_TYPE_DATETIME:<br>+ return mp_compare_datetime(field_a, field_b);<br> default:<br> unreachable();<br> return 0;<br>@@ -518,6 +538,8 @@ tuple_compare_field_with_type(const char *field_a, enum mp_type a_type,<br> field_b, b_type);<br> case FIELD_TYPE_UUID:<br> return mp_compare_uuid(field_a, field_b);<br>+ case FIELD_TYPE_DATETIME:<br>+ return mp_compare_datetime(field_a, field_b);<br> default:<br> unreachable();<br> return 0;<br>@@ -1518,6 +1540,21 @@ func_index_compare_with_key(struct tuple *tuple, hint_t tuple_hint,<br> #define HINT_VALUE_DOUBLE_MAX (exp2(HINT_VALUE_BITS - 1) - 1)<br> #define HINT_VALUE_DOUBLE_MIN (-exp2(HINT_VALUE_BITS - 1))<br> <br>+/**<br>+ * We need to squeeze 64 bits of seconds and 32 bits of nanoseconds<br>+ * into 60 bits of hint value. The idea is to represent wide enough<br>+ * years range, and leave the rest of bits occupied from nanoseconds part:<br>+ * - 36 bits is enough for time range of [208BC..4147]<br>+ * - for nanoseconds there is left 24 bits, which are MSB part of<br>+ * 32-bit value<br>+ */<br>+#define HINT_VALUE_SECS_BITS 36<br>+#define HINT_VALUE_NSEC_BITS (HINT_VALUE_BITS - HINT_VALUE_SECS_BITS)<br>+#define HINT_VALUE_SECS_MAX ((1LL << (HINT_VALUE_SECS_BITS - 1)) - 1)<br>+#define HINT_VALUE_SECS_MIN (-(1LL << (HINT_VALUE_SECS_BITS - 1)))<br>+#define HINT_VALUE_NSEC_SHIFT (sizeof(int) * CHAR_BIT - HINT_VALUE_NSEC_BITS)<br>+#define HINT_VALUE_NSEC_MAX ((1ULL << HINT_VALUE_NSEC_BITS) - 1)<br>+<br> /*<br> * HINT_CLASS_BITS should be big enough to store any mp_class value.<br> * Note, ((1 << HINT_CLASS_BITS) - 1) is reserved for HINT_NONE.<br>@@ -1610,6 +1647,25 @@ hint_uuid_raw(const char *data)<br> return hint_create(MP_CLASS_UUID, val);<br> }<br> <br>+static inline hint_t<br>+hint_datetime(struct datetime *date)<br>+{<br>+ /*<br>+ * Use at most HINT_VALUE_SECS_BITS from datetime<br>+ * seconds field as a hint value, and at MSB part<br>+ * of HINT_VALUE_NSEC_BITS from nanoseconds.<br>+ */<br>+ int64_t secs = date->secs;<br>+ int32_t nsec = date->nsec;<br>+ uint64_t val = secs <= HINT_VALUE_SECS_MIN ? 0 :<br>+ secs - HINT_VALUE_SECS_MIN;<br>+ if (val >= HINT_VALUE_SECS_MAX)<br>+ val = HINT_VALUE_SECS_MAX;<br>+ val <<= HINT_VALUE_NSEC_BITS;<br>+ val |= (nsec >> HINT_VALUE_NSEC_SHIFT) & HINT_VALUE_NSEC_MAX;<br>+ return hint_create(MP_CLASS_DATETIME, val);<br>+}<br>+<br> static inline uint64_t<br> hint_str_raw(const char *s, uint32_t len)<br> {<br>@@ -1741,6 +1797,17 @@ field_hint_uuid(const char *field)<br> return hint_uuid_raw(data);<br> }<br> <br>+static inline hint_t<br>+field_hint_datetime(const char *field)<br>+{<br>+ assert(mp_typeof(*field) == MP_EXT);<br>+ int8_t ext_type;<br>+ uint32_t len = mp_decode_extl(&field, &ext_type);<br>+ assert(ext_type == MP_DATETIME);<br>+ struct datetime date;<br>+ return hint_datetime(datetime_unpack(&field, len, &date));<br>+}<br>+<br> static inline hint_t<br> field_hint_string(const char *field, struct coll *coll)<br> {<br>@@ -1792,6 +1859,11 @@ field_hint_scalar(const char *field, struct coll *coll)<br> }<br> case MP_UUID:<br> return hint_uuid_raw(field);<br>+ case MP_DATETIME:<br>+ {<br>+ struct datetime date;<br>+ return hint_datetime(datetime_unpack(&field, len, &date));<br>+ }<br> default:<br> unreachable();<br> }<br>@@ -1829,6 +1901,8 @@ field_hint(const char *field, struct coll *coll)<br> return field_hint_decimal(field);<br> case FIELD_TYPE_UUID:<br> return field_hint_uuid(field);<br>+ case FIELD_TYPE_DATETIME:<br>+ return field_hint_datetime(field);<br> default:<br> unreachable();<br> }<br>@@ -1943,6 +2017,9 @@ key_def_set_hint_func(struct key_def *def)<br> case FIELD_TYPE_UUID:<br> key_def_set_hint_func<FIELD_TYPE_UUID>(def);<br> break;<br>+ case FIELD_TYPE_DATETIME:<br>+ key_def_set_hint_func<FIELD_TYPE_DATETIME>(def);<br>+ break;<br> default:<br> /* Invalid key definition. */<br> def->key_hint = NULL;<br>diff --git a/src/lib/core/datetime.c b/src/lib/core/datetime.c<br>index 7125090e6..ebc05e29c 100644<br>--- a/src/lib/core/datetime.c<br>+++ b/src/lib/core/datetime.c<br>@@ -123,3 +123,12 @@ datetime_to_string(const struct datetime *date, char *buf, int len)<br> return sz;<br> }<br> <br>+int<br>+datetime_compare(const struct datetime *lhs, const struct datetime *rhs)<br>+{<br>+ int result = COMPARE_RESULT(lhs->secs, rhs->secs);<br>+ if (result != 0)<br>+ return result;<br>+<br>+ return COMPARE_RESULT(lhs->nsec, rhs->nsec);<br>+}<br>diff --git a/src/lib/core/datetime.h b/src/lib/core/datetime.h<br>index fb537e372..fc5717115 100644<br>--- a/src/lib/core/datetime.h<br>+++ b/src/lib/core/datetime.h<br>@@ -81,6 +81,17 @@ struct datetime_interval {<br> */<br> #define DT_TO_STRING_BUFSIZE 48<br> <br>+/*<br>+ * Compare arguments of a datetime type<br>+ * @param lhs left datetime argument<br>+ * @param rhs right datetime argument<br>+ * @retval < 0 if lhs less than rhs<br>+ * @retval = 0 if lhs and rhs equal<br>+ * @retval > 0 if lhs greater than rhs<br>+ */<br>+int<br>+datetime_compare(const struct datetime *lhs, const struct datetime *rhs);<br>+<br> /**<br> * Convert datetime to string using default format<br> * @param date source datetime value<br>diff --git a/test/engine/datetime.result b/test/engine/datetime.result<br>new file mode 100644<br>index 000000000..848a0aaec<br>--- /dev/null<br>+++ b/test/engine/datetime.result<br>@@ -0,0 +1,77 @@<br>+-- test-run result file version 2<br>+env = require('test_run')<br>+ | ---<br>+ | ...<br>+test_run = env.new()<br>+ | ---<br>+ | ...<br>+engine = test_run:get_cfg('engine')<br>+ | ---<br>+ | ...<br>+<br>+date = require('datetime')<br>+ | ---<br>+ | ...<br>+<br>+_ = box.schema.space.create('T', {engine = engine})<br>+ | ---<br>+ | ...<br>+_ = box.space.T:create_index('pk', {parts={1,'datetime'}})<br>+ | ---<br>+ | ...<br>+<br>+box.space.T:insert{date('1970-01-01')}\<br>+box.space.T:insert{date('1970-01-02')}\<br>+box.space.T:insert{date('1970-01-03')}\<br>+box.space.T:insert{date('2000-01-01')}<br>+ | ---<br>+ | ...<br>+<br>+o = box.space.T:select{}<br>+ | ---<br>+ | ...<br>+assert(tostring(o[1][1]) == '1970-01-01T00:00Z')<br>+ | ---<br>+ | - true<br>+ | ...<br>+assert(tostring(o[2][1]) == '1970-01-02T00:00Z')<br>+ | ---<br>+ | - true<br>+ | ...<br>+assert(tostring(o[3][1]) == '1970-01-03T00:00Z')<br>+ | ---<br>+ | - true<br>+ | ...<br>+assert(tostring(o[4][1]) == '2000-01-01T00:00Z')<br>+ | ---<br>+ | - true<br>+ | ...<br>+<br>+for i = 1,16 do\<br>+ box.space.T:insert{date.now()}\<br>+end<br>+ | ---<br>+ | ...<br>+<br>+a = box.space.T:select{}<br>+ | ---<br>+ | ...<br>+err = {}<br>+ | ---<br>+ | ...<br>+for i = 1, #a - 1 do\<br>+ if a[i][1] >= a[i+1][1] then\<br>+ table.insert(err, {a[i][1], a[i+1][1]})\<br>+ break\<br>+ end\<br>+end<br>+ | ---<br>+ | ...<br>+<br>+err<br>+ | ---<br>+ | - []<br>+ | ...<br>+box.space.T:drop()<br>+ | ---<br>+ | ...<br>diff --git a/test/engine/datetime.test.lua b/test/engine/datetime.test.lua<br>new file mode 100644<br>index 000000000..3685e4d4b<br>--- /dev/null<br>+++ b/test/engine/datetime.test.lua<br>@@ -0,0 +1,35 @@<br>+env = require('test_run')<br>+test_run = env.new()<br>+engine = test_run:get_cfg('engine')<br>+<br>+date = require('datetime')<br>+<br>+_ = box.schema.space.create('T', {engine = engine})<br>+_ = box.space.T:create_index('pk', {parts={1,'datetime'}})<br>+<br>+box.space.T:insert{date('1970-01-01')}\<br>+box.space.T:insert{date('1970-01-02')}\<br>+box.space.T:insert{date('1970-01-03')}\<br>+box.space.T:insert{date('2000-01-01')}<br>+<br>+o = box.space.T:select{}<br>+assert(tostring(o[1][1]) == '1970-01-01T00:00Z')<br>+assert(tostring(o[2][1]) == '1970-01-02T00:00Z')<br>+assert(tostring(o[3][1]) == '1970-01-03T00:00Z')<br>+assert(tostring(o[4][1]) == '2000-01-01T00:00Z')<br>+<br>+for i = 1,16 do\<br>+ box.space.T:insert{date.now()}\<br>+end<br>+<br>+a = box.space.T:select{}<br>+err = {}<br>+for i = 1, #a - 1 do\<br>+ if a[i][1] >= a[i+1][1] then\<br>+ table.insert(err, {a[i][1], a[i+1][1]})\<br>+ break\<br>+ end\<br>+end<br>+<br>+err<br>+box.space.T:drop()<br>diff --git a/test/unit/datetime.c b/test/unit/datetime.c<br>index c6ba444f5..61ebfe76b 100644<br>--- a/test/unit/datetime.c<br>+++ b/test/unit/datetime.c<br>@@ -281,7 +281,7 @@ mp_datetime_test()<br> };<br> size_t index;<br> <br>- plan(68);<br>+ plan(85);<br> for (index = 0; index < lengthof(tests); index++) {<br> struct datetime date = {<br> tests[index].secs,<br>@@ -303,6 +303,7 @@ mp_datetime_test()<br> struct datetime *rc = mp_decode_datetime(&data1, &ret);<br> is(rc, &ret, "mp_decode_datetime() return code");<br> is(data1, end, "mp_sizeof_uuid() == decoded length");<br>+ is(datetime_compare(&date, &ret), 0, "datetime_compare(&date, &ret)");<br> }<br> check_plan();<br> }<br>--<br>2.29.2</div></div></div></div></blockquote> <div> </div><div data-signature-widget="container"><div data-signature-widget="content"><div>--<br>Dmitry E. Oboukhov</div></div></div><div> </div></div></BODY></HTML>