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);