Bug 386742: added a new function, PR_ParseTimeStringToExplodedTime, which
authorwtc%google.com
Tue, 07 Aug 2007 02:13:00 +0000
changeset 3856 0986469ee55f0202b1ef6bfced713c0cec2b86d7
parent 3855 3f940533d93a9047c7aab5cc85658e9a2f6d5e29
child 3857 c66f7fd87e1335a769ccaf95aa46be93ce638f77
push idunknown
push userunknown
push dateunknown
bugs386742
Bug 386742: added a new function, PR_ParseTimeStringToExplodedTime, which is the same as PR_ParseTimeString except that it returns the result in a PRExplodedTime structure. The patch is contributed by Christian Eyrich <ch.ey@gmx.net>. r=wtc. Modified Files: prtime.h nspr.def prtime.c
pr/include/prtime.h
pr/src/misc/prtime.c
pr/src/nspr.def
--- a/pr/include/prtime.h
+++ b/pr/include/prtime.h
@@ -229,18 +229,22 @@ NSPR_API(PRTimeParameters) PR_GMTParamet
 
 /*
  * Time parameters that represent the US Pacific Time Zone, with the
  * current daylight saving time rules (for testing only)
  */
 NSPR_API(PRTimeParameters) PR_USPacificTimeParameters(const PRExplodedTime *gmt);
 
 /*
- * This parses a time/date string into a PRTime
- * (microseconds after "1-Jan-1970 00:00:00 GMT").
+ * This parses a time/date string into a PRExplodedTime
+ * struct. It populates all fields but it can't split
+ * the offset from UTC into tp_gmt_offset and tp_dst_offset in
+ * most cases (exceptions: PST/PDT, MST/MDT, CST/CDT, EST/EDT, GMT/BST).
+ * In those cases tp_gmt_offset will be the sum of these two and
+ * tp_dst_offset will be 0.
  * It returns PR_SUCCESS on success, and PR_FAILURE
  * if the time/date string can't be parsed.
  *
  * Many formats are handled, including:
  *
  *   14 Apr 89 03:20:12
  *   14 Apr 89 03:20 GMT
  *   Fri, 17 Mar 89 4:01:33
@@ -259,16 +263,29 @@ NSPR_API(PRTimeParameters) PR_USPacificT
  *
  * If the input string doesn't contain a description of the timezone,
  * we consult the `default_to_gmt' to decide whether the string should
  * be interpreted relative to the local time zone (PR_FALSE) or GMT (PR_TRUE).
  * The correct value for this argument depends on what standard specified
  * the time string which you are parsing.
  */
 
+NSPR_API(PRStatus) PR_ParseTimeStringToExplodedTime (
+        const char *string,
+        PRBool default_to_gmt,
+        PRExplodedTime *result);
+
+/*
+ * This uses PR_ParseTimeStringToExplodedTime to parse
+ * a time/date string and PR_ImplodeTime to transform it into
+ * a PRTime (microseconds after "1-Jan-1970 00:00:00 GMT").
+ * It returns PR_SUCCESS on success, and PR_FAILURE
+ * if the time/date string can't be parsed.
+ */
+
 NSPR_API(PRStatus) PR_ParseTimeString (
 	const char *string,
 	PRBool default_to_gmt,
 	PRTime *result);
 
 /*
  * FIXME: should we also have a formatting function, such as asctime, ctime,
  * and strftime in standard C library?  But this would involve
--- a/pr/src/misc/prtime.c
+++ b/pr/src/misc/prtime.c
@@ -989,26 +989,26 @@ typedef enum
  * If the input string doesn't contain a description of the timezone,
  * we consult the `default_to_gmt' to decide whether the string should
  * be interpreted relative to the local time zone (PR_FALSE) or GMT (PR_TRUE).
  * The correct value for this argument depends on what standard specified
  * the time string which you are parsing.
  */
 
 PR_IMPLEMENT(PRStatus)
-PR_ParseTimeString(
+PR_ParseTimeStringToExplodedTime(
         const char *string,
         PRBool default_to_gmt,
-        PRTime *result)
+        PRExplodedTime *result)
 {
-  PRExplodedTime tm;
   TIME_TOKEN dotw = TT_UNKNOWN;
   TIME_TOKEN month = TT_UNKNOWN;
   TIME_TOKEN zone = TT_UNKNOWN;
   int zone_offset = -1;
+  int dst_offset = 0;
   int date = -1;
   PRInt32 year = -1;
   int hour = -1;
   int min = -1;
   int sec = -1;
 
   const char *rest = string;
 
@@ -1521,146 +1521,151 @@ PR_ParseTimeString(
 
         }
 
   if (zone != TT_UNKNOWN && zone_offset == -1)
         {
           switch (zone)
                 {
                 case TT_PST: zone_offset = -8 * 60; break;
-                case TT_PDT: zone_offset = -7 * 60; break;
+                case TT_PDT: zone_offset = -8 * 60; dst_offset = 1 * 60; break;
                 case TT_MST: zone_offset = -7 * 60; break;
-                case TT_MDT: zone_offset = -6 * 60; break;
+                case TT_MDT: zone_offset = -7 * 60; dst_offset = 1 * 60; break;
                 case TT_CST: zone_offset = -6 * 60; break;
-                case TT_CDT: zone_offset = -5 * 60; break;
+                case TT_CDT: zone_offset = -6 * 60; dst_offset = 1 * 60; break;
                 case TT_EST: zone_offset = -5 * 60; break;
-                case TT_EDT: zone_offset = -4 * 60; break;
+                case TT_EDT: zone_offset = -5 * 60; dst_offset = 1 * 60; break;
                 case TT_AST: zone_offset = -4 * 60; break;
                 case TT_NST: zone_offset = -3 * 60 - 30; break;
                 case TT_GMT: zone_offset =  0 * 60; break;
-                case TT_BST: zone_offset =  1 * 60; break;
+                case TT_BST: zone_offset =  0 * 60; dst_offset = 1 * 60; break;
                 case TT_MET: zone_offset =  1 * 60; break;
                 case TT_EET: zone_offset =  2 * 60; break;
                 case TT_JST: zone_offset =  9 * 60; break;
                 default:
                   PR_ASSERT (0);
                   break;
                 }
         }
 
   /* If we didn't find a year, month, or day-of-the-month, we can't
          possibly parse this, and in fact, mktime() will do something random
          (I'm seeing it return "Tue Feb  5 06:28:16 2036", which is no doubt
          a numerologically significant date... */
   if (month == TT_UNKNOWN || date == -1 || year == -1)
       return PR_FAILURE;
 
-  memset(&tm, 0, sizeof(tm));
+  memset(result, 0, sizeof(*result));
   if (sec != -1)
-        tm.tm_sec = sec;
+        result->tm_sec = sec;
   if (min != -1)
-  tm.tm_min = min;
+        result->tm_min = min;
   if (hour != -1)
-        tm.tm_hour = hour;
+        result->tm_hour = hour;
   if (date != -1)
-        tm.tm_mday = date;
+        result->tm_mday = date;
   if (month != TT_UNKNOWN)
-        tm.tm_month = (((int)month) - ((int)TT_JAN));
+        result->tm_month = (((int)month) - ((int)TT_JAN));
   if (year != -1)
-        tm.tm_year = year;
+        result->tm_year = year;
   if (dotw != TT_UNKNOWN)
-        tm.tm_wday = (((int)dotw) - ((int)TT_SUN));
+        result->tm_wday = (((int)dotw) - ((int)TT_SUN));
 
   if (zone == TT_UNKNOWN && default_to_gmt)
         {
           /* No zone was specified, so pretend the zone was GMT. */
           zone = TT_GMT;
           zone_offset = 0;
         }
 
   if (zone_offset == -1)
          {
            /* no zone was specified, and we're to assume that everything
              is local. */
           struct tm localTime;
           time_t secs;
 
-          PR_ASSERT(tm.tm_month > -1 
-                                   && tm.tm_mday > 0 
-                                   && tm.tm_hour > -1
-                                   && tm.tm_min > -1
-                                   && tm.tm_sec > -1);
+          PR_ASSERT(result->tm_month > -1 &&
+                    result->tm_mday > 0 &&
+                    result->tm_hour > -1 &&
+                    result->tm_min > -1 &&
+                    result->tm_sec > -1);
 
             /*
              * To obtain time_t from a tm structure representing the local
              * time, we call mktime().  However, we need to see if we are
              * on 1-Jan-1970 or before.  If we are, we can't call mktime()
              * because mktime() will crash on win16. In that case, we
              * calculate zone_offset based on the zone offset at 
              * 00:00:00, 2 Jan 1970 GMT, and subtract zone_offset from the
              * date we are parsing to transform the date to GMT.  We also
              * do so if mktime() returns (time_t) -1 (time out of range).
            */
 
           /* month, day, hours, mins and secs are always non-negative
              so we dont need to worry about them. */  
-            if(tm.tm_year >= 1970)
+          if(result->tm_year >= 1970)
                 {
                   PRInt64 usec_per_sec;
 
-                  localTime.tm_sec = tm.tm_sec;
-                  localTime.tm_min = tm.tm_min;
-                  localTime.tm_hour = tm.tm_hour;
-                  localTime.tm_mday = tm.tm_mday;
-                  localTime.tm_mon = tm.tm_month;
-                  localTime.tm_year = tm.tm_year - 1900;
+                  localTime.tm_sec = result->tm_sec;
+                  localTime.tm_min = result->tm_min;
+                  localTime.tm_hour = result->tm_hour;
+                  localTime.tm_mday = result->tm_mday;
+                  localTime.tm_mon = result->tm_month;
+                  localTime.tm_year = result->tm_year - 1900;
                   /* Set this to -1 to tell mktime "I don't care".  If you set
                      it to 0 or 1, you are making assertions about whether the
                      date you are handing it is in daylight savings mode or not;
                      and if you're wrong, it will "fix" it for you. */
                   localTime.tm_isdst = -1;
                   secs = mktime(&localTime);
                   if (secs != (time_t) -1)
                     {
-#if defined(XP_MAC) && (__MSL__ < 0x6000)
-                      /*
-                       * The mktime() routine in MetroWerks MSL C
-                       * Runtime library returns seconds since midnight,
-                       * 1 Jan. 1900, not 1970 - in versions of MSL (Metrowerks Standard
-                       * Library) prior to version 6.  Only for older versions of
-                       * MSL do we adjust the value of secs to the NSPR epoch
-                       */
-                      secs -= ((365 * 70UL) + 17) * 24 * 60 * 60;
-#endif
-                      LL_I2L(*result, secs);
+                      PRTime usecs64;
+                      LL_I2L(usecs64, secs);
                       LL_I2L(usec_per_sec, PR_USEC_PER_SEC);
-                      LL_MUL(*result, *result, usec_per_sec);
+                      LL_MUL(usecs64, usecs64, usec_per_sec);
+                      PR_ExplodeTime(usecs64, PR_LocalTimeParameters, result);
                       return PR_SUCCESS;
                     }
                 }
                 
                 /* So mktime() can't handle this case.  We assume the
                    zone_offset for the date we are parsing is the same as
                    the zone offset on 00:00:00 2 Jan 1970 GMT. */
                 secs = 86400;
                 (void) MT_safe_localtime(&secs, &localTime);
                 zone_offset = localTime.tm_min
                               + 60 * localTime.tm_hour
                               + 1440 * (localTime.tm_mday - 2);
         }
 
-        /* Adjust the hours and minutes before handing them to
-           PR_ImplodeTime(). Note that it's ok for them to be <0 or >24/60 
+  /* mainly to compute wday and yday */
+  PR_NormalizeTime(result, PR_GMTParameters);
+  result->tm_params.tp_gmt_offset = zone_offset * 60;
+  result->tm_params.tp_dst_offset = dst_offset * 60;
+
+  return PR_SUCCESS;
+}
 
-           We adjust the time to GMT before going into PR_ImplodeTime().
-           The zone_offset represents the difference between the time
-           zone parsed and GMT
-         */
-        tm.tm_hour -= (zone_offset / 60);
-        tm.tm_min  -= (zone_offset % 60);
+PR_IMPLEMENT(PRStatus)
+PR_ParseTimeString(
+        const char *string,
+        PRBool default_to_gmt,
+        PRTime *result)
+{
+  PRExplodedTime tm;
+  PRStatus rv;
+
+  rv = PR_ParseTimeStringToExplodedTime(string,
+                                        default_to_gmt,
+                                        &tm);
+  if (rv != PR_SUCCESS)
+        return rv;
 
   *result = PR_ImplodeTime(&tm);
 
   return PR_SUCCESS;
 }
 
 /*
  *******************************************************************
--- a/pr/src/nspr.def
+++ b/pr/src/nspr.def
@@ -460,8 +460,12 @@ EXPORTS ;-
 		PR_GetAddrInfoByName;
 		PR_GetCanonNameFromAddrInfo;
 ;+} NSPR_4.4;
 ;+
 ;+NSPR_4.6 {
 ;+	global:
 		PR_GetPhysicalMemorySize;
 ;+} NSPR_4.5;
+;+NSPR_4.7 {
+;+	global:
+		PR_ParseTimeStringToExplodedTime;
+;+} NSPR_4.6;