tree data UPDATE portable timezone fix
diff --git a/CMakeModules/UseCompat.cmake b/CMakeModules/UseCompat.cmake
index 4cc1873..c8daa2d 100644
--- a/CMakeModules/UseCompat.cmake
+++ b/CMakeModules/UseCompat.cmake
@@ -48,10 +48,6 @@
check_include_file("stdatomic.h" HAVE_STDATOMIC)
- include(CheckStructHasMember)
- check_struct_has_member("struct tm" tm_gmtoff time.h HAVE_TM_GMTOFF)
- check_symbol_exists(timezone time.h HAVE_TIME_H_TIMEZONE)
-
check_symbol_exists(realpath "stdlib.h" HAVE_REALPATH)
check_symbol_exists(localtime_r "time.h" HAVE_LOCALTIME_R)
check_symbol_exists(gmtime_r "time.h" HAVE_GMTIME_R)
diff --git a/compat/compat.h.in b/compat/compat.h.in
index 6df7a7b..0fa2fe7 100644
--- a/compat/compat.h.in
+++ b/compat/compat.h.in
@@ -3,7 +3,7 @@
* @author Michal Vasko <mvasko@cesnet.cz>
* @brief compatibility functions header
*
- * Copyright (c) 2021 CESNET, z.s.p.o.
+ * Copyright (c) 2021 - 2023 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
@@ -65,8 +65,6 @@
#cmakedefine HAVE_STRCHRNUL
#cmakedefine HAVE_GET_CURRENT_DIR_NAME
#cmakedefine HAVE_PTHREAD_MUTEX_TIMEDLOCK
-#cmakedefine HAVE_TM_GMTOFF
-#cmakedefine HAVE_TIME_H_TIMEZONE
#cmakedefine HAVE_REALPATH
#cmakedefine HAVE_LOCALTIME_R
#cmakedefine HAVE_GMTIME_R
@@ -189,6 +187,10 @@
struct tm *localtime_r(const time_t *timep, struct tm *result);
#endif
+#ifndef HAVE_GMTIME_R
+struct tm *gmtime_r(const time_t *timep, struct tm *result);
+#endif
+
#ifndef HAVE_TIMEGM
# if defined (_WIN32)
# define timegm _mkgmtime
diff --git a/src/plugins_types/date_and_time.c b/src/plugins_types/date_and_time.c
index 5ccb86d..65132c0 100644
--- a/src/plugins_types/date_and_time.c
+++ b/src/plugins_types/date_and_time.c
@@ -115,11 +115,9 @@
ret = ly_time_str2time(value, &val->time, &val->fractions_s);
LY_CHECK_GOTO(ret, cleanup);
-#ifdef HAVE_TIME_H_TIMEZONE
if (!strncmp(((char *)value + value_len) - 6, "-00:00", 6)) {
/* unknown timezone, move the timestamp to UTC */
- tzset();
- val->time += (time_t)timezone;
+ val->time -= ly_time_tz_offset();
val->unknown_tz = 1;
/* DST may apply, adjust accordingly */
@@ -135,10 +133,6 @@
val->time -= 3600;
}
}
-#else
- (void)tm;
- val->unknown_tz = 1;
-#endif
if (format == LY_VALUE_CANON) {
/* store canonical value */
diff --git a/src/tree_data.h b/src/tree_data.h
index ff98f60..0531f46 100644
--- a/src/tree_data.h
+++ b/src/tree_data.h
@@ -2557,6 +2557,13 @@
LIBYANG_API_DECL LY_ERR lyd_find_target(const struct ly_path *path, const struct lyd_node *tree, struct lyd_node **match);
/**
+ * @brief Get current timezone UTC (GMT) time offset in seconds.
+ *
+ * @return Timezone shift in seconds.
+ */
+LIBYANG_API_DECL int ly_time_tz_offset(void);
+
+/**
* @brief Convert date-and-time from string to UNIX timestamp and fractions of a second.
*
* @param[in] value Valid string date-and-time value.
diff --git a/src/tree_data_common.c b/src/tree_data_common.c
index 5af3c6d..d06d0e8 100644
--- a/src/tree_data_common.c
+++ b/src/tree_data_common.c
@@ -20,6 +20,7 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/time.h>
#include <time.h>
#include "common.h"
@@ -1508,6 +1509,32 @@
return NULL;
}
+LIBYANG_API_DEF int
+ly_time_tz_offset(void)
+{
+ const time_t epoch_plus_11h = 60 * 60 * 11;
+ struct tm tm_local, tm_utc;
+ int result = 0;
+
+ /* init timezone */
+ tzset();
+
+ /* get local and UTC time */
+ localtime_r(&epoch_plus_11h, &tm_local);
+ gmtime_r(&epoch_plus_11h, &tm_utc);
+
+ /* hours shift in seconds */
+ result += (tm_local.tm_hour - tm_utc.tm_hour) * 3600;
+
+ /* minutes shift in seconds */
+ result += (tm_local.tm_min - tm_utc.tm_min) * 60;
+
+ /* seconds shift */
+ result += tm_local.tm_sec - tm_utc.tm_sec;
+
+ return result;
+}
+
LIBYANG_API_DEF LY_ERR
ly_time_str2time(const char *value, time_t *time, char **fractions_s)
{
@@ -1575,41 +1602,24 @@
ly_time_time2str(time_t time, const char *fractions_s, char **str)
{
struct tm tm;
- char zoneshift[8];
- int32_t zonediff_h, zonediff_m;
+ char zoneshift[12];
+ int zonediff_s, zonediff_h, zonediff_m;
LY_CHECK_ARG_RET(NULL, str, LY_EINVAL);
- /* initialize the local timezone */
+ /* init timezone */
tzset();
-#ifdef HAVE_TM_GMTOFF
/* convert */
if (!localtime_r(&time, &tm)) {
return LY_ESYS;
}
/* get timezone offset */
- if (tm.tm_gmtoff == 0) {
- /* time is Zulu (UTC) */
- zonediff_h = 0;
- zonediff_m = 0;
- } else {
- /* timezone offset */
- zonediff_h = tm.tm_gmtoff / 60 / 60;
- zonediff_m = tm.tm_gmtoff / 60 % 60;
- }
+ zonediff_s = ly_time_tz_offset();
+ zonediff_h = zonediff_s / 60 / 60;
+ zonediff_m = zonediff_s / 60 % 60;
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");
-#endif
/* print */
if (asprintf(str, "%04d-%02d-%02dT%02d:%02d:%02d%s%s%s",
diff --git a/tests/utests/types/yang_types.c b/tests/utests/types/yang_types.c
index 7bcb5e6..68e1ec0 100644
--- a/tests/utests/types/yang_types.c
+++ b/tests/utests/types/yang_types.c
@@ -91,7 +91,6 @@
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
/* date-and-time */
-#if defined (HAVE_TM_GMTOFF) && defined (HAVE_TIME_H_TIMEZONE)
TEST_SUCCESS_XML("a", "l", "2005-05-25T23:15:15.88888Z", STRING, "2005-05-25T21:15:15.88888-02:00");
TEST_SUCCESS_XML("a", "l", "2005-05-31T23:15:15-08:59", STRING, "2005-06-01T06:14:15-02:00");
TEST_SUCCESS_XML("a", "l", "2005-05-31T23:15:15-23:00", STRING, "2005-06-01T20:15:15-02:00");
@@ -105,23 +104,6 @@
/* 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");