Merge "Fix strftime if tm_zone is null."
diff --git a/libc/Android.mk b/libc/Android.mk
index 06dcc66..a89fe23 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -725,6 +725,7 @@
LOCAL_CFLAGS += -DALL_STATE
# Include tzsetwall, timelocal, timegm, time2posix, and posix2time.
LOCAL_CFLAGS += -DSTD_INSPIRED
+# Obviously, we want to be thread-safe.
LOCAL_CFLAGS += -DTHREAD_SAFE
# The name of the tm_gmtoff field in our struct tm.
LOCAL_CFLAGS += -DTM_GMTOFF=tm_gmtoff
@@ -732,6 +733,8 @@
LOCAL_CFLAGS += -DTZDIR=\"/system/usr/share/zoneinfo\"
# Include timezone and daylight globals.
LOCAL_CFLAGS += -DUSG_COMPAT=1
+# Use the empty string (instead of " ") as the timezone abbreviation fallback.
+LOCAL_CFLAGS += -DWILDABBR=\"\"
LOCAL_CFLAGS += -DNO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU
LOCAL_CFLAGS += -Dlint
diff --git a/libc/tzcode/strftime.c b/libc/tzcode/strftime.c
index 10dfb4b..4349cf6 100644
--- a/libc/tzcode/strftime.c
+++ b/libc/tzcode/strftime.c
@@ -502,7 +502,23 @@
continue;
case 'Z':
#ifdef TM_ZONE
- pt = _add(t->TM_ZONE, pt, ptlim, modifier);
+ // BEGIN: Android-changed.
+ {
+ const char* zone = t->TM_ZONE;
+ if (!zone || !*zone) {
+ // "The value of tm_isdst shall be positive if Daylight Savings Time is
+ // in effect, 0 if Daylight Savings Time is not in effect, and negative
+ // if the information is not available."
+ if (t->tm_isdst == 0) zone = tzname[0];
+ else if (t->tm_isdst > 0) zone = tzname[1];
+
+ // "Replaced by the timezone name or abbreviation, or by no bytes if no
+ // timezone information exists."
+ if (!zone || !*zone) zone = "";
+ }
+ pt = _add(zone, pt, ptlim, modifier);
+ }
+ // END: Android-changed.
#else
if (t->tm_isdst >= 0)
pt = _add(tzname[t->tm_isdst != 0],
diff --git a/tests/time_test.cpp b/tests/time_test.cpp
index c685e94..a04c449 100644
--- a/tests/time_test.cpp
+++ b/tests/time_test.cpp
@@ -143,6 +143,44 @@
EXPECT_STREQ("Sun Mar 10 00:00:00 2100", buf);
}
+TEST(time, strftime_null_tm_zone) {
+ // Netflix on Nexus Player wouldn't start (http://b/25170306).
+ struct tm t;
+ memset(&t, 0, sizeof(tm));
+
+ char buf[64];
+
+ setenv("TZ", "America/Los_Angeles", 1);
+ tzset();
+
+ t.tm_isdst = 0; // "0 if Daylight Savings Time is not in effect".
+ EXPECT_EQ(5U, strftime(buf, sizeof(buf), "<%Z>", &t));
+ EXPECT_STREQ("<PST>", buf);
+
+#if defined(__BIONIC__) // glibc 2.19 only copes with tm_isdst being 0 and 1.
+ t.tm_isdst = 2; // "positive if Daylight Savings Time is in effect"
+ EXPECT_EQ(5U, strftime(buf, sizeof(buf), "<%Z>", &t));
+ EXPECT_STREQ("<PDT>", buf);
+
+ t.tm_isdst = -123; // "and negative if the information is not available".
+ EXPECT_EQ(2U, strftime(buf, sizeof(buf), "<%Z>", &t));
+ EXPECT_STREQ("<>", buf);
+#endif
+
+ setenv("TZ", "UTC", 1);
+ tzset();
+
+ t.tm_isdst = 0;
+ EXPECT_EQ(5U, strftime(buf, sizeof(buf), "<%Z>", &t));
+ EXPECT_STREQ("<UTC>", buf);
+
+#if defined(__BIONIC__) // glibc 2.19 thinks UTC DST is "UTC".
+ t.tm_isdst = 1; // UTC has no DST.
+ EXPECT_EQ(2U, strftime(buf, sizeof(buf), "<%Z>", &t));
+ EXPECT_STREQ("<>", buf);
+#endif
+}
+
TEST(time, strptime) {
setenv("TZ", "UTC", 1);