diff --git a/libc/Android.mk b/libc/Android.mk index 06dcc668b..a89fe230b 100644 --- a/libc/Android.mk +++ b/libc/Android.mk @@ -725,6 +725,7 @@ LOCAL_CFLAGS := $(libc_common_cflags) \ 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 += -DTM_GMTOFF=tm_gmtoff 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 10dfb4b6c..4349cf607 100644 --- a/libc/tzcode/strftime.c +++ b/libc/tzcode/strftime.c @@ -502,7 +502,23 @@ label: 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 c685e9478..a04c44976 100644 --- a/tests/time_test.cpp +++ b/tests/time_test.cpp @@ -143,6 +143,44 @@ TEST(time, strftime) { 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("", 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("", 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("", 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);