MSVC: preserve date-and-time with unspecified TZ
This compatibility code was not stable for datetime values with unknown
TZ. I think that the old behavior was not in violation of the YANG
standard, but it was silly anyway -- if there's a timestamp with
"unknown TZ", adding the *local* TZ before storing it doesn't make a lot
of sense.
After this commit, the date-and-time handling on Windows becomes saner.
These timestamps still won't remember their original TZ, but at least
the absolute time will remain unchanged if we interpret "unknown" as
"UTC", *and* there's now roundtrip stability.
Also expand the test coverage a bit.
Fixes: e182a27c Allow building on platforms without `struct tm.tm_gmtoff`, `timezone`, `daylight`
diff --git a/README.md b/README.md
index 4880ad5..28d5447 100644
--- a/README.md
+++ b/README.md
@@ -86,6 +86,7 @@
* [`getopt-win32`](https://github.com/libimobiledevice-win32/getopt)
The Windows version [does not support plugins](https://github.com/CESNET/libyang/commit/323c31221645052e13db83f7d0e6e51c3ce9d802), and the `yanglint` works in a [non-interactive mode](https://github.com/CESNET/libyang/commit/2e3f935ed6f4a47e65b31de5aeebcd8877d5a09b) only.
+On Windows, all YANG date-and-time values are first converted to UTC (if TZ offset was specified), and then returned with "unspecified timezone".
## Building
diff --git a/src/tree_data_helpers.c b/src/tree_data_helpers.c
index f1b453d..c3dc23b 100644
--- a/src/tree_data_helpers.c
+++ b/src/tree_data_helpers.c
@@ -930,12 +930,12 @@
/* initialize the local timezone */
tzset();
+#ifdef HAVE_TM_GMTOFF
/* convert */
if (!localtime_r(&time, &tm)) {
return LY_ESYS;
}
-#ifdef HAVE_TM_GMTOFF
/* get timezone offset */
if (tm.tm_gmtoff == 0) {
/* time is Zulu (UTC) */
@@ -948,6 +948,11 @@
}
sprintf(zoneshift, "%+03d:%02d", zonediff_h, zonediff_m);
#else
+ /* convert */
+ if (!gmtime_r(&time, &tm)) {
+ return LY_ESYS;
+ }
+
(void)zonediff_h;
(void)zonediff_m;
sprintf(zoneshift, "-00:00");
diff --git a/tests/utests/types/yang_types.c b/tests/utests/types/yang_types.c
index 567df72..c3d0ff2 100644
--- a/tests/utests/types/yang_types.c
+++ b/tests/utests/types/yang_types.c
@@ -103,15 +103,29 @@
/* canonize */
TEST_SUCCESS_XML("a", "l", "2005-02-29T23:15:15-02:00", STRING, "2005-03-01T23:15:15-02:00");
- /* unknown timezone */
+ /* fractional hours */
+ TEST_SUCCESS_XML("a", "l", "2005-05-25T23:15:15.88888+04:30", STRING, "2005-05-25T16:45:15.88888-02:00");
+#else
+ /* Tests run with a TZ offset of +02:00, but this platform cannot represent that in time_t,
+ * so libyang always returns unspecified TZ. */
+ TEST_SUCCESS_XML("a", "l", "2005-05-25T23:15:15.88888Z", STRING, "2005-05-25T23:15:15.88888-00:00");
+ TEST_SUCCESS_XML("a", "l", "2005-05-31T23:15:15-08:59", STRING, "2005-06-01T08:14:15-00:00");
+ TEST_SUCCESS_XML("a", "l", "2005-05-31T23:15:15-23:00", STRING, "2005-06-01T22:15:15-00:00");
+
+ /* test 1 second before epoch (mktime returns -1, but it is a correct value), with and without DST */
+ TEST_SUCCESS_XML("a", "l", "1970-01-01T00:59:59-02:00", STRING, "1970-01-01T02:59:59-00:00");
+ TEST_SUCCESS_XML("a", "l", "1969-12-31T23:59:59-02:00", STRING, "1970-01-01T01:59:59-00:00");
+
+ /* canonize */
+ TEST_SUCCESS_XML("a", "l", "2005-02-29T23:15:15-02:00", STRING, "2005-03-02T01:15:15-00:00");
+
+ /* fractional hours */
+ TEST_SUCCESS_XML("a", "l", "2005-05-25T23:15:15.88888+04:30", STRING, "2005-05-25T18:45:15.88888-00:00");
+#endif
+
+ /* unknown timezone -- timezone conversion MUST NOT happen */
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");
-#else
- /* Tests run with a TZ offset of +02:00.
- * Strictly speaking, this result is "not wrong" because we're indeed saying "unspecified TZ". */
- TEST_SUCCESS_XML("a", "l", "2005-05-25T23:15:15.88888Z", STRING, "2005-05-25T21:15:15.88888-00:00");
- TEST_SUCCESS_XML("a", "l", "2005-05-25T23:15:15.88888+04:30", STRING, "2005-05-25T16:45:15.88888-00:00");
-#endif
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 "