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']");