about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/time/__tz.c20
-rw-r--r--src/time/gmtime_r.c4
-rw-r--r--src/time/strftime.c16
-rw-r--r--src/time/timegm.c4
4 files changed, 36 insertions, 8 deletions
diff --git a/src/time/__tz.c b/src/time/__tz.c
index 36b59802..dfeac519 100644
--- a/src/time/__tz.c
+++ b/src/time/__tz.c
@@ -15,11 +15,12 @@ weak_alias(__tzname, tzname);
 
 static char std_name[TZNAME_MAX+1];
 static char dst_name[TZNAME_MAX+1];
+const char __gmt[] = "GMT";
 
 static int dst_off;
 static int r0[5], r1[5];
 
-static const unsigned char *zi, *trans, *index, *types, *abbrevs;
+static const unsigned char *zi, *trans, *index, *types, *abbrevs, *abbrevs_end;
 static size_t map_size;
 
 static char old_tz_buf[32];
@@ -127,7 +128,7 @@ static void do_tzset()
 		"/usr/share/zoneinfo/\0/share/zoneinfo/\0/etc/zoneinfo/\0";
 
 	s = getenv("TZ");
-	if (!s || !*s) s = "GMT0";
+	if (!s || !*s) s = __gmt;
 
 	if (old_tz && !strcmp(s, old_tz)) return;
 
@@ -184,6 +185,7 @@ static void do_tzset()
 		index = trans + (zi_read32(trans-12) << scale);
 		types = index + zi_read32(trans-12);
 		abbrevs = types + 6*zi_read32(trans-8);
+		abbrevs_end = abbrevs + zi_read32(trans-4);
 		if (zi[map_size-1] == '\n') {
 			for (s = (const char *)zi+map_size-2; *s!='\n'; s--);
 			s++;
@@ -192,7 +194,7 @@ static void do_tzset()
 		}
 	}
 
-	if (!s) s = "GMT0";
+	if (!s) s = __gmt;
 	getname(std_name, &s);
 	__tzname[0] = std_name;
 	__timezone = getoff(&s);
@@ -387,3 +389,15 @@ void __tzset()
 }
 
 weak_alias(__tzset, tzset);
+
+const char *__tm_to_tzname(const struct tm *tm)
+{
+	const void *p = tm->__tm_zone;
+	LOCK(lock);
+	do_tzset();
+	if (p != __gmt && p != __tzname[0] && p != __tzname[1]
+	    && (uintptr_t)p-(uintptr_t)abbrevs >= abbrevs_end - abbrevs)
+		p = "";
+	UNLOCK(lock);
+	return p;
+}
diff --git a/src/time/gmtime_r.c b/src/time/gmtime_r.c
index fee01bd6..8cbdadcb 100644
--- a/src/time/gmtime_r.c
+++ b/src/time/gmtime_r.c
@@ -2,6 +2,8 @@
 #include <errno.h>
 #include "libc.h"
 
+extern const char __gmt[];
+
 struct tm *__gmtime_r(const time_t *restrict t, struct tm *restrict tm)
 {
 	if (__secs_to_tm(*t, tm) < 0) {
@@ -10,7 +12,7 @@ struct tm *__gmtime_r(const time_t *restrict t, struct tm *restrict tm)
 	}
 	tm->tm_isdst = 0;
 	tm->__tm_gmtoff = 0;
-	tm->__tm_zone = "GMT";
+	tm->__tm_zone = __gmt;
 	return tm;
 }
 
diff --git a/src/time/strftime.c b/src/time/strftime.c
index 24000f3b..48f65320 100644
--- a/src/time/strftime.c
+++ b/src/time/strftime.c
@@ -43,6 +43,7 @@ static int week_num(const struct tm *tm)
 	return val;
 }
 
+const char *__tm_to_tzname(const struct tm *);
 size_t __strftime_l(char *restrict, size_t, const char *restrict, const struct tm *restrict, locale_t);
 
 const char *__strftime_fmt_1(char (*s)[100], size_t *l, int f, const struct tm *tm, locale_t loc)
@@ -166,11 +167,20 @@ const char *__strftime_fmt_1(char (*s)[100], size_t *l, int f, const struct tm *
 		width = 4;
 		goto number;
 	case 'z':
-		val = -tm->__tm_gmtoff;
-		*l = snprintf(*s, sizeof *s, "%+.2d%.2d", val/3600, abs(val%3600)/60);
+		if (tm->tm_isdst < 0) {
+			*l = 0;
+			return "";
+		}
+		*l = snprintf(*s, sizeof *s, "%+.2d%.2d",
+			(-tm->__tm_gmtoff)/3600,
+			abs(tm->__tm_gmtoff%3600)/60);
 		return *s;
 	case 'Z':
-		fmt = tm->__tm_zone;
+		if (tm->tm_isdst < 0) {
+			*l = 0;
+			return "";
+		}
+		fmt = __tm_to_tzname(tm);
 		goto string;
 	case '%':
 		*l = 1;
diff --git a/src/time/timegm.c b/src/time/timegm.c
index e7a7939b..b5dae8b6 100644
--- a/src/time/timegm.c
+++ b/src/time/timegm.c
@@ -2,6 +2,8 @@
 #include "time_impl.h"
 #include <errno.h>
 
+extern const char __gmt[];
+
 time_t timegm(struct tm *tm)
 {
 	struct tm new;
@@ -13,6 +15,6 @@ time_t timegm(struct tm *tm)
 	*tm = new;
 	tm->tm_isdst = 0;
 	tm->__tm_gmtoff = 0;
-	tm->__tm_zone = "GMT";
+	tm->__tm_zone = __gmt;
 	return t;
 }