plugins types FEATURE sort callback in date_time
diff --git a/src/plugins_types/date_and_time.c b/src/plugins_types/date_and_time.c
index b60bf55..1cc0ec4 100644
--- a/src/plugins_types/date_and_time.c
+++ b/src/plugins_types/date_and_time.c
@@ -16,6 +16,7 @@
 
 #include "plugins_types.h"
 
+#include <assert.h>
 #include <ctype.h>
 #include <errno.h>
 #include <stdint.h>
@@ -172,6 +173,91 @@
 }
 
 /**
+ * @brief Decide if @p frac can be represented as zero.
+ *
+ * @param[in] frac Fractions of a second.
+ * @return 1 if @p frac can be represented as zero.
+ * @return 0 @p frac is not zero.
+ */
+static ly_bool
+lyplg_type_fractions_is_zero(char *frac)
+{
+    char *iter;
+
+    if (!frac) {
+        return 1;
+    }
+
+    for (iter = frac; *iter; iter++) {
+        if (*iter != '0') {
+            return 0;
+        }
+    }
+
+    return 1;
+}
+
+/**
+ * @brief Compare @p f1 and @p f2 for sorting.
+ *
+ * @param[in] f1 First fractions of a second.
+ * @param[in] f2 Second fractions of a second.
+ * @return 1 if @p f1 > @p f2.
+ * @return 0 if @p f1 == @p f2.
+ * @return -1 if @p f1 < @p f2.
+ */
+static int
+lyplg_type_sort_by_fractions(char *f1, char *f2)
+{
+    ly_bool f1_is_zero, f2_is_zero;
+    int df;
+
+    f1_is_zero = lyplg_type_fractions_is_zero(f1);
+    f2_is_zero = lyplg_type_fractions_is_zero(f2);
+
+    if (f1_is_zero && !f2_is_zero) {
+        return -1;
+    } else if (!f1_is_zero && f2_is_zero) {
+        return 1;
+    } else if (f1_is_zero && f2_is_zero) {
+        return 0;
+    }
+
+    /* both f1 and f2 have some non-zero number */
+    assert(!f1_is_zero && !f2_is_zero && f1 && f2);
+    df = strcmp(f1, f2);
+    if (df > 0) {
+        return 1;
+    } else if (df < 0) {
+        return -1;
+    } else {
+        return 0;
+    }
+}
+
+/**
+ * @brief Implementation of ::lyplg_type_sort_clb for ietf-yang-types date-and-time type.
+ */
+static int
+lyplg_type_sort_date_and_time(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *val1, const struct lyd_value *val2)
+{
+    struct lyd_value_date_and_time *v1, *v2;
+    double dt;
+
+    LYD_VALUE_GET(val1, v1);
+    LYD_VALUE_GET(val2, v2);
+
+    /* compare timestamps */
+    dt = difftime(v1->time, v2->time);
+    if (dt != 0) {
+        return dt;
+    }
+
+    /* compare second fractions */
+    return lyplg_type_sort_by_fractions(v1->fractions_s, v2->fractions_s);
+}
+
+/**
  * @brief Implementation of ::lyplg_type_print_clb for ietf-yang-types date-and-time type.
  */
 static const void *
@@ -316,7 +402,7 @@
         .plugin.store = lyplg_type_store_date_and_time,
         .plugin.validate = NULL,
         .plugin.compare = lyplg_type_compare_date_and_time,
-        .plugin.sort = NULL,
+        .plugin.sort = lyplg_type_sort_date_and_time,
         .plugin.print = lyplg_type_print_date_and_time,
         .plugin.duplicate = lyplg_type_dup_date_and_time,
         .plugin.free = lyplg_type_free_date_and_time,
diff --git a/tests/utests/types/yang_types.c b/tests/utests/types/yang_types.c
index 56778c4..51a7c7f 100644
--- a/tests/utests/types/yang_types.c
+++ b/tests/utests/types/yang_types.c
@@ -228,6 +228,86 @@
     TEST_SUCCESS_LYB("a\" xmlns:aa=\"urn:tests:a", "l2", "/aa:l2[. = '4']");
 }
 
+static void
+test_sort(void **state)
+{
+    const char *v1, *v2;
+    const char *schema;
+    struct lys_module *mod;
+    struct lyd_value val1 = {0}, val2 = {0};
+    struct lyplg_type *type = lyplg_type_plugin_find("ietf-yang-types", "2013-07-15", "date-and-time");
+    struct lysc_type *lysc_type;
+    struct ly_err_item *err = NULL;
+
+    /* create schema. Prepare common used variables */
+    schema = MODULE_CREATE_YANG("a",
+            "leaf-list ll {type yang:date-and-time;}");
+    UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, &mod);
+    lysc_type = ((struct lysc_node_leaflist *)mod->compiled->data)->type;
+
+    /* v1 > v2, v2 < v1, v1 == v1 */
+    v1 = "2005-05-25T23:15:15Z";
+    assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v1, strlen(v1),
+            0, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &val1, NULL, &err));
+    v2 = "2005-05-25T23:15:14Z";
+    assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v2, strlen(v2),
+            0, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &val2, NULL, &err));
+    assert_true(0 < type->sort(UTEST_LYCTX, &val1, &val2));
+    assert_true(0 > type->sort(UTEST_LYCTX, &val2, &val1));
+    assert_int_equal(0, type->sort(UTEST_LYCTX, &val1, &val1));
+    type->free(UTEST_LYCTX, &val1);
+    type->free(UTEST_LYCTX, &val2);
+
+    /* unknown timezone */
+    v1 = "2005-05-25T23:15:15Z";
+    assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v1, strlen(v1),
+            0, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &val1, NULL, &err));
+    v2 = "2005-05-25T23:15:15-00:00";
+    assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v2, strlen(v2),
+            0, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &val2, NULL, &err));
+    assert_int_equal(0, type->sort(UTEST_LYCTX, &val1, &val2));
+    type->free(UTEST_LYCTX, &val1);
+    type->free(UTEST_LYCTX, &val2);
+
+    /* fractions of a second */
+    v1 = "2005-05-25T23:15:15.88888Z";
+    assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v1, strlen(v1),
+            0, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &val1, NULL, &err));
+    v2 = "2005-05-25T23:15:15.88889Z";
+    assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v2, strlen(v2),
+            0, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &val2, NULL, &err));
+    assert_true(0 > type->sort(UTEST_LYCTX, &val1, &val2));
+    assert_true(0 < type->sort(UTEST_LYCTX, &val2, &val1));
+    assert_int_equal(0, type->sort(UTEST_LYCTX, &val1, &val1));
+    type->free(UTEST_LYCTX, &val1);
+    type->free(UTEST_LYCTX, &val2);
+
+    /* zero fractions of a second */
+    v1 = "2005-05-25T23:15:15.00Z";
+    assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v1, strlen(v1),
+            0, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &val1, NULL, &err));
+    v2 = "2005-05-25T23:15:15Z";
+    assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v2, strlen(v2),
+            0, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &val2, NULL, &err));
+    assert_int_equal(0, type->sort(UTEST_LYCTX, &val1, &val2));
+    assert_int_equal(0, type->sort(UTEST_LYCTX, &val2, &val1));
+    type->free(UTEST_LYCTX, &val1);
+    type->free(UTEST_LYCTX, &val2);
+
+    /* zero fractions of a second and non-zero */
+    v1 = "2005-05-25T23:15:15.00Z";
+    assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v1, strlen(v1),
+            0, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &val1, NULL, &err));
+    v2 = "2005-05-25T23:15:15.0001Z";
+    assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v2, strlen(v2),
+            0, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &val2, NULL, &err));
+    assert_int_equal(-1, type->sort(UTEST_LYCTX, &val1, &val2));
+    assert_int_equal(1, type->sort(UTEST_LYCTX, &val2, &val1));
+    assert_int_equal(0, type->sort(UTEST_LYCTX, &val1, &val1));
+    type->free(UTEST_LYCTX, &val1);
+    type->free(UTEST_LYCTX, &val2);
+}
+
 int
 main(void)
 {
@@ -236,6 +316,7 @@
         UTEST(test_print),
         UTEST(test_duplicate),
         UTEST(test_lyb),
+        UTEST(test_sort),
     };
 
     return cmocka_run_group_tests(tests, NULL, NULL);