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 "