date and time BUGFIX support for unknown timezone

Fixes #1734
diff --git a/src/plugins_types/date_and_time.c b/src/plugins_types/date_and_time.c
index 6633622..f849c46 100644
--- a/src/plugins_types/date_and_time.c
+++ b/src/plugins_types/date_and_time.c
@@ -20,6 +20,7 @@
 #include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
+#include <time.h>
 
 #include "libyang.h"
 
@@ -33,6 +34,7 @@
  * | Size (B) | Mandatory | Type | Meaning |
  * | :------  | :-------: | :--: | :-----: |
  * | 8        | yes | `time_t *` | UNIX timestamp |
+ * | 1        | no | `int8_t *` | flag whether the value is in the special -00:00 unknown timezone or not |
  * | string length | no | `char *` | string with the fraction digits of a second |
  */
 
@@ -66,7 +68,7 @@
                     "(expected at least 8).", value_len);
             goto cleanup;
         }
-        for (i = 8; i < value_len; ++i) {
+        for (i = 9; i < value_len; ++i) {
             c = ((char *)value)[i];
             if (!isdigit(c)) {
                 ret = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Invalid LYB date-and-time character '%c' "
@@ -79,11 +81,16 @@
         memcpy(&val->time, value, sizeof val->time);
 
         /* store fractions of second */
-        if (value_len > 8) {
-            val->fractions_s = strndup(((char *)value) + 8, value_len - 8);
+        if (value_len > 9) {
+            val->fractions_s = strndup(((char *)value) + 9, value_len - 9);
             LY_CHECK_ERR_GOTO(!val->fractions_s, ret = LY_EMEM, cleanup);
         }
 
+        /* store unknown timezone */
+        if (value_len > 8) {
+            val->unknown_tz = *(((int8_t *)value) + 8) ? 1 : 0;
+        }
+
         /* success */
         goto cleanup;
     }
@@ -106,6 +113,13 @@
     ret = ly_time_str2time(value, &val->time, &val->fractions_s);
     LY_CHECK_GOTO(ret, cleanup);
 
+    if (!strncmp(((char *)value + value_len) - 6, "-00:00", 6)) {
+        /* unknown timezone, move the timestamp to UTC */
+        tzset();
+        val->time += timezone;
+        val->unknown_tz = 1;
+    }
+
     if (format == LY_VALUE_CANON) {
         /* store canonical value */
         if (options & LYPLG_TYPE_STORE_DYNAMIC) {
@@ -144,8 +158,8 @@
     LYD_VALUE_GET(val1, v1);
     LYD_VALUE_GET(val2, v2);
 
-    /* compare timestamp */
-    if (v1->time != v2->time) {
+    /* compare timestamp and unknown tz */
+    if ((v1->time != v2->time) || (v1->unknown_tz != v2->unknown_tz)) {
         return LY_ENOT;
     }
 
@@ -170,16 +184,19 @@
     LYD_VALUE_GET(value, val);
 
     if (format == LY_VALUE_LYB) {
-        if (val->fractions_s) {
-            ret = malloc(8 + strlen(val->fractions_s));
+        if (val->unknown_tz || val->fractions_s) {
+            ret = malloc(8 + 1 + (val->fractions_s ? strlen(val->fractions_s) : 0));
             LY_CHECK_ERR_RET(!ret, LOGMEM(ctx), NULL);
 
             *dynamic = 1;
             if (value_len) {
-                *value_len = 8 + strlen(val->fractions_s);
+                *value_len = 8 + 1 + (val->fractions_s ? strlen(val->fractions_s) : 0);
             }
             memcpy(ret, &val->time, sizeof val->time);
-            memcpy(ret + 8, val->fractions_s, strlen(val->fractions_s));
+            memcpy(ret + 8, &val->unknown_tz, sizeof val->unknown_tz);
+            if (val->fractions_s) {
+                memcpy(ret + 9, val->fractions_s, strlen(val->fractions_s));
+            }
         } else {
             *dynamic = 0;
             if (value_len) {
@@ -197,6 +214,11 @@
             return NULL;
         }
 
+        if (val->unknown_tz) {
+            /* date and time is correct, fix only the timezone */
+            strcpy((ret + strlen(ret)) - 6, "-00:00");
+        }
+
         /* store it */
         if (lydict_insert_zc(ctx, ret, (const char **)&value->_canonical)) {
             LOGMEM(ctx);
@@ -235,8 +257,9 @@
 
     LYD_VALUE_GET(original, orig_val);
 
-    /* copy timestamp */
+    /* copy timestamp and unknown tz */
     dup_val->time = orig_val->time;
+    dup_val->unknown_tz = orig_val->unknown_tz;
 
     /* duplicate second fractions */
     if (orig_val->fractions_s) {
diff --git a/src/tree_data.h b/src/tree_data.h
index 71db8dd..fa52499 100644
--- a/src/tree_data.h
+++ b/src/tree_data.h
@@ -671,6 +671,7 @@
 struct lyd_value_date_and_time {
     time_t time;        /**< UNIX timestamp */
     char *fractions_s;  /**< Optional fractions of a second */
+    ly_bool unknown_tz; /**< Whether the value is in the special -00:00 timezone. */
 };
 
 /**
diff --git a/tests/utests/types/yang_types.c b/tests/utests/types/yang_types.c
index c8540bd..2ed427c 100644
--- a/tests/utests/types/yang_types.c
+++ b/tests/utests/types/yang_types.c
@@ -101,6 +101,10 @@
     /* canonize */
     TEST_SUCCESS_XML("a", "l", "2005-02-29T23:15:15-02:00", STRING, "2005-03-01T23:15:15-02:00");
 
+    /* unknown timezone */
+    TEST_SUCCESS_XML("a", "l", "2017-02-01T00:00:00-00:00", STRING, "2017-02-01T00:00:00-00:00");
+    TEST_SUCCESS_XML("a", "l", "2021-02-29T00:00:00-00:00", STRING, "2021-03-01T00:00:00-00:00");
+
     TEST_ERROR_XML("a", "l", "2005-05-31T23:15:15.-08:00");
     CHECK_LOG_CTX("Unsatisfied pattern - \"2005-05-31T23:15:15.-08:00\" does not conform to "
             "\"\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[\\+\\-]\\d{2}:\\d{2})\".",
@@ -178,6 +182,7 @@
     /* date-and-time */
     TEST_SUCCESS_LYB("a", "l", "2005-05-25T23:15:15.88888Z");
     TEST_SUCCESS_LYB("a", "l", "2005-05-31T23:15:15-08:59");
+    TEST_SUCCESS_LYB("a", "l", "2005-05-01T20:15:15-00:00");
 
     /* xpath1.0 */
     TEST_SUCCESS_LYB("a\" xmlns:aa=\"urn:tests:a", "l2", "/aa:l2[. = '4']");