tree data BUGFIX local timezone depends on the timestamp

DST setting changes and hence the local timezone may
me a daylight-saving timezone or not.
Refs #3050
diff --git a/src/tree_data.h b/src/tree_data.h
index 9d6bb5b..dddeb6c 100644
--- a/src/tree_data.h
+++ b/src/tree_data.h
@@ -2611,13 +2611,21 @@
 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. Changes based on the current DST setting.
+ * @brief Get current timezone (including DST setting) UTC (GMT) time offset in seconds.
  *
  * @return Timezone shift in seconds.
  */
 LIBYANG_API_DECL int ly_time_tz_offset(void);
 
 /**
+ * @brief Get UTC (GMT) timezone offset in seconds at a specific timestamp (including DST setting).
+ *
+ * @param[in] time Timestamp to get the offset at.
+ * @return Timezone shift in seconds.
+ */
+LIBYANG_API_DECL int ly_time_tz_offset_at(time_t time);
+
+/**
  * @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 316fad4..69c3851 100644
--- a/src/tree_data_common.c
+++ b/src/tree_data_common.c
@@ -1545,23 +1545,35 @@
 LIBYANG_API_DEF int
 ly_time_tz_offset(void)
 {
-    time_t now;
+    return ly_time_tz_offset_at(time(NULL));
+}
+
+LIBYANG_API_DEF int
+ly_time_tz_offset_at(time_t time)
+{
     struct tm tm_local, tm_utc;
     int result = 0;
 
     /* init timezone */
     tzset();
 
-    /* get current timestamp (need to use it to account for DST) */
-    now = time(NULL);
-
     /* get local and UTC time */
-    localtime_r(&now, &tm_local);
-    gmtime_r(&now, &tm_utc);
+    localtime_r(&time, &tm_local);
+    gmtime_r(&time, &tm_utc);
 
-    /* account for year/month/day change by adding/subtracting from the hours */
-    if (tm_local.tm_mday != tm_utc.tm_mday) {
-        tm_local.tm_hour += (tm_local.tm_mday - tm_utc.tm_mday) * 24;
+    /* account for year/month/day change by adding/subtracting from the hours, the change cannot be more than 1 day */
+    if (tm_local.tm_year < tm_utc.tm_year) {
+        tm_utc.tm_hour += 24;
+    } else if (tm_local.tm_year > tm_utc.tm_year) {
+        tm_local.tm_hour += 24;
+    } else if (tm_local.tm_mon < tm_utc.tm_mon) {
+        tm_utc.tm_hour += 24;
+    } else if (tm_local.tm_mon > tm_utc.tm_mon) {
+        tm_local.tm_hour += 24;
+    } else if (tm_local.tm_mday < tm_utc.tm_mday) {
+        tm_utc.tm_hour += 24;
+    } else if (tm_local.tm_mday > tm_utc.tm_mday) {
+        tm_local.tm_hour += 24;
     }
 
     /* hours shift in seconds */
@@ -1657,7 +1669,7 @@
     }
 
     /* get timezone offset (do not use tm_gmtoff to avoid portability problems) */
-    zonediff_s = ly_time_tz_offset();
+    zonediff_s = ly_time_tz_offset_at(time);
     zonediff_h = zonediff_s / 60 / 60;
     zonediff_m = zonediff_s / 60 % 60;
     sprintf(zoneshift, "%+03d:%02d", zonediff_h, zonediff_m);