strptime: support everything that strftime supports.

Our strptime was missing `%F`, `%G`, `%g`, `%P`, `%u`, `%V`, and
`%v`. Most of these are already supported upstream (and I've just pulled
their current implementation), but some aren't. We're horribly out of
sync anyway, so I'll upstream the missing pieces and then try to get us
back in sync later.

Test: new tests, but originally found by toybox trying to use %F
Change-Id: Ib1a10801a7a3b9c9189440c3b300109bde535fd9
diff --git a/docs/status.md b/docs/status.md
index 0cbcb47..d6a2f4c 100644
--- a/docs/status.md
+++ b/docs/status.md
@@ -45,14 +45,17 @@
   * `getloadavg` (BSD/GNU extension in <stdlib.h>)
 
 New libc behavior in Q (API level 29):
-  * Whole printf family now supports the GNU `%m` extension, rather than a special-case hack in `syslog`
-  * `popen` now always uses `O_CLOEXEC`, not just with the `e` extension
-  * Bug fixes to handling of UTF-8 U+fffe/U+ffff and code points above U+10ffff
-  * `aligned_alloc` correctly verifies that `size` is a multiple of `alignment`
+  * Whole printf family now supports the GNU `%m` extension, rather than a
+    special-case hack in `syslog`.
+  * `popen` now always uses `O_CLOEXEC`, not just with the `e` extension.
+  * Bug fixes to handling of UTF-8 U+fffe/U+ffff and code points above U+10ffff.
+  * `aligned_alloc` correctly verifies that `size` is a multiple of `alignment`.
   * Using `%n` with the printf family is now reported as a FORTIFY failure.
     Previous versions of Android would ignore the `%n` but not consume the
     corresponding pointer argument, leading to obscure errors. The scanf family
     is unchanged.
+  * Support in strptime for `%F`, `%G`, `%g`, `%P`, `%u`, `%V`, and `%v`.
+    (strftime already supported them all.)
   * [fdsan](fdsan.md) detects common file descriptor errors at runtime.
 
 New libc functions in P (API level 28):
@@ -74,9 +77,9 @@
   * `syncfs`
 
 New libc behavior in P (API level 28):
-  * `%C` and `%S` support in the printf family (previously only the wprintf family supported these)
-  * `%mc`/`%ms`/`%m[` support in the scanf family
-  * `%s` support in strptime (strftime already supported it)
+  * `%C` and `%S` support in the printf family (previously only the wprintf family supported these).
+  * `%mc`/`%ms`/`%m[` support in the scanf family.
+  * `%s` support in strptime (strftime already supported it).
   * Using a `pthread_mutex_t` after it's been destroyed will be detected at
     runtime and reported as a FORTIFY failure.
   * Passing a null `FILE*` or `DIR*` to libc is now detected at runtime and
diff --git a/libc/tzcode/strptime.c b/libc/tzcode/strptime.c
index 0e9a7d3..41eaa9b 100644
--- a/libc/tzcode/strptime.c
+++ b/libc/tzcode/strptime.c
@@ -172,6 +172,12 @@
                 return (NULL);
             break;
 
+        case 'F':  /* The date as "%Y-%m-%d". */
+            _LEGAL_ALT(0);
+            if (!(bp = _strptime(bp, "%Y-%m-%d", tm, cr)))
+                return (NULL);
+            continue;
+
         case 'R':   /* The time as "%H:%M". */
             _LEGAL_ALT(0);
             if (!(bp = _strptime(bp, "%H:%M", tm, cr)))
@@ -190,6 +196,12 @@
                 return (NULL);
             break;
 
+        case 'v':  /* The date as "%e-%b-%Y". */
+            _LEGAL_ALT(0);
+            if (!(bp = _strptime(bp, "%e-%b-%Y", tm, cr)))
+                return (NULL);
+            break;
+
         case 'X':   /* The time, using the locale's format. */
             _LEGAL_ALT(_ALT_E);
             if (!(bp = _strptime(bp, _ctloc(t_fmt), tm, cr)))
@@ -305,6 +317,7 @@
             tm->tm_mon--;
             break;
 
+        case 'P':
         case 'p':   /* The locale's equivalent of AM/PM. */
             _LEGAL_ALT(0);
             /* AM? */
@@ -377,6 +390,33 @@
                 return (NULL);
             break;
 
+        case 'u':  /* The day of week, monday = 1. */
+            _LEGAL_ALT(_ALT_O);
+            if (!(_conv_num(&bp, &i, 1, 7)))
+                return (NULL);
+            tm->tm_wday = i % 7;
+            continue;
+
+        case 'g':  /* The year corresponding to the ISO week
+                    * number but without the century.
+                    */
+            if (!(_conv_num(&bp, &i, 0, 99)))
+                return (NULL);
+            continue;
+
+        case 'G':  /* The year corresponding to the ISO week
+                    * number with century.
+                    */
+            do
+                bp++;
+            while (isdigit(*bp));
+            continue;
+
+        case 'V':  /* The ISO 8601:1988 week number as decimal */
+            if (!(_conv_num(&bp, &i, 0, 53)))
+                return (NULL);
+            continue;
+
         case 'Y':   /* The year. */
             _LEGAL_ALT(_ALT_E);
             if (!(_conv_num(&bp, &i, 0, 9999)))
diff --git a/tests/time_test.cpp b/tests/time_test.cpp
index 637fa85..8653d91 100644
--- a/tests/time_test.cpp
+++ b/tests/time_test.cpp
@@ -296,6 +296,59 @@
   EXPECT_STREQ("09:41:53", buf);
 }
 
+TEST(time, strptime_F) {
+  setenv("TZ", "UTC", 1);
+
+  struct tm tm = {};
+  ASSERT_EQ('\0', *strptime("2019-03-26", "%F", &tm));
+  EXPECT_EQ(119, tm.tm_year);
+  EXPECT_EQ(2, tm.tm_mon);
+  EXPECT_EQ(26, tm.tm_mday);
+}
+
+TEST(time, strptime_P_p) {
+  setenv("TZ", "UTC", 1);
+
+  struct tm tm = {.tm_hour = 12};
+  ASSERT_EQ('\0', *strptime("AM", "%p", &tm));
+  EXPECT_EQ(0, tm.tm_hour);
+
+  tm = {.tm_hour = 12};
+  ASSERT_EQ('\0', *strptime("AM", "%P", &tm));
+  EXPECT_EQ(0, tm.tm_hour);
+}
+
+TEST(time, strptime_u) {
+  setenv("TZ", "UTC", 1);
+
+  struct tm tm = {};
+  ASSERT_EQ('\0', *strptime("2", "%u", &tm));
+  EXPECT_EQ(2, tm.tm_wday);
+}
+
+TEST(time, strptime_v) {
+  setenv("TZ", "UTC", 1);
+
+  struct tm tm = {};
+  ASSERT_EQ('\0', *strptime("26-Mar-1980", "%v", &tm));
+  EXPECT_EQ(80, tm.tm_year);
+  EXPECT_EQ(2, tm.tm_mon);
+  EXPECT_EQ(26, tm.tm_mday);
+}
+
+TEST(time, strptime_V_G_g) {
+  setenv("TZ", "UTC", 1);
+
+  // %V (ISO-8601 week number), %G (year of week number, without century), and
+  // %g (year of week number) have no effect when parsed, and are supported
+  // solely so that it's possible for strptime(3) to parse everything that
+  // strftime(3) can output.
+  struct tm tm = {};
+  ASSERT_EQ('\0', *strptime("1 2 3", "%V %G %g", &tm));
+  struct tm zero = {};
+  EXPECT_TRUE(memcmp(&tm, &zero, sizeof(tm)) == 0);
+}
+
 void SetTime(timer_t t, time_t value_s, time_t value_ns, time_t interval_s, time_t interval_ns) {
   itimerspec ts;
   ts.it_value.tv_sec = value_s;