diff --git a/cmake/BuildCDT.cmake b/cmake/BuildCDT.cmake
index 80b26c64a12ab0086387c35760046ea7f659c522..8c89e8a117d58e01ec6ec928ba313a94d52e0a2c 100644
--- a/cmake/BuildCDT.cmake
+++ b/cmake/BuildCDT.cmake
@@ -5,6 +5,9 @@ macro(libccdt_build)
     file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/third_party/c-dt/build/)
     add_subdirectory(${PROJECT_SOURCE_DIR}/third_party/c-dt
                      ${CMAKE_CURRENT_BINARY_DIR}/third_party/c-dt/build/)
-    set_target_properties(cdt PROPERTIES COMPILE_FLAGS "-DDT_NAMESPACE=tnt_")
+    set_target_properties(cdt
+        PROPERTIES COMPILE_FLAGS
+            "-DDT_NAMESPACE=tnt_ -DDT_PARSE_ISO_YEAR0 -DDT_PARSE_ISO_TNT"
+    )
     add_definitions("-DDT_NAMESPACE=tnt_")
 endmacro()
diff --git a/extra/exports b/extra/exports
index be61fb7c1aef5653cd19bac91784c89e0e2dfb4a..efbe17eef29ca2c76c9d85cdfdd2dec9dd05a008 100644
--- a/extra/exports
+++ b/extra/exports
@@ -430,6 +430,7 @@ tnt_dt_dow
 tnt_dt_doy
 tnt_dt_from_rdn
 tnt_dt_from_ymd
+tnt_dt_from_ymd_checked
 tnt_dt_month
 tnt_dt_parse_iso_date
 tnt_dt_parse_iso_time
diff --git a/src/lib/core/datetime.c b/src/lib/core/datetime.c
index 9df22a690d1624a61f60e1241e3438f593e2451c..0360fe7fc0db1f01a087a3023c532c4308748bcc 100644
--- a/src/lib/core/datetime.c
+++ b/src/lib/core/datetime.c
@@ -7,8 +7,10 @@
 #include <assert.h>
 #include <limits.h>
 #include <string.h>
+#include <stdbool.h>
 #include <time.h>
 
+#define DT_PARSE_ISO_TNT
 #include "c-dt/dt.h"
 #include "datetime.h"
 #include "trivia/util.h"
@@ -71,7 +73,7 @@ datetime_strftime(const struct datetime *date, char *buf, size_t len,
 /**
  * Create datetime structure using given tnt_tm fieldsÑŽ
  */
-static void
+static bool
 tm_to_datetime(struct tnt_tm *tm, struct datetime *date)
 {
 	assert(tm != NULL);
@@ -91,9 +93,12 @@ tm_to_datetime(struct tnt_tm *tm, struct datetime *date)
 			dt = ((wday - 4) % 7) + DT_EPOCH_1970_OFFSET;
 		}
 	} else {
-		assert(mday >= 0 && mday < 32);
+		if (mday == 0)
+			mday = 1;
+		assert(mday >= 1 && mday <= 31);
 		assert(mon >= 0 && mon <= 11);
-		dt = dt_from_ymd(year + 1900, mon + 1, mday);
+		if (dt_from_ymd_checked(year + 1900, mon + 1, mday, &dt) == false)
+			return false;
 	}
 	int64_t local_secs =
 		(int64_t)dt * SECS_PER_DAY - SECS_EPOCH_1970_OFFSET;
@@ -102,6 +107,7 @@ tm_to_datetime(struct tnt_tm *tm, struct datetime *date)
 	date->nsec = tm->tm_nsec;
 	date->tzindex = 0;
 	date->tzoffset = tm->tm_gmtoff / 60;
+	return true;
 }
 
 size_t
@@ -114,7 +120,8 @@ datetime_strptime(struct datetime *date, const char *buf, const char *fmt)
 	char *ret = tnt_strptime(buf, fmt, &t);
 	if (ret == NULL)
 		return 0;
-	tm_to_datetime(&t, date);
+	if (tm_to_datetime(&t, date) == false)
+		return 0;
 	return ret - buf;
 }
 
@@ -198,30 +205,37 @@ datetime_parse_full(struct datetime *date, const char *str, size_t len,
 	n = dt_parse_iso_date(str, len, &dt);
 	if (n == 0)
 		return 0;
-	if (n == len)
+
+	str += n;
+	len -= n;
+	if (len <= 0)
 		goto exit;
 
-	c = str[n++];
+	c = *str++;
 	if (c != 'T' && c != 't' && c != ' ')
 		return 0;
-
-	str += n;
-	len -= n;
+	len--;
+	if (len <= 0)
+		goto exit;
 
 	n = dt_parse_iso_time(str, len, &sec_of_day, &nanosecond);
 	if (n == 0)
 		return 0;
-	if (n == len)
-		goto exit;
-
-	if (str[n] == ' ')
-		n++;
 
 	str += n;
 	len -= n;
+	if (len <= 0)
+		goto exit;
+
+	if (*str == ' ') {
+		str++;
+		len--;
+	}
+	if (len <= 0)
+		goto exit;
 
 	n = dt_parse_iso_zone_lenient(str, len, &offset);
-	if (n == 0 || n != len)
+	if (n == 0)
 		return 0;
 	str += n;
 
diff --git a/src/lib/tzcode/strptime.c b/src/lib/tzcode/strptime.c
index 37656d225f04d858d2e551fe0d078f4293a4341d..88939cae332b98f7f177ed058dce8048d28fe899 100644
--- a/src/lib/tzcode/strptime.c
+++ b/src/lib/tzcode/strptime.c
@@ -83,6 +83,23 @@ first_wday_of(int year)
 		((year % 100) / 4) + (isleap(year) ? 6 : 0) + 1) % 7;
 }
 
+#define NUM_(N, buf) \
+	({	size_t _len = N; \
+		long val = 0; \
+		long sign = +1; \
+		if ('-' == *buf) { \
+			buf++; \
+			sign = -1; \
+		} \
+		for (; _len > 0 && *buf != 0 && is_digit((u_char)*buf); \
+		     buf++, _len--) \
+			val = val * 10 + (*buf - '0'); \
+		sign * val; \
+	})
+
+#define NUM2(buf) NUM_(2, buf)
+#define NUM3(buf) NUM_(3, buf)
+
 char *
 tnt_strptime(const char *__restrict buf, const char *__restrict fmt,
 	     struct tnt_tm *__restrict tm)
@@ -136,13 +153,7 @@ tnt_strptime(const char *__restrict buf, const char *__restrict fmt,
 				return NULL;
 
 			/* XXX This will break for 3-digit centuries. */
-			len = 2;
-			for (i = 0; len && *buf != 0 && is_digit((u_char)*buf);
-			     buf++) {
-				i *= 10;
-				i += *buf - '0';
-				len--;
-			}
+			i = NUM2(buf);
 
 			century = i;
 			flags |= FLAG_YEAR;
@@ -224,13 +235,7 @@ tnt_strptime(const char *__restrict buf, const char *__restrict fmt,
 			if (!is_digit((u_char)*buf))
 				return NULL;
 
-			len = 3;
-			for (i = 0; len && *buf != 0 && is_digit((u_char)*buf);
-			     buf++) {
-				i *= 10;
-				i += *buf - '0';
-				len--;
-			}
+			i = NUM3(buf);
 			if (i < 1 || i > 366)
 				return NULL;
 
@@ -283,13 +288,7 @@ tnt_strptime(const char *__restrict buf, const char *__restrict fmt,
 			if (!is_digit((u_char)*buf))
 				return NULL;
 
-			len = 2;
-			for (i = 0; len && *buf != 0 && is_digit((u_char)*buf);
-			     buf++) {
-				i *= 10;
-				i += *buf - '0';
-				len--;
-			}
+			i = NUM2(buf);
 
 			if (c == 'M') {
 				if (i > 59)
@@ -325,12 +324,7 @@ tnt_strptime(const char *__restrict buf, const char *__restrict fmt,
 			if (!is_digit((u_char)*buf))
 				return NULL;
 
-			for (i = 0; len && *buf != 0 && is_digit((u_char)*buf);
-			     buf++) {
-				i *= 10;
-				i += *buf - '0';
-				len--;
-			}
+			i = NUM_(len, buf);
 			if (c == 'H' || c == 'k') {
 				if (i > 23)
 					return NULL;
@@ -397,13 +391,7 @@ tnt_strptime(const char *__restrict buf, const char *__restrict fmt,
 			if (!is_digit((u_char)*buf))
 				return NULL;
 
-			len = 2;
-			for (i = 0; len && *buf != 0 && is_digit((u_char)*buf);
-			     buf++) {
-				i *= 10;
-				i += *buf - '0';
-				len--;
-			}
+			i = NUM2(buf);
 			if (i > 53)
 				return NULL;
 
@@ -452,13 +440,7 @@ tnt_strptime(const char *__restrict buf, const char *__restrict fmt,
 			if (!is_digit((u_char)*buf))
 				return NULL;
 
-			len = 2;
-			for (i = 0; len && *buf != 0 && is_digit((u_char)*buf);
-			     buf++) {
-				i *= 10;
-				i += *buf - '0';
-				len--;
-			}
+			i = NUM2(buf);
 			if (i == 0 || i > 31)
 				return NULL;
 
@@ -514,13 +496,7 @@ tnt_strptime(const char *__restrict buf, const char *__restrict fmt,
 			if (!is_digit((u_char)*buf))
 				return NULL;
 
-			len = 2;
-			for (i = 0; len && *buf != 0 && is_digit((u_char)*buf);
-			     buf++) {
-				i *= 10;
-				i += *buf - '0';
-				len--;
-			}
+			i = NUM2(buf);
 			if (i < 1 || i > 12)
 				return NULL;
 
@@ -549,16 +525,11 @@ tnt_strptime(const char *__restrict buf, const char *__restrict fmt,
 			if (*buf == 0 || isspace((u_char)*buf))
 				break;
 
-			if (!is_digit((u_char)*buf))
+			if (*buf != '-' && !is_digit((u_char)*buf))
 				return NULL;
 
-			len = (c == 'Y' || c == 'G') ? 4 : 2;
-			for (i = 0; len && *buf != 0 && is_digit((u_char)*buf);
-			     buf++) {
-				i *= 10;
-				i += *buf - '0';
-				len--;
-			}
+			len = (c == 'Y' || c == 'G') ? 7 : 2;
+			i = NUM_(len, buf);
 			if (c == 'Y' || c == 'G')
 				century = i / 100;
 			year = i % 100;
@@ -579,7 +550,8 @@ tnt_strptime(const char *__restrict buf, const char *__restrict fmt,
 				zonestr[cp - buf] = '\0';
 				tzset();
 				if (0 == strcmp(zonestr, "GMT") ||
-				    0 == strcmp(zonestr, "UTC")) {
+				    0 == strcmp(zonestr, "UTC") ||
+				    0 == strcmp(zonestr, "Z")) {
 					tm->tm_gmtoff = 0;
 				} else if (0 == strcmp(zonestr, tzname[0])) {
 					tm->tm_isdst = 0;
@@ -593,6 +565,16 @@ tnt_strptime(const char *__restrict buf, const char *__restrict fmt,
 		} break;
 
 		case 'z': {
+
+			/* Even for %z format specifier we better to accept
+			 * Zulu timezone as default Tarantool shortcut for
+			 * +00:00 offset.
+			 */
+			if (*buf == 'Z') {
+				buf++;
+				tm->tm_gmtoff = 0;
+				break;
+			}
 			int sign = 1;
 
 			if (*buf != '+') {
diff --git a/src/lua/datetime.lua b/src/lua/datetime.lua
index 8bb21e440a5dfd46487c2b05cd6523d3cbc530e5..7b494fe92bd666b103a7820aa2f9718f848501d3 100644
--- a/src/lua/datetime.lua
+++ b/src/lua/datetime.lua
@@ -922,7 +922,7 @@ local function datetime_parse_full(str, tzoffset)
     if len == 0 then
         error(("could not parse '%s'"):format(str))
     end
-    return date, len
+    return date, tonumber(len)
 end
 
 --[[
@@ -935,7 +935,7 @@ local function datetime_parse_format(str, fmt)
     if len == 0 then
         error(("could not parse '%s' using '%s' format"):format(str, fmt))
     end
-    return date, len
+    return date, tonumber(len)
 end
 
 local function datetime_parse_from(str, obj)
diff --git a/test/app-tap/datetime.test.lua b/test/app-tap/datetime.test.lua
index ee40a3081ca2831d08147db04b1f18c6591c52d4..6d60aa5dd13300fae4a77b1e418232a278609471 100755
--- a/test/app-tap/datetime.test.lua
+++ b/test/app-tap/datetime.test.lua
@@ -11,7 +11,7 @@ local ffi = require('ffi')
 --]]
 if jit.arch == 'arm64' then jit.off() end
 
-test:plan(31)
+test:plan(32)
 
 -- minimum supported date - -5879610-06-22
 local MIN_DATE_YEAR = -5879610
@@ -96,17 +96,16 @@ local function invalid_date_fmt_error(str)
     return ('invalid date format %s'):format(str)
 end
 
--- utility functions to gracefully handle pcall errors
 local function assert_raises(test, error_msg, func, ...)
     local ok, err = pcall(func, ...)
-    local err_tail = err:gsub("^.+:%d+: ", "")
+    local err_tail = err and err:gsub("^.+:%d+: ", "") or ''
     return test:is(not ok and err_tail, error_msg,
                    ('"%s" received, "%s" expected'):format(err_tail, error_msg))
 end
 
 local function assert_raises_like(test, error_msg, func, ...)
     local ok, err = pcall(func, ...)
-    local err_tail = err:gsub("^.+:%d+: ", "")
+    local err_tail = err and err:gsub("^.+:%d+: ", "") or ''
     return test:like(not ok and err_tail, error_msg,
                    ('"%s" received, "%s" expected'):format(err_tail, error_msg))
 end
@@ -498,6 +497,28 @@ local function create_date_string(date)
     return ('%04d-%02d-%02dT%02d:%02d:%02dZ'):format(year, month, day, hour, min, sec)
 end
 
+test:test("Check parsing of full supported years range", function(test)
+    test:plan(63)
+    local valid_years = {
+        -5879610, -5879000, -5800000, -2e6, -1e5, -1e4, -9999, -2000, -1000,
+        0, 1, 1000, 1900, 1970, 2000, 9999,
+        1e4, 1e6, 2e6, 5e6, 5879611
+    }
+    local fmt = '%FT%T%z'
+    for _, y in ipairs(valid_years) do
+        local txt = ('%04d-06-22'):format(y)
+        local dt = date.parse(txt)
+        test:isnt(dt, nil, dt)
+        local out_txt = tostring(dt)
+        local out_dt = date.parse(out_txt)
+        test:is(dt, out_dt, ('default parse of %s (%s == %s)'):
+                            format(out_txt, dt, out_dt))
+        local fmt_dt = date.parse(out_txt, {format = fmt})
+        test:is(dt, fmt_dt, ('parse via format %s (%s == %s)'):
+                            format(fmt, dt, fmt_dt))
+    end
+end)
+
 local function couldnt_parse(txt)
     return ("could not parse '%s'"):format(txt)
 end
@@ -1307,7 +1328,7 @@ test:test("Matrix of allowed time and interval subtractions", function(test)
 end)
 
 test:test("Parse iso8601 date - valid strings", function(test)
-    test:plan(32)
+    test:plan(54)
     local good = {
         {2012, 12, 24, "20121224",                   8 },
         {2012, 12, 24, "20121224  Foo bar",          8 },
@@ -1325,6 +1346,17 @@ test:test("Parse iso8601 date - valid strings", function(test)
         {   1,  1,  1, "0001-W01-1",                10 },
         {   1,  1,  1, "0001-01-01",                10 },
         {   1,  1,  1, "0001-001",                   8 },
+        {9999, 12, 31, "9999-12-31",                10 },
+        {   0,  1,  1, "0000-Q1-01",                10 },
+        {   0,  1,  3, "0000-W01-1",                10 },
+        {   0,  1,  1, "0000-01-01",                10 },
+        {   0,  1,  1, "0000-001",                   8 },
+        {-200, 12, 31, "-200-12-31",                10 },
+        {-1000,12, 31, "-1000-12-31",               11 },
+        {-10000,12,31, "-10000-12-31",              12 },
+        {-5879610,6,22,"-5879610-06-22",            14 },
+        {10000, 1,  1, "10000-01-01",               11 },
+        {5879611,7, 1, "5879611-07-01",             13 },
     }
 
     for _, value in ipairs(good) do
@@ -1339,7 +1371,7 @@ test:test("Parse iso8601 date - valid strings", function(test)
 end)
 
 test:test("Parse iso8601 date - invalid strings", function(test)
-    test:plan(31)
+    test:plan(29)
     local bad = {
         "20121232"   , -- Invalid day of month
         "2012-12-310", -- Invalid day of month
@@ -1368,10 +1400,8 @@ test:test("Parse iso8601 date - invalid strings", function(test)
         "2012U1234"  , -- Invalid
         "2012-1234"  , -- Invalid
         "2012-X1234" , -- Invalid
-        "0000-Q1-01" , -- Year less than 0001
-        "0000-W01-1" , -- Year less than 0001
-        "0000-01-01" , -- Year less than 0001
-        "0000-001"   , -- Year less than 0001
+        "-5879611-01-01",  -- Year less than 5879610-06-22
+        "5879612-01-01",  -- Year greater than 5879611-07-11
     }
 
     for _, str in ipairs(bad) do
diff --git a/test/unit/datetime.c b/test/unit/datetime.c
index b183be67457af7636c941db1e43be74ff05b12a6..fb2919caaa56a61b1f0c7e9eaf1487b366864513 100644
--- a/test/unit/datetime.c
+++ b/test/unit/datetime.c
@@ -102,7 +102,7 @@ datetime_test(void)
 	size_t index;
 	struct datetime date_expected;
 
-	plan(355);
+	plan(497);
 	datetime_parse_full(&date_expected, sample, sizeof(sample) - 1, 0);
 
 	for (index = 0; index < lengthof(tests); index++) {
@@ -121,15 +121,20 @@ datetime_test(void)
 		 * time fields
 		 */
 		static char buff[DT_TO_STRING_BUFSIZE];
-		struct tnt_tm tm = { .tm_sec = 0 };
 		len = datetime_strftime(&date, buff, sizeof(buff), "%F %T%z");
 		ok(len > 0, "strftime");
+		struct datetime date_strp;
+		len = datetime_strptime(&date_strp, buff, "%F %T%z");
+		is(len > 0, true, "correct parse_strptime return value "
+		   "for '%s'", buff);
+		is(date.epoch, date_strp.epoch,
+		   "reversible seconds via datetime_strptime for '%s'", buff);
 		struct datetime date_parsed;
 		len = datetime_parse_full(&date_parsed, buff, len, 0);
-		is(len > 0, true, "correct parse_datetime return value "
+		is(len > 0, true, "correct datetime_parse_full return value "
 		   "for '%s'", buff);
 		is(date.epoch, date_parsed.epoch,
-		   "reversible seconds via strftime for '%s'", buff);
+		   "reversible seconds via datetime_parse_full for '%s'", buff);
 	}
 	check_plan();
 }
@@ -158,10 +163,12 @@ tostring_datetime_test(void)
 		{"1973-11-29T21:33:09Z",    123456789,         0,    0},
 		{"2013-10-28T17:51:56Z",   1382982716,         0,    0},
 		{"9999-12-31T23:59:59Z", 253402300799,         0,    0},
+		{"10000-01-01T00:00:00Z", 253402300800,        0,    0},
+		{"5879611-07-11T00:00:00Z", 185480451417600,   0,    0},
 	};
 	size_t index;
 
-	plan(15);
+	plan(17);
 	for (index = 0; index < lengthof(tests); index++) {
 		struct datetime date = {
 			tests[index].secs,
@@ -187,7 +194,7 @@ _dt_to_epoch(dt_t dt)
 static void
 parse_date_test(void)
 {
-	plan(59);
+	plan(154);
 
 	static struct {
 		int64_t epoch;
@@ -210,6 +217,19 @@ parse_date_test(void)
 		{ -62135596800, "0001-W01-1", 10 },
 		{ -62135596800, "0001-01-01", 10 },
 		{ -62135596800, "0001-001", 8 },
+
+		/* Tarantool extra ranges */
+		{ -62167219200, "0000-01-01", 10 },
+		{ -62167046400, "0000-W01-1", 10 },
+		{ -62167219200, "0000-Q1-01", 10 },
+		{ -68447116800, "-200-12-31", 10 },
+		{ -377705203200, "-10000-12-31", 12 },
+		{ -185604722870400, "-5879610-06-22", 14 },
+		{ -185604706627200, "-5879610W521", 12 },
+		{ 253402214400, "9999-12-31", 10 },
+		{ 253402300800, "10000-01-01", 11 },
+		{ 185480451417600, "5879611-07-11", 13 },
+		{ 185480434915200, "5879611Q101", 11 },
 	};
 	size_t index;
 
@@ -220,10 +240,10 @@ parse_date_test(void)
 		int64_t expected_epoch = valid_tests[index].epoch;
 		size_t len = tnt_dt_parse_iso_date(str, expected_len, &dt);
 		int64_t epoch = _dt_to_epoch(dt);
-		is(len, expected_len, "string '%s' parse failed, len %lu", str,
+		is(len, expected_len, "string '%s' parse, len %lu", str,
 		   len);
-		is(epoch, expected_epoch,
-		   "string '%s' parse failed, epoch %" PRId64, str, epoch);
+		is(epoch, expected_epoch, "string '%s' parse, epoch %" PRId64,
+		   str, epoch);
 	}
 
 	static const char *const invalid_tests[] = {
@@ -262,6 +282,98 @@ parse_date_test(void)
 		is(len, 0, "expected failure of string '%s' parse, len %lu",
 		   str, len);
 	}
+
+	/* check strptime formats */
+	const struct {
+		const char *fmt;
+		const char *text;
+	} format_tests[] = {
+		{ "%A",                      "Thursday" },
+		{ "%a",                      "Thu" },
+		{ "%B",                      "January" },
+		{ "%b",                      "Jan" },
+		{ "%h",                      "Jan" },
+		{ "%c",                      "Thu Jan  1 03:00:00 1970" },
+		{ "%D",                      "01/01/70" },
+		{ "%m/%d/%y",                "01/01/70" },
+		{ "%d",                      "01" },
+		{ "%Ec",                     "Thu Jan  1 03:00:00 1970" },
+		{ "%Ex",                     "01/01/70" },
+		{ "%EX",                     "03:00:00" },
+		{ "%Ey",                     "70" },
+		{ "%EY",                     "1970" },
+		{ "%Od",                     "01" },
+		{ "%OH",                     "03" },
+		{ "%OI",                     "03" },
+		{ "%Om",                     "01" },
+		{ "%OM",                     "00" },
+		{ "%OS",                     "00" },
+		{ "%Ou",                     "4" },
+		{ "%OU",                     "00" },
+		{ "%Ow",                     "4" },
+		{ "%OW",                     "00" },
+		{ "%Oy",                     "70" },
+		{ "%e",                      " 1" },
+		{ "%F",                      "1970-01-01" },
+		{ "%Y-%m-%d",                "1970-01-01" },
+		{ "%H",                      "03" },
+		{ "%I",                      "03" },
+		{ "%j",                      "001" },
+		{ "%k",                      " 3" },
+		{ "%l",                      " 3" },
+		{ "%M",                      "00" },
+		{ "%m",                      "01" },
+		{ "%n",                      "\n" },
+		{ "%p",                      "AM" },
+		{ "%R",                      "03:00" },
+		{ "%H:%M",                   "03:00" },
+		{ "%r",                      "03:00:00 AM" },
+		{ "%I:%M:%S %p",             "03:00:00 AM" },
+		{ "%S",                      "00" },
+		{ "%s",                      "10800" },
+		{ "%f",                      "125" },
+		{ "%T",                      "03:00:00" },
+		{ "%H:%M:%S",                "03:00:00" },
+		{ "%t",                      "\t" },
+		{ "%U",                      "00" },
+		{ "%u",                      "4" },
+		{ "%G",                      "1970" },
+		{ "%g",                      "70" },
+		{ "%v",                      " 1-Jan-1970" },
+		{ "%e-%b-%Y",                " 1-Jan-1970" },
+		{ "%W",                      "00" },
+		{ "%w",                      "4" },
+		{ "%X",                      "03:00:00" },
+		{ "%x",                      "01/01/70" },
+		{ "%y",                      "70" },
+		{ "%Y",                      "1970" },
+		{ "%z",                      "+0300" },
+		{ "%%",                      "%" },
+		{ "%Y-%m-%dT%H:%M:%S.%9f%z", "1970-01-01T03:00:00.125000000+0300" },
+		{ "%Y-%m-%dT%H:%M:%S.%f%z",  "1970-01-01T03:00:00.125+0300" },
+		{ "%Y-%m-%dT%H:%M:%S.%f",    "1970-01-01T03:00:00.125" },
+		{ "%FT%T.%f",                "1970-01-01T03:00:00.125" },
+		{ "%FT%T.%f%z",              "1970-01-01T03:00:00.125+0300" },
+		{ "%FT%T.%9f%z",             "1970-01-01T03:00:00.125000000+0300" },
+		{ "%Y-%m-%d",                "0000-01-01" },
+		{ "%Y-%m-%d",                "0001-01-01" },
+		{ "%Y-%m-%d",                "9999-01-01" },
+		{ "%Y-%m-%d",                "10000-01-01" },
+		{ "%Y-%m-%d",                "10000-01-01" },
+		{ "%Y-%m-%d",                "5879611-07-11" },
+	};
+
+	for (index = 0; index < lengthof(format_tests); index++) {
+		const char *fmt = format_tests[index].fmt;
+		const char *text = format_tests[index].text;
+		struct tnt_tm date = { .tm_epoch = 0};
+		char *ptr = tnt_strptime(text, fmt, &date);
+		static char buff[DT_TO_STRING_BUFSIZE];
+		tnt_strftime(buff, sizeof(buff), "%FT%T%z", &date);
+		isnt(ptr, NULL, "parse string '%s' using '%s' (result '%s')",
+		     text, fmt, buff);
+	}
+
 	check_plan();
 }