Index: trunk/src/VBox/Runtime/common/time/time.cpp
===================================================================
--- trunk/src/VBox/Runtime/common/time/time.cpp	(revision 74149)
+++ trunk/src/VBox/Runtime/common/time/time.cpp	(revision 74150)
@@ -949,4 +949,6 @@
                          : g_aiDayOfYear[pTime->u8Month - 1]);
 
+    pTime->u8WeekDay = UINT8_MAX; /* later */
+
     /*
      * The time part.
@@ -980,9 +982,9 @@
         return NULL;
 
-    /* Just in case there is a fraction of seconds (should be!). */
+    /* We generally put a 9 digit fraction here, but it's entirely optional. */
     if (*pszString == '.')
     {
-        const char * const pszStart = pszString;
-        rc = RTStrToUInt32Ex(pszString + 1, (char **)&pszString, 10, &pTime->u32Nanosecond);
+        const char * const pszStart = ++pszString;
+        rc = RTStrToUInt32Ex(pszString, (char **)&pszString, 10, &pTime->u32Nanosecond);
         if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_CHARS && rc != VWRN_TRAILING_SPACES)
             return NULL;
@@ -1016,5 +1018,5 @@
         pszString++;
         pTime->fFlags &= ~RTTIME_FLAGS_TYPE_MASK;
-        pTime->fFlags |= ~RTTIME_FLAGS_TYPE_UTC;
+        pTime->fFlags |= RTTIME_FLAGS_TYPE_UTC;
         pTime->offUTC = 0;
     }
@@ -1052,4 +1054,6 @@
             return NULL;
 
+    /* Calc week day. */
+    rtTimeNormalizeInternal(pTime);
     return pTime;
 }
@@ -1183,10 +1187,8 @@
 
     /* Optional day of week: */
-    if (RT_C_IS_ALPHA(pszString[0]))
-        pTime->u8WeekDay = UINT8_MAX;
-    else if (pszString[0] != '\0' && pszString[1] != '\0')
-    {
-        uint32_t uWeekDay = RT_MAKE_U32_FROM_U8(RT_C_TO_LOWER(pszString[0]), RT_C_TO_LOWER(pszString[0]),
-                                                RT_C_TO_LOWER(pszString[1]), 0);
+    if (RT_C_IS_ALPHA(pszString[0]) && pszString[1] != '\0')
+    {
+        uint32_t uWeekDay = RT_MAKE_U32_FROM_U8(RT_C_TO_LOWER(pszString[0]), RT_C_TO_LOWER(pszString[1]),
+                                                RT_C_TO_LOWER(pszString[2]), 0);
         if (     uWeekDay == RT_MAKE_U32_FROM_U8('m', 'o', 'n', 0))     pTime->u8WeekDay = 0;
         else if (uWeekDay == RT_MAKE_U32_FROM_U8('t', 'u', 'e', 0))     pTime->u8WeekDay = 1;
@@ -1208,4 +1210,6 @@
             return NULL;
     }
+    else if (RT_C_IS_DIGIT(pszString[0]))
+        pTime->u8WeekDay = UINT8_MAX;
     else
         return NULL;
@@ -1221,6 +1225,6 @@
     if (pszString[0] == '\0' || pszString[1] == '\0' || pszString[2] == '\0')
         return NULL;
-    uint32_t uMonth = RT_MAKE_U32_FROM_U8(RT_C_TO_LOWER(pszString[0]), RT_C_TO_LOWER(pszString[0]),
-                                          RT_C_TO_LOWER(pszString[1]), 0);
+    uint32_t uMonth = RT_MAKE_U32_FROM_U8(RT_C_TO_LOWER(pszString[0]), RT_C_TO_LOWER(pszString[1]),
+                                          RT_C_TO_LOWER(pszString[2]), 0);
     if (     uMonth == RT_MAKE_U32_FROM_U8('j', 'a', 'n', 0))     pTime->u8Month = 1;
     else if (uMonth == RT_MAKE_U32_FROM_U8('f', 'e', 'b', 0))     pTime->u8Month = 2;
@@ -1244,6 +1248,15 @@
 
     /* Year */
+    const char * const pszStartYear = pszString;
     rc = RTStrToInt32Ex(pszString, (char **)&pszString, 10, &pTime->i32Year);
     if (rc != VWRN_TRAILING_CHARS)
+        return NULL;
+    if (pszString - pszStartYear >= 4 )
+    { /* likely */ }
+    else if (pszString - pszStartYear == 3)
+        pTime->i32Year += 1900;
+    else if (pszString - pszStartYear == 2)
+        pTime->i32Year += pTime->i32Year >= 50 ? 1900 : 2000;
+    else
         return NULL;
 
@@ -1296,9 +1309,9 @@
         return NULL;
 
-    /* Nanoseconds  and probably non-standard. */
+    /* Non-standard fraction.  Handy for testing, though. */
     if (*pszString == '.')
     {
-        const char * const pszStart = pszString;
-        rc = RTStrToUInt32Ex(pszString + 1, (char **)&pszString, 10, &pTime->u32Nanosecond);
+        const char * const pszStart = ++pszString;
+        rc = RTStrToUInt32Ex(pszString, (char **)&pszString, 10, &pTime->u32Nanosecond);
         if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_CHARS && rc != VWRN_TRAILING_SPACES)
             return NULL;
@@ -1324,19 +1337,12 @@
     else
         pTime->u32Nanosecond = 0;
+    while (RT_C_IS_SPACE(*pszString))
+        pszString++;
 
     /*
      * Time zone.
      */
-    if (   (pszString[0] == 'G' || pszString[0] == 'g')
-        && (pszString[1] == 'M' || pszString[1] == 'm')
-        && (pszString[2] == 'T' || pszString[2] == 't') )
-    {
-        pszString++;
-        pTime->fFlags &= ~RTTIME_FLAGS_TYPE_MASK;
-        pTime->fFlags |= ~RTTIME_FLAGS_TYPE_UTC;
-        pTime->offUTC = 0;
-    }
-    else if (   *pszString == '+'
-             || *pszString == '-')
+    if (   *pszString == '+'
+        || *pszString == '-')
     {
         if (   !RT_C_IS_DIGIT(pszString[1])
@@ -1344,5 +1350,6 @@
             return NULL;
         int8_t cUtcHours = (pszString[1] - '0') * 10 + (pszString[2] - '0');
-        if (*pszString == '-')
+        char   chSign    = *pszString;
+        if (chSign == '-')
             cUtcHours = -cUtcHours;
         pszString += 3;
@@ -1363,4 +1370,55 @@
         if (RT_ABS(pTime->offUTC) > 840)
             return NULL;
+
+        /* -0000: GMT isn't necessarily the local time zone, so change flags from local to UTC. */
+        if (pTime->offUTC == 0 && chSign == '-')
+        {
+            pTime->fFlags &= ~RTTIME_FLAGS_TYPE_MASK;
+            pTime->fFlags |= RTTIME_FLAGS_TYPE_UTC;
+        }
+    }
+    else if (RT_C_IS_ALPHA(*pszString))
+    {
+        uint32_t uTimeZone = RT_MAKE_U32_FROM_U8(RT_C_TO_LOWER(pszString[0]), RT_C_TO_LOWER(pszString[1]),
+                                                 RT_C_TO_LOWER(pszString[2]), 0);
+        if (uTimeZone == RT_MAKE_U32_FROM_U8('g', 'm', 't', 0))
+        {
+            pTime->fFlags &= ~RTTIME_FLAGS_TYPE_MASK;
+            pTime->fFlags |= RTTIME_FLAGS_TYPE_UTC;
+            pTime->offUTC = 0;
+            pszString += 3;
+        }
+        else if ((uint16_t)uTimeZone == RT_MAKE_U16('u', 't'))
+        {
+            pTime->fFlags &= ~RTTIME_FLAGS_TYPE_MASK;
+            pTime->fFlags |= RTTIME_FLAGS_TYPE_UTC;
+            pTime->offUTC = 0;
+            pszString += 2;
+        }
+        else
+        {
+            static const struct { uint32_t uTimeZone; int32_t offUtc; } s_aLegacyTimeZones[] =
+            {
+                { RT_MAKE_U32_FROM_U8('e', 'd', 't', 0), -4*60 },
+                { RT_MAKE_U32_FROM_U8('e', 's', 't', 0), -5*60 },
+                { RT_MAKE_U32_FROM_U8('c', 'd', 't', 0), -5*60 },
+                { RT_MAKE_U32_FROM_U8('c', 's', 't', 0), -6*60 },
+                { RT_MAKE_U32_FROM_U8('m', 'd', 't', 0), -6*60 },
+                { RT_MAKE_U32_FROM_U8('m', 's', 't', 0), -7*60 },
+                { RT_MAKE_U32_FROM_U8('p', 'd', 't', 0), -7*60 },
+                { RT_MAKE_U32_FROM_U8('p', 's', 't', 0), -8*60 },
+            };
+            size_t i = RT_ELEMENTS(s_aLegacyTimeZones);
+            while (i-- > 0)
+                if (s_aLegacyTimeZones[i].uTimeZone == uTimeZone)
+                {
+                    pTime->fFlags &= ~RTTIME_FLAGS_TYPE_MASK;
+                    pTime->fFlags |= RTTIME_FLAGS_TYPE_LOCAL;
+                    pTime->offUTC = s_aLegacyTimeZones[i].offUtc;
+                    pszString += 3;
+                    break;
+                }
+        }
+
     }
     /* else: No time zone given, local with offUTC = 0. */
@@ -1374,4 +1432,5 @@
             return NULL;
 
+    rtTimeNormalizeInternal(pTime);
     return pTime;
 }
Index: trunk/src/VBox/Runtime/testcase/tstRTTimeSpec.cpp
===================================================================
--- trunk/src/VBox/Runtime/testcase/tstRTTimeSpec.cpp	(revision 74149)
+++ trunk/src/VBox/Runtime/testcase/tstRTTimeSpec.cpp	(revision 74150)
@@ -37,4 +37,5 @@
 #include <iprt/time.h>
 
+#include <iprt/rand.h>
 #include <iprt/test.h>
 #include <iprt/string.h>
@@ -672,10 +673,38 @@
                              szValue, cchResult, a_szExpect, sizeof(a_szExpect) - 1); \
         } while (0)
+#define RTTESTI_CHECK_FROM(a_FromCall) \
+        do { \
+            RTRandBytes(&T2, sizeof(T2)); \
+            PRTTIME pResult = a_FromCall; \
+            if (!pResult) \
+                RTTestFailed(hTest, "%s failed on line " RT_XSTR(__LINE__), #a_FromCall); \
+            else if (memcmp(&T1, &T2, sizeof(T2)) != 0) \
+                RTTestFailed(hTest, "%s produced incorrect result on line " RT_XSTR(__LINE__)": %s", #a_FromCall, ToString(&T2)); \
+        } while (0)
     SET_TIME(&T1, 1969,12,31, 23,59,58,999995000, 365, 2, 0, RTTIME_FLAGS_TYPE_UTC | RTTIME_FLAGS_COMMON_YEAR);
     RTTESTI_CHECK_FMT(RTTimeToRfc2822(&T1, szValue, sizeof(szValue),                    0), "Wed, 31 Dec 1969 23:59:58 -0000");
     RTTESTI_CHECK_FMT(RTTimeToRfc2822(&T1, szValue, sizeof(szValue), RTTIME_RFC2822_F_GMT), "Wed, 31 Dec 1969 23:59:58 GMT");
+    RTTESTI_CHECK_FMT(RTTimeToStringEx(&T1, szValue, sizeof(szValue), 0), "1969-12-31T23:59:58Z");
+    RTTESTI_CHECK_FMT(RTTimeToStringEx(&T1, szValue, sizeof(szValue), 1), "1969-12-31T23:59:58.9Z");
+    RTTESTI_CHECK_FMT(RTTimeToStringEx(&T1, szValue, sizeof(szValue), 5), "1969-12-31T23:59:58.99999Z");
+    RTTESTI_CHECK_FMT(RTTimeToStringEx(&T1, szValue, sizeof(szValue), 9), "1969-12-31T23:59:58.999995000Z");
+    RTTESTI_CHECK_FROM(RTTimeFromString(&T2, "1969-12-31T23:59:58.999995000Z"));
+    RTTESTI_CHECK_FROM(RTTimeFromRfc2822(&T2, "Wed, 31 Dec 1969 23:59:58.999995 GMT"));
+    RTTESTI_CHECK_FROM(RTTimeFromRfc2822(&T2, "Wed, 31 Dec 69 23:59:58.999995 GMT"));
+    RTTESTI_CHECK_FROM(RTTimeFromRfc2822(&T2, "31 Dec 69 23:59:58.999995 GMT"));
+    RTTESTI_CHECK_FROM(RTTimeFromRfc2822(&T2, "31 Dec 1969 23:59:58.999995 GMT"));
+    RTTESTI_CHECK_FROM(RTTimeFromRfc2822(&T2, "31 dec 1969 23:59:58.999995 GMT"));
+    RTTESTI_CHECK_FROM(RTTimeFromRfc2822(&T2, "wEd, 31 Dec 69 23:59:58.999995 UT"));
+
     SET_TIME(&T1, 2018, 9, 6,  4, 9, 8,        0, 249, 3, 0, RTTIME_FLAGS_TYPE_UTC | RTTIME_FLAGS_COMMON_YEAR);
     RTTESTI_CHECK_FMT(RTTimeToRfc2822(&T1, szValue, sizeof(szValue),                    0), "Thu, 6 Sep 2018 04:09:08 -0000");
-    RTTESTI_CHECK_FMT(RTTimeToRfc2822(&T1, szValue, sizeof(szValue), RTTIME_RFC2822_F_GMT), "Thu, 6 Sep 2018 04:09:08 GMT");
+    RTTESTI_CHECK_FMT(RTTimeToStringEx(&T1, szValue, sizeof(szValue), 0), "2018-09-06T04:09:08Z");
+    RTTESTI_CHECK_FROM(RTTimeFromString(&T2, "2018-09-06T04:09:08Z"));
+    RTTESTI_CHECK_FROM(RTTimeFromRfc2822(&T2, "Thu, 6 Sep 2018 04:09:08 -0000"));
+    RTTESTI_CHECK_FROM(RTTimeFromRfc2822(&T2, "Thu, 6 Sep 2018 04:09:08 GMT"));
+    RTTESTI_CHECK_FROM(RTTimeFromRfc2822(&T2, "Thu, 06 Sep 2018 04:09:08 GMT"));
+    RTTESTI_CHECK_FROM(RTTimeFromRfc2822(&T2, "Thu, 00006 Sep 2018 04:09:08 GMT"));
+    RTTESTI_CHECK_FROM(RTTimeFromRfc2822(&T2, " 00006 Sep 2018 04:09:08 GMT "));
+
 
     /*
