LCOV - code coverage report
Current view: top level - nsprpub/pr/src/misc - prtime.c (source / functions) Hit Total Coverage
Test: output.info Lines: 295 816 36.2 %
Date: 2017-07-14 16:53:18 Functions: 4 7 57.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : /*
       7             :  * prtime.c --
       8             :  *
       9             :  *     NSPR date and time functions
      10             :  *
      11             :  */
      12             : 
      13             : #include "prinit.h"
      14             : #include "prtime.h"
      15             : #include "prlock.h"
      16             : #include "prprf.h"
      17             : #include "prlog.h"
      18             : 
      19             : #include <string.h>
      20             : #include <ctype.h>
      21             : #include <errno.h>  /* for EINVAL */
      22             : #include <time.h>
      23             : 
      24             : /* 
      25             :  * The COUNT_LEAPS macro counts the number of leap years passed by
      26             :  * till the start of the given year Y.  At the start of the year 4
      27             :  * A.D. the number of leap years passed by is 0, while at the start of
      28             :  * the year 5 A.D. this count is 1. The number of years divisible by
      29             :  * 100 but not divisible by 400 (the non-leap years) is deducted from
      30             :  * the count to get the correct number of leap years.
      31             :  *
      32             :  * The COUNT_DAYS macro counts the number of days since 01/01/01 till the
      33             :  * start of the given year Y. The number of days at the start of the year
      34             :  * 1 is 0 while the number of days at the start of the year 2 is 365
      35             :  * (which is ((2)-1) * 365) and so on. The reference point is 01/01/01
      36             :  * midnight 00:00:00.
      37             :  */
      38             : 
      39             : #define COUNT_LEAPS(Y)   ( ((Y)-1)/4 - ((Y)-1)/100 + ((Y)-1)/400 )
      40             : #define COUNT_DAYS(Y)  ( ((Y)-1)*365 + COUNT_LEAPS(Y) )
      41             : #define DAYS_BETWEEN_YEARS(A, B)  (COUNT_DAYS(B) - COUNT_DAYS(A))
      42             : 
      43             : /*
      44             :  * Static variables used by functions in this file
      45             :  */
      46             : 
      47             : /*
      48             :  * The following array contains the day of year for the last day of
      49             :  * each month, where index 1 is January, and day 0 is January 1.
      50             :  */
      51             : 
      52             : static const int lastDayOfMonth[2][13] = {
      53             :     {-1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364},
      54             :     {-1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}
      55             : };
      56             : 
      57             : /*
      58             :  * The number of days in a month
      59             :  */
      60             : 
      61             : static const PRInt8 nDays[2][12] = {
      62             :     {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
      63             :     {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
      64             : };
      65             : 
      66             : /*
      67             :  * Declarations for internal functions defined later in this file.
      68             :  */
      69             : 
      70             : static void        ComputeGMT(PRTime time, PRExplodedTime *gmt);
      71             : static int         IsLeapYear(PRInt16 year);
      72             : static void        ApplySecOffset(PRExplodedTime *time, PRInt32 secOffset);
      73             : 
      74             : /*
      75             :  *------------------------------------------------------------------------
      76             :  *
      77             :  * ComputeGMT --
      78             :  *
      79             :  *     Caveats:
      80             :  *     - we ignore leap seconds
      81             :  *
      82             :  *------------------------------------------------------------------------
      83             :  */
      84             : 
      85             : static void
      86          25 : ComputeGMT(PRTime time, PRExplodedTime *gmt)
      87             : {
      88             :     PRInt32 tmp, rem;
      89             :     PRInt32 numDays;
      90             :     PRInt64 numDays64, rem64;
      91             :     int isLeap;
      92             :     PRInt64 sec;
      93             :     PRInt64 usec;
      94             :     PRInt64 usecPerSec;
      95             :     PRInt64 secPerDay;
      96             : 
      97             :     /*
      98             :      * We first do the usec, sec, min, hour thing so that we do not
      99             :      * have to do LL arithmetic.
     100             :      */
     101             : 
     102          25 :     LL_I2L(usecPerSec, 1000000L);
     103          25 :     LL_DIV(sec, time, usecPerSec);
     104          25 :     LL_MOD(usec, time, usecPerSec);
     105          25 :     LL_L2I(gmt->tm_usec, usec);
     106             :     /* Correct for weird mod semantics so the remainder is always positive */
     107          25 :     if (gmt->tm_usec < 0) {
     108             :         PRInt64 one;
     109             : 
     110           0 :         LL_I2L(one, 1L);
     111           0 :         LL_SUB(sec, sec, one);
     112           0 :         gmt->tm_usec += 1000000L;
     113             :     }
     114             : 
     115          25 :     LL_I2L(secPerDay, 86400L);
     116          25 :     LL_DIV(numDays64, sec, secPerDay);
     117          25 :     LL_MOD(rem64, sec, secPerDay);
     118             :     /* We are sure both of these numbers can fit into PRInt32 */
     119          25 :     LL_L2I(numDays, numDays64);
     120          25 :     LL_L2I(rem, rem64);
     121          25 :     if (rem < 0) {
     122           0 :         numDays--;
     123           0 :         rem += 86400L;
     124             :     }
     125             : 
     126             :     /* Compute day of week.  Epoch started on a Thursday. */
     127             : 
     128          25 :     gmt->tm_wday = (numDays + 4) % 7;
     129          25 :     if (gmt->tm_wday < 0) {
     130           0 :         gmt->tm_wday += 7;
     131             :     }
     132             : 
     133             :     /* Compute the time of day. */
     134             : 
     135          25 :     gmt->tm_hour = rem / 3600;
     136          25 :     rem %= 3600;
     137          25 :     gmt->tm_min = rem / 60;
     138          25 :     gmt->tm_sec = rem % 60;
     139             : 
     140             :     /*
     141             :      * Compute the year by finding the 400 year period, then working
     142             :      * down from there.
     143             :      *
     144             :      * Since numDays is originally the number of days since January 1, 1970,
     145             :      * we must change it to be the number of days from January 1, 0001.
     146             :      */
     147             : 
     148          25 :     numDays += 719162;       /* 719162 = days from year 1 up to 1970 */
     149          25 :     tmp = numDays / 146097;  /* 146097 = days in 400 years */
     150          25 :     rem = numDays % 146097;
     151          25 :     gmt->tm_year = tmp * 400 + 1;
     152             : 
     153             :     /* Compute the 100 year period. */
     154             : 
     155          25 :     tmp = rem / 36524;    /* 36524 = days in 100 years */
     156          25 :     rem %= 36524;
     157          25 :     if (tmp == 4) {       /* the 400th year is a leap year */
     158           0 :         tmp = 3;
     159           0 :         rem = 36524;
     160             :     }
     161          25 :     gmt->tm_year += tmp * 100;
     162             : 
     163             :     /* Compute the 4 year period. */
     164             : 
     165          25 :     tmp = rem / 1461;     /* 1461 = days in 4 years */
     166          25 :     rem %= 1461;
     167          25 :     gmt->tm_year += tmp * 4;
     168             : 
     169             :     /* Compute which year in the 4. */
     170             : 
     171          25 :     tmp = rem / 365;
     172          25 :     rem %= 365;
     173          25 :     if (tmp == 4) {       /* the 4th year is a leap year */
     174           0 :         tmp = 3;
     175           0 :         rem = 365;
     176             :     }
     177             : 
     178          25 :     gmt->tm_year += tmp;
     179          25 :     gmt->tm_yday = rem;
     180          25 :     isLeap = IsLeapYear(gmt->tm_year);
     181             : 
     182             :     /* Compute the month and day of month. */
     183             : 
     184          25 :     for (tmp = 1; lastDayOfMonth[isLeap][tmp] < gmt->tm_yday; tmp++) {
     185             :     }
     186          25 :     gmt->tm_month = --tmp;
     187          25 :     gmt->tm_mday = gmt->tm_yday - lastDayOfMonth[isLeap][tmp];
     188             : 
     189          25 :     gmt->tm_params.tp_gmt_offset = 0;
     190          25 :     gmt->tm_params.tp_dst_offset = 0;
     191          25 : }
     192             : 
     193             : 
     194             : /*
     195             :  *------------------------------------------------------------------------
     196             :  *
     197             :  * PR_ExplodeTime --
     198             :  *
     199             :  *     Cf. struct tm *gmtime(const time_t *tp) and
     200             :  *         struct tm *localtime(const time_t *tp)
     201             :  *
     202             :  *------------------------------------------------------------------------
     203             :  */
     204             : 
     205             : PR_IMPLEMENT(void)
     206             : PR_ExplodeTime(
     207             :         PRTime usecs,
     208             :         PRTimeParamFn params,
     209             :         PRExplodedTime *exploded)
     210             : {
     211          25 :     ComputeGMT(usecs, exploded);
     212          25 :     exploded->tm_params = params(exploded);
     213          50 :     ApplySecOffset(exploded, exploded->tm_params.tp_gmt_offset
     214          25 :             + exploded->tm_params.tp_dst_offset);
     215          25 : }
     216             : 
     217             : 
     218             : /*
     219             :  *------------------------------------------------------------------------
     220             :  *
     221             :  * PR_ImplodeTime --
     222             :  *
     223             :  *     Cf. time_t mktime(struct tm *tp)
     224             :  *     Note that 1 year has < 2^25 seconds.  So an PRInt32 is large enough.
     225             :  *
     226             :  *------------------------------------------------------------------------
     227             :  */
     228             : PR_IMPLEMENT(PRTime)
     229             : PR_ImplodeTime(const PRExplodedTime *exploded)
     230             : {
     231             :     PRExplodedTime copy;
     232             :     PRTime retVal;
     233             :     PRInt64 secPerDay, usecPerSec;
     234             :     PRInt64 temp;
     235             :     PRInt64 numSecs64;
     236             :     PRInt32 numDays;
     237             :     PRInt32 numSecs;
     238             : 
     239             :     /* Normalize first.  Do this on our copy */
     240          35 :     copy = *exploded;
     241          35 :     PR_NormalizeTime(&copy, PR_GMTParameters);
     242             : 
     243          35 :     numDays = DAYS_BETWEEN_YEARS(1970, copy.tm_year);
     244             :     
     245          70 :     numSecs = copy.tm_yday * 86400 + copy.tm_hour * 3600
     246          35 :             + copy.tm_min * 60 + copy.tm_sec;
     247             : 
     248          35 :     LL_I2L(temp, numDays);
     249          35 :     LL_I2L(secPerDay, 86400);
     250          35 :     LL_MUL(temp, temp, secPerDay);
     251          35 :     LL_I2L(numSecs64, numSecs);
     252          35 :     LL_ADD(numSecs64, numSecs64, temp);
     253             : 
     254             :     /* apply the GMT and DST offsets */
     255          35 :     LL_I2L(temp,  copy.tm_params.tp_gmt_offset);
     256          35 :     LL_SUB(numSecs64, numSecs64, temp);
     257          35 :     LL_I2L(temp,  copy.tm_params.tp_dst_offset);
     258          35 :     LL_SUB(numSecs64, numSecs64, temp);
     259             : 
     260          35 :     LL_I2L(usecPerSec, 1000000L);
     261          35 :     LL_MUL(temp, numSecs64, usecPerSec);
     262          35 :     LL_I2L(retVal, copy.tm_usec);
     263          35 :     LL_ADD(retVal, retVal, temp);
     264             : 
     265          35 :     return retVal;
     266             : }
     267             : 
     268             : /*
     269             :  *-------------------------------------------------------------------------
     270             :  *
     271             :  * IsLeapYear --
     272             :  *
     273             :  *     Returns 1 if the year is a leap year, 0 otherwise.
     274             :  *
     275             :  *-------------------------------------------------------------------------
     276             :  */
     277             : 
     278         117 : static int IsLeapYear(PRInt16 year)
     279             : {
     280         117 :     if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
     281           0 :         return 1;
     282         117 :     return 0;
     283             : }
     284             : 
     285             : /*
     286             :  * 'secOffset' should be less than 86400 (i.e., a day).
     287             :  * 'time' should point to a normalized PRExplodedTime.
     288             :  */
     289             : 
     290             : static void
     291          70 : ApplySecOffset(PRExplodedTime *time, PRInt32 secOffset)
     292             : {
     293          70 :     time->tm_sec += secOffset;
     294             : 
     295             :     /* Note that in this implementation we do not count leap seconds */
     296          70 :     if (time->tm_sec < 0 || time->tm_sec >= 60) {
     297          25 :         time->tm_min += time->tm_sec / 60;
     298          25 :         time->tm_sec %= 60;
     299          25 :         if (time->tm_sec < 0) {
     300           0 :             time->tm_sec += 60;
     301           0 :             time->tm_min--;
     302             :         }
     303             :     }
     304             : 
     305          70 :     if (time->tm_min < 0 || time->tm_min >= 60) {
     306          25 :         time->tm_hour += time->tm_min / 60;
     307          25 :         time->tm_min %= 60;
     308          25 :         if (time->tm_min < 0) {
     309           0 :             time->tm_min += 60;
     310           0 :             time->tm_hour--;
     311             :         }
     312             :     }
     313             : 
     314          70 :     if (time->tm_hour < 0) {
     315             :         /* Decrement mday, yday, and wday */
     316           0 :         time->tm_hour += 24;
     317           0 :         time->tm_mday--;
     318           0 :         time->tm_yday--;
     319           0 :         if (time->tm_mday < 1) {
     320           0 :             time->tm_month--;
     321           0 :             if (time->tm_month < 0) {
     322           0 :                 time->tm_month = 11;
     323           0 :                 time->tm_year--;
     324           0 :                 if (IsLeapYear(time->tm_year))
     325           0 :                     time->tm_yday = 365;
     326             :                 else
     327           0 :                     time->tm_yday = 364;
     328             :             }
     329           0 :             time->tm_mday = nDays[IsLeapYear(time->tm_year)][time->tm_month];
     330             :         }
     331           0 :         time->tm_wday--;
     332           0 :         if (time->tm_wday < 0)
     333           0 :             time->tm_wday = 6;
     334          70 :     } else if (time->tm_hour > 23) {
     335             :         /* Increment mday, yday, and wday */
     336           2 :         time->tm_hour -= 24;
     337           2 :         time->tm_mday++;
     338           2 :         time->tm_yday++;
     339           4 :         if (time->tm_mday >
     340           2 :                 nDays[IsLeapYear(time->tm_year)][time->tm_month]) {
     341           0 :             time->tm_mday = 1;
     342           0 :             time->tm_month++;
     343           0 :             if (time->tm_month > 11) {
     344           0 :                 time->tm_month = 0;
     345           0 :                 time->tm_year++;
     346           0 :                 time->tm_yday = 0;
     347             :             }
     348             :         }
     349           2 :         time->tm_wday++;
     350           2 :         if (time->tm_wday > 6)
     351           0 :             time->tm_wday = 0;
     352             :     }
     353          70 : }
     354             : 
     355             : PR_IMPLEMENT(void)
     356             : PR_NormalizeTime(PRExplodedTime *time, PRTimeParamFn params)
     357             : {
     358             :     int daysInMonth;
     359             :     PRInt32 numDays;
     360             : 
     361             :     /* Get back to GMT */
     362          90 :     time->tm_sec -= time->tm_params.tp_gmt_offset
     363          45 :             + time->tm_params.tp_dst_offset;
     364          45 :     time->tm_params.tp_gmt_offset = 0;
     365          45 :     time->tm_params.tp_dst_offset = 0;
     366             : 
     367             :     /* Now normalize GMT */
     368             : 
     369          45 :     if (time->tm_usec < 0 || time->tm_usec >= 1000000) {
     370           0 :         time->tm_sec +=  time->tm_usec / 1000000;
     371           0 :         time->tm_usec %= 1000000;
     372           0 :         if (time->tm_usec < 0) {
     373           0 :             time->tm_usec += 1000000;
     374           0 :             time->tm_sec--;
     375             :         }
     376             :     }
     377             : 
     378             :     /* Note that we do not count leap seconds in this implementation */
     379          45 :     if (time->tm_sec < 0 || time->tm_sec >= 60) {
     380           0 :         time->tm_min += time->tm_sec / 60;
     381           0 :         time->tm_sec %= 60;
     382           0 :         if (time->tm_sec < 0) {
     383           0 :             time->tm_sec += 60;
     384           0 :             time->tm_min--;
     385             :         }
     386             :     }
     387             : 
     388          45 :     if (time->tm_min < 0 || time->tm_min >= 60) {
     389           0 :         time->tm_hour += time->tm_min / 60;
     390           0 :         time->tm_min %= 60;
     391           0 :         if (time->tm_min < 0) {
     392           0 :             time->tm_min += 60;
     393           0 :             time->tm_hour--;
     394             :         }
     395             :     }
     396             : 
     397          45 :     if (time->tm_hour < 0 || time->tm_hour >= 24) {
     398           0 :         time->tm_mday += time->tm_hour / 24;
     399           0 :         time->tm_hour %= 24;
     400           0 :         if (time->tm_hour < 0) {
     401           0 :             time->tm_hour += 24;
     402           0 :             time->tm_mday--;
     403             :         }
     404             :     }
     405             : 
     406             :     /* Normalize month and year before mday */
     407          45 :     if (time->tm_month < 0 || time->tm_month >= 12) {
     408           0 :         time->tm_year += time->tm_month / 12;
     409           0 :         time->tm_month %= 12;
     410           0 :         if (time->tm_month < 0) {
     411           0 :             time->tm_month += 12;
     412           0 :             time->tm_year--;
     413             :         }
     414             :     }
     415             : 
     416             :     /* Now that month and year are in proper range, normalize mday */
     417             : 
     418          45 :     if (time->tm_mday < 1) {
     419             :         /* mday too small */
     420             :         do {
     421             :             /* the previous month */
     422           0 :             time->tm_month--;
     423           0 :             if (time->tm_month < 0) {
     424           0 :                 time->tm_month = 11;
     425           0 :                 time->tm_year--;
     426             :             }
     427           0 :             time->tm_mday += nDays[IsLeapYear(time->tm_year)][time->tm_month];
     428           0 :         } while (time->tm_mday < 1);
     429             :     } else {
     430          45 :         daysInMonth = nDays[IsLeapYear(time->tm_year)][time->tm_month];
     431          90 :         while (time->tm_mday > daysInMonth) {
     432             :             /* mday too large */
     433           0 :             time->tm_mday -= daysInMonth;
     434           0 :             time->tm_month++;
     435           0 :             if (time->tm_month > 11) {
     436           0 :                 time->tm_month = 0;
     437           0 :                 time->tm_year++;
     438             :             }
     439           0 :             daysInMonth = nDays[IsLeapYear(time->tm_year)][time->tm_month];
     440             :         }
     441             :     }
     442             : 
     443             :     /* Recompute yday and wday */
     444          90 :     time->tm_yday = time->tm_mday +
     445          45 :             lastDayOfMonth[IsLeapYear(time->tm_year)][time->tm_month];
     446             :             
     447          45 :     numDays = DAYS_BETWEEN_YEARS(1970, time->tm_year) + time->tm_yday;
     448          45 :     time->tm_wday = (numDays + 4) % 7;
     449          45 :     if (time->tm_wday < 0) {
     450           0 :         time->tm_wday += 7;
     451             :     }
     452             : 
     453             :     /* Recompute time parameters */
     454             : 
     455          45 :     time->tm_params = params(time);
     456             : 
     457          90 :     ApplySecOffset(time, time->tm_params.tp_gmt_offset
     458          45 :             + time->tm_params.tp_dst_offset);
     459          45 : }
     460             : 
     461             : 
     462             : /*
     463             :  *-------------------------------------------------------------------------
     464             :  *
     465             :  * PR_LocalTimeParameters --
     466             :  * 
     467             :  *     returns the time parameters for the local time zone
     468             :  *
     469             :  *     The following uses localtime() from the standard C library.
     470             :  *     (time.h)  This is our fallback implementation.  Unix, PC, and BeOS
     471             :  *     use this version.  A platform may have its own machine-dependent
     472             :  *     implementation of this function.
     473             :  *
     474             :  *-------------------------------------------------------------------------
     475             :  */
     476             : 
     477             : #if defined(HAVE_INT_LOCALTIME_R)
     478             : 
     479             : /*
     480             :  * In this case we could define the macro as
     481             :  *     #define MT_safe_localtime(timer, result) \
     482             :  *             (localtime_r(timer, result) == 0 ? result : NULL)
     483             :  * I chose to compare the return value of localtime_r with -1 so 
     484             :  * that I can catch the cases where localtime_r returns a pointer
     485             :  * to struct tm.  The macro definition above would not be able to
     486             :  * detect such mistakes because it is legal to compare a pointer
     487             :  * with 0.
     488             :  */
     489             : 
     490             : #define MT_safe_localtime(timer, result) \
     491             :         (localtime_r(timer, result) == -1 ? NULL: result)
     492             : 
     493             : #elif defined(HAVE_POINTER_LOCALTIME_R)
     494             : 
     495             : #define MT_safe_localtime localtime_r
     496             : 
     497             : #elif defined(_MSC_VER)
     498             : 
     499             : /* Visual C++ has had localtime_s() since Visual C++ 2005. */
     500             : 
     501             : static struct tm *MT_safe_localtime(const time_t *clock, struct tm *result)
     502             : {
     503             :     errno_t err = localtime_s(result, clock);
     504             :     if (err != 0) {
     505             :         errno = err;
     506             :         return NULL;
     507             :     }
     508             :     return result;
     509             : }
     510             : 
     511             : #else
     512             : 
     513             : #define HAVE_LOCALTIME_MONITOR 1  /* We use 'monitor' to serialize our calls
     514             :                                    * to localtime(). */
     515             : static PRLock *monitor = NULL;
     516             : 
     517             : static struct tm *MT_safe_localtime(const time_t *clock, struct tm *result)
     518             : {
     519             :     struct tm *tmPtr;
     520             :     int needLock = PR_Initialized();  /* We need to use a lock to protect
     521             :                                        * against NSPR threads only when the
     522             :                                        * NSPR thread system is activated. */
     523             : 
     524             :     if (needLock) PR_Lock(monitor);
     525             : 
     526             :     /*
     527             :      * Microsoft (all flavors) localtime() returns a NULL pointer if 'clock'
     528             :      * represents a time before midnight January 1, 1970.  In
     529             :      * that case, we also return a NULL pointer and the struct tm
     530             :      * object pointed to by 'result' is not modified.
     531             :      *
     532             :      * Watcom C/C++ 11.0 localtime() treats time_t as unsigned long
     533             :      * hence, does not recognize negative values of clock as pre-1/1/70.
     534             :      * We have to manually check (WIN16 only) for negative value of
     535             :      * clock and return NULL.
     536             :      *
     537             :      * With negative values of clock, OS/2 returns the struct tm for
     538             :      * clock plus ULONG_MAX. So we also have to check for the invalid
     539             :      * structs returned for timezones west of Greenwich when clock == 0.
     540             :      */
     541             :     
     542             :     tmPtr = localtime(clock);
     543             : 
     544             : #if defined(WIN16) || defined(XP_OS2)
     545             :     if ( (PRInt32) *clock < 0 ||
     546             :          ( (PRInt32) *clock == 0 && tmPtr->tm_year != 70))
     547             :         result = NULL;
     548             :     else
     549             :         *result = *tmPtr;
     550             : #else
     551             :     if (tmPtr) {
     552             :         *result = *tmPtr;
     553             :     } else {
     554             :         result = NULL;
     555             :     }
     556             : #endif /* WIN16 */
     557             : 
     558             :     if (needLock) PR_Unlock(monitor);
     559             : 
     560             :     return result;
     561             : }
     562             : 
     563             : #endif  /* definition of MT_safe_localtime() */
     564             : 
     565           3 : void _PR_InitTime(void)
     566             : {
     567             : #ifdef HAVE_LOCALTIME_MONITOR
     568             :     monitor = PR_NewLock();
     569             : #endif
     570             : #ifdef WINCE
     571             :     _MD_InitTime();
     572             : #endif
     573           3 : }
     574             : 
     575           0 : void _PR_CleanupTime(void)
     576             : {
     577             : #ifdef HAVE_LOCALTIME_MONITOR
     578             :     if (monitor) {
     579             :         PR_DestroyLock(monitor);
     580             :         monitor = NULL;
     581             :     }
     582             : #endif
     583             : #ifdef WINCE
     584             :     _MD_CleanupTime();
     585             : #endif
     586           0 : }
     587             : 
     588             : #if defined(XP_UNIX) || defined(XP_PC) || defined(XP_BEOS)
     589             : 
     590             : PR_IMPLEMENT(PRTimeParameters)
     591             : PR_LocalTimeParameters(const PRExplodedTime *gmt)
     592             : {
     593             : 
     594             :     PRTimeParameters retVal;
     595             :     struct tm localTime;
     596             :     struct tm *localTimeResult;
     597             :     time_t secs;
     598             :     PRTime secs64;
     599             :     PRInt64 usecPerSec;
     600             :     PRInt64 usecPerSec_1;
     601             :     PRInt64 maxInt32;
     602             :     PRInt64 minInt32;
     603             :     PRInt32 dayOffset;
     604             :     PRInt32 offset2Jan1970;
     605             :     PRInt32 offsetNew;
     606             :     int isdst2Jan1970;
     607             : 
     608             :     /*
     609             :      * Calculate the GMT offset.  First, figure out what is
     610             :      * 00:00:00 Jan. 2, 1970 GMT (which is exactly a day, or 86400
     611             :      * seconds, since the epoch) in local time.  Then we calculate
     612             :      * the difference between local time and GMT in seconds:
     613             :      *     gmt_offset = local_time - GMT
     614             :      *
     615             :      * Caveat: the validity of this calculation depends on two
     616             :      * assumptions:
     617             :      * 1. Daylight saving time was not in effect on Jan. 2, 1970.
     618             :      * 2. The time zone of the geographic location has not changed
     619             :      *    since Jan. 2, 1970.
     620             :      */
     621             : 
     622          25 :     secs = 86400L;
     623          25 :     localTimeResult = MT_safe_localtime(&secs, &localTime);
     624          25 :     PR_ASSERT(localTimeResult != NULL);
     625          25 :     if (localTimeResult == NULL) {
     626             :         /* Shouldn't happen. Use safe fallback for optimized builds. */
     627           0 :         return PR_GMTParameters(gmt);
     628             :     }
     629             : 
     630             :     /* GMT is 00:00:00, 2nd of Jan. */
     631             : 
     632          50 :     offset2Jan1970 = (PRInt32)localTime.tm_sec 
     633          25 :             + 60L * (PRInt32)localTime.tm_min
     634          50 :             + 3600L * (PRInt32)localTime.tm_hour
     635          25 :             + 86400L * (PRInt32)((PRInt32)localTime.tm_mday - 2L);
     636             : 
     637          25 :     isdst2Jan1970 = localTime.tm_isdst;
     638             : 
     639             :     /*
     640             :      * Now compute DST offset.  We calculate the overall offset
     641             :      * of local time from GMT, similar to above.  The overall
     642             :      * offset has two components: gmt offset and dst offset.
     643             :      * We subtract gmt offset from the overall offset to get
     644             :      * the dst offset.
     645             :      *     overall_offset = local_time - GMT
     646             :      *     overall_offset = gmt_offset + dst_offset
     647             :      * ==> dst_offset = local_time - GMT - gmt_offset
     648             :      */
     649             : 
     650          25 :     secs64 = PR_ImplodeTime(gmt);    /* This is still in microseconds */
     651          25 :     LL_I2L(usecPerSec, PR_USEC_PER_SEC);
     652          25 :     LL_I2L(usecPerSec_1, PR_USEC_PER_SEC - 1);
     653             :     /* Convert to seconds, truncating down (3.1 -> 3 and -3.1 -> -4) */
     654          25 :     if (LL_GE_ZERO(secs64)) {
     655          25 :         LL_DIV(secs64, secs64, usecPerSec);
     656             :     } else {
     657           0 :         LL_NEG(secs64, secs64);
     658           0 :         LL_ADD(secs64, secs64, usecPerSec_1);
     659           0 :         LL_DIV(secs64, secs64, usecPerSec);
     660           0 :         LL_NEG(secs64, secs64);
     661             :     }
     662          25 :     LL_I2L(maxInt32, PR_INT32_MAX);
     663          25 :     LL_I2L(minInt32, PR_INT32_MIN);
     664          25 :     if (LL_CMP(secs64, >, maxInt32) || LL_CMP(secs64, <, minInt32)) {
     665             :         /* secs64 is too large or too small for time_t (32-bit integer) */
     666           0 :         retVal.tp_gmt_offset = offset2Jan1970;
     667           0 :         retVal.tp_dst_offset = 0;
     668           0 :         return retVal;
     669             :     }
     670          25 :     LL_L2I(secs, secs64);
     671             : 
     672             :     /*
     673             :      * On Windows, localtime() (and our MT_safe_localtime() too)
     674             :      * returns a NULL pointer for time before midnight January 1,
     675             :      * 1970 GMT.  In that case, we just use the GMT offset for
     676             :      * Jan 2, 1970 and assume that DST was not in effect.
     677             :      */
     678             : 
     679          25 :     if (MT_safe_localtime(&secs, &localTime) == NULL) {
     680           0 :         retVal.tp_gmt_offset = offset2Jan1970;
     681           0 :         retVal.tp_dst_offset = 0;
     682           0 :         return retVal;
     683             :     }
     684             : 
     685             :     /*
     686             :      * dayOffset is the offset between local time and GMT in 
     687             :      * the day component, which can only be -1, 0, or 1.  We
     688             :      * use the day of the week to compute dayOffset.
     689             :      */
     690             : 
     691          25 :     dayOffset = (PRInt32) localTime.tm_wday - gmt->tm_wday;
     692             : 
     693             :     /*
     694             :      * Need to adjust for wrapping around of day of the week from
     695             :      * 6 back to 0.
     696             :      */
     697             : 
     698          25 :     if (dayOffset == -6) {
     699             :         /* Local time is Sunday (0) and GMT is Saturday (6) */
     700           0 :         dayOffset = 1;
     701          25 :     } else if (dayOffset == 6) {
     702             :         /* Local time is Saturday (6) and GMT is Sunday (0) */
     703           0 :         dayOffset = -1;
     704             :     }
     705             : 
     706          50 :     offsetNew = (PRInt32)localTime.tm_sec - gmt->tm_sec
     707          25 :             + 60L * ((PRInt32)localTime.tm_min - gmt->tm_min)
     708          50 :             + 3600L * ((PRInt32)localTime.tm_hour - gmt->tm_hour)
     709          25 :             + 86400L * (PRInt32)dayOffset;
     710             : 
     711          25 :     if (localTime.tm_isdst <= 0) {
     712             :         /* DST is not in effect */
     713           0 :         retVal.tp_gmt_offset = offsetNew;
     714           0 :         retVal.tp_dst_offset = 0;
     715             :     } else {
     716             :         /* DST is in effect */
     717          25 :         if (isdst2Jan1970 <=0) {
     718             :             /*
     719             :              * DST was not in effect back in 2 Jan. 1970.
     720             :              * Use the offset back then as the GMT offset,
     721             :              * assuming the time zone has not changed since then.
     722             :              */
     723          25 :             retVal.tp_gmt_offset = offset2Jan1970;
     724          25 :             retVal.tp_dst_offset = offsetNew - offset2Jan1970;
     725             :         } else {
     726             :             /*
     727             :              * DST was also in effect back in 2 Jan. 1970.
     728             :              * Then our clever trick (or rather, ugly hack) fails.
     729             :              * We will just assume DST offset is an hour.
     730             :              */
     731           0 :             retVal.tp_gmt_offset = offsetNew - 3600;
     732           0 :             retVal.tp_dst_offset = 3600;
     733             :         }
     734             :     }
     735             :     
     736          25 :     return retVal;
     737             : }
     738             : 
     739             : #endif    /* defined(XP_UNIX) || defined(XP_PC) || defined(XP_BEOS) */
     740             : 
     741             : /*
     742             :  *------------------------------------------------------------------------
     743             :  *
     744             :  * PR_USPacificTimeParameters --
     745             :  *
     746             :  *     The time parameters function for the US Pacific Time Zone.
     747             :  *
     748             :  *------------------------------------------------------------------------
     749             :  */
     750             : 
     751             : /*
     752             :  * Returns the mday of the first sunday of the month, where
     753             :  * mday and wday are for a given day in the month.
     754             :  * mdays start with 1 (e.g. 1..31).  
     755             :  * wdays start with 0 and are in the range 0..6.  0 = Sunday.
     756             :  */
     757             : #define firstSunday(mday, wday) (((mday - wday + 7 - 1) % 7) + 1)
     758             : 
     759             : /*
     760             :  * Returns the mday for the N'th Sunday of the month, where 
     761             :  * mday and wday are for a given day in the month.
     762             :  * mdays start with 1 (e.g. 1..31).  
     763             :  * wdays start with 0 and are in the range 0..6.  0 = Sunday.
     764             :  * N has the following values: 0 = first, 1 = second (etc), -1 = last.
     765             :  * ndays is the number of days in that month, the same value as the 
     766             :  * mday of the last day of the month.
     767             :  */
     768             : static PRInt32 
     769           0 : NthSunday(PRInt32 mday, PRInt32 wday, PRInt32 N, PRInt32 ndays) 
     770             : {
     771           0 :     PRInt32 firstSun = firstSunday(mday, wday);
     772             : 
     773           0 :     if (N < 0) 
     774           0 :         N = (ndays - firstSun) / 7;
     775           0 :     return firstSun + (7 * N);
     776             : }
     777             : 
     778             : typedef struct DSTParams {
     779             :     PRInt8 dst_start_month;       /* 0 = January */
     780             :     PRInt8 dst_start_Nth_Sunday;  /* N as defined above */
     781             :     PRInt8 dst_start_month_ndays; /* ndays as defined above */
     782             :     PRInt8 dst_end_month;         /* 0 = January */
     783             :     PRInt8 dst_end_Nth_Sunday;    /* N as defined above */
     784             :     PRInt8 dst_end_month_ndays;   /* ndays as defined above */
     785             : } DSTParams;
     786             : 
     787             : static const DSTParams dstParams[2] = {
     788             :     /* year < 2007:  First April Sunday - Last October Sunday */
     789             :     { 3, 0, 30, 9, -1, 31 },
     790             :     /* year >= 2007: Second March Sunday - First November Sunday */
     791             :     { 2, 1, 31, 10, 0, 30 }
     792             : };
     793             : 
     794             : PR_IMPLEMENT(PRTimeParameters)
     795             : PR_USPacificTimeParameters(const PRExplodedTime *gmt)
     796             : {
     797             :     const DSTParams *dst;
     798             :     PRTimeParameters retVal;
     799             :     PRExplodedTime st;
     800             : 
     801             :     /*
     802             :      * Based on geographic location and GMT, figure out offset of
     803             :      * standard time from GMT.  In this example implementation, we
     804             :      * assume the local time zone is US Pacific Time.
     805             :      */
     806             : 
     807           0 :     retVal.tp_gmt_offset = -8L * 3600L;
     808             : 
     809             :     /*
     810             :      * Make a copy of GMT.  Note that the tm_params field of this copy
     811             :      * is ignored.
     812             :      */
     813             : 
     814           0 :     st.tm_usec = gmt->tm_usec;
     815           0 :     st.tm_sec = gmt->tm_sec;
     816           0 :     st.tm_min = gmt->tm_min;
     817           0 :     st.tm_hour = gmt->tm_hour;
     818           0 :     st.tm_mday = gmt->tm_mday;
     819           0 :     st.tm_month = gmt->tm_month;
     820           0 :     st.tm_year = gmt->tm_year;
     821           0 :     st.tm_wday = gmt->tm_wday;
     822           0 :     st.tm_yday = gmt->tm_yday;
     823             : 
     824             :     /* Apply the offset to GMT to obtain the local standard time */
     825           0 :     ApplySecOffset(&st, retVal.tp_gmt_offset);
     826             : 
     827           0 :     if (st.tm_year < 2007) { /* first April Sunday - Last October Sunday */
     828           0 :         dst = &dstParams[0];
     829             :     } else {                 /* Second March Sunday - First November Sunday */
     830           0 :         dst = &dstParams[1];
     831             :     }
     832             : 
     833             :     /*
     834             :      * Apply the rules on standard time or GMT to obtain daylight saving
     835             :      * time offset.  In this implementation, we use the US DST rule.
     836             :      */
     837           0 :     if (st.tm_month < dst->dst_start_month) {
     838           0 :         retVal.tp_dst_offset = 0L;
     839           0 :     } else if (st.tm_month == dst->dst_start_month) {
     840           0 :         int NthSun = NthSunday(st.tm_mday, st.tm_wday, 
     841           0 :                                dst->dst_start_Nth_Sunday, 
     842           0 :                                dst->dst_start_month_ndays);
     843           0 :         if (st.tm_mday < NthSun) {              /* Before starting Sunday */
     844           0 :             retVal.tp_dst_offset = 0L;
     845           0 :         } else if (st.tm_mday == NthSun) {      /* Starting Sunday */
     846             :             /* 01:59:59 PST -> 03:00:00 PDT */
     847           0 :             if (st.tm_hour < 2) {
     848           0 :                 retVal.tp_dst_offset = 0L;
     849             :             } else {
     850           0 :                 retVal.tp_dst_offset = 3600L;
     851             :             }
     852             :         } else {                                /* After starting Sunday */
     853           0 :             retVal.tp_dst_offset = 3600L;
     854             :         }
     855           0 :     } else if (st.tm_month < dst->dst_end_month) {
     856           0 :         retVal.tp_dst_offset = 3600L;
     857           0 :     } else if (st.tm_month == dst->dst_end_month) {
     858           0 :         int NthSun = NthSunday(st.tm_mday, st.tm_wday, 
     859           0 :                                dst->dst_end_Nth_Sunday, 
     860           0 :                                dst->dst_end_month_ndays);
     861           0 :         if (st.tm_mday < NthSun) {              /* Before ending Sunday */
     862           0 :             retVal.tp_dst_offset = 3600L;
     863           0 :         } else if (st.tm_mday == NthSun) {      /* Ending Sunday */
     864             :             /* 01:59:59 PDT -> 01:00:00 PST */
     865           0 :             if (st.tm_hour < 1) {
     866           0 :                 retVal.tp_dst_offset = 3600L;
     867             :             } else {
     868           0 :                 retVal.tp_dst_offset = 0L;
     869             :             }
     870             :         } else {                                /* After ending Sunday */
     871           0 :             retVal.tp_dst_offset = 0L;
     872             :         }
     873             :     } else {
     874           0 :         retVal.tp_dst_offset = 0L;
     875             :     }
     876           0 :     return retVal;
     877             : }
     878             : 
     879             : /*
     880             :  *------------------------------------------------------------------------
     881             :  *
     882             :  * PR_GMTParameters --
     883             :  *
     884             :  *     Returns the PRTimeParameters for Greenwich Mean Time.
     885             :  *     Trivially, both the tp_gmt_offset and tp_dst_offset fields are 0.
     886             :  *
     887             :  *------------------------------------------------------------------------
     888             :  */
     889             : 
     890             : PR_IMPLEMENT(PRTimeParameters)
     891             : PR_GMTParameters(const PRExplodedTime *gmt)
     892             : {
     893          45 :     PRTimeParameters retVal = { 0, 0 };
     894          45 :     return retVal;
     895             : }
     896             : 
     897             : /*
     898             :  * The following code implements PR_ParseTimeString().  It is based on
     899             :  * ns/lib/xp/xp_time.c, revision 1.25, by Jamie Zawinski <jwz@netscape.com>.
     900             :  */
     901             : 
     902             : /*
     903             :  * We only recognize the abbreviations of a small subset of time zones
     904             :  * in North America, Europe, and Japan.
     905             :  *
     906             :  * PST/PDT: Pacific Standard/Daylight Time
     907             :  * MST/MDT: Mountain Standard/Daylight Time
     908             :  * CST/CDT: Central Standard/Daylight Time
     909             :  * EST/EDT: Eastern Standard/Daylight Time
     910             :  * AST: Atlantic Standard Time
     911             :  * NST: Newfoundland Standard Time
     912             :  * GMT: Greenwich Mean Time
     913             :  * BST: British Summer Time
     914             :  * MET: Middle Europe Time
     915             :  * EET: Eastern Europe Time
     916             :  * JST: Japan Standard Time
     917             :  */
     918             : 
     919             : typedef enum
     920             : {
     921             :   TT_UNKNOWN,
     922             : 
     923             :   TT_SUN, TT_MON, TT_TUE, TT_WED, TT_THU, TT_FRI, TT_SAT,
     924             : 
     925             :   TT_JAN, TT_FEB, TT_MAR, TT_APR, TT_MAY, TT_JUN,
     926             :   TT_JUL, TT_AUG, TT_SEP, TT_OCT, TT_NOV, TT_DEC,
     927             : 
     928             :   TT_PST, TT_PDT, TT_MST, TT_MDT, TT_CST, TT_CDT, TT_EST, TT_EDT,
     929             :   TT_AST, TT_NST, TT_GMT, TT_BST, TT_MET, TT_EET, TT_JST
     930             : } TIME_TOKEN;
     931             : 
     932             : /*
     933             :  * This parses a time/date string into a PRTime
     934             :  * (microseconds after "1-Jan-1970 00:00:00 GMT").
     935             :  * It returns PR_SUCCESS on success, and PR_FAILURE
     936             :  * if the time/date string can't be parsed.
     937             :  *
     938             :  * Many formats are handled, including:
     939             :  *
     940             :  *   14 Apr 89 03:20:12
     941             :  *   14 Apr 89 03:20 GMT
     942             :  *   Fri, 17 Mar 89 4:01:33
     943             :  *   Fri, 17 Mar 89 4:01 GMT
     944             :  *   Mon Jan 16 16:12 PDT 1989
     945             :  *   Mon Jan 16 16:12 +0130 1989
     946             :  *   6 May 1992 16:41-JST (Wednesday)
     947             :  *   22-AUG-1993 10:59:12.82
     948             :  *   22-AUG-1993 10:59pm
     949             :  *   22-AUG-1993 12:59am
     950             :  *   22-AUG-1993 12:59 PM
     951             :  *   Friday, August 04, 1995 3:54 PM
     952             :  *   06/21/95 04:24:34 PM
     953             :  *   20/06/95 21:07
     954             :  *   95-06-08 19:32:48 EDT
     955             :  *
     956             :  * If the input string doesn't contain a description of the timezone,
     957             :  * we consult the `default_to_gmt' to decide whether the string should
     958             :  * be interpreted relative to the local time zone (PR_FALSE) or GMT (PR_TRUE).
     959             :  * The correct value for this argument depends on what standard specified
     960             :  * the time string which you are parsing.
     961             :  */
     962             : 
     963             : PR_IMPLEMENT(PRStatus)
     964             : PR_ParseTimeStringToExplodedTime(
     965             :         const char *string,
     966             :         PRBool default_to_gmt,
     967             :         PRExplodedTime *result)
     968             : {
     969          10 :   TIME_TOKEN dotw = TT_UNKNOWN;
     970          10 :   TIME_TOKEN month = TT_UNKNOWN;
     971          10 :   TIME_TOKEN zone = TT_UNKNOWN;
     972          10 :   int zone_offset = -1;
     973          10 :   int dst_offset = 0;
     974          10 :   int date = -1;
     975          10 :   PRInt32 year = -1;
     976          10 :   int hour = -1;
     977          10 :   int min = -1;
     978          10 :   int sec = -1;
     979             :   struct tm *localTimeResult;
     980             : 
     981          10 :   const char *rest = string;
     982             : 
     983          10 :   int iterations = 0;
     984             : 
     985          10 :   PR_ASSERT(string && result);
     986          10 :   if (!string || !result) return PR_FAILURE;
     987             : 
     988          80 :   while (*rest)
     989             :         {
     990             : 
     991          60 :           if (iterations++ > 1000)
     992             :                 {
     993           0 :                   return PR_FAILURE;
     994             :                 }
     995             : 
     996          60 :           switch (*rest)
     997             :                 {
     998             :                 case 'a': case 'A':
     999           0 :                   if (month == TT_UNKNOWN &&
    1000           0 :                           (rest[1] == 'p' || rest[1] == 'P') &&
    1001           0 :                           (rest[2] == 'r' || rest[2] == 'R'))
    1002           0 :                         month = TT_APR;
    1003           0 :                   else if (zone == TT_UNKNOWN &&
    1004           0 :                                    (rest[1] == 's' || rest[1] == 'S') &&
    1005           0 :                                    (rest[2] == 't' || rest[2] == 'T'))
    1006           0 :                         zone = TT_AST;
    1007           0 :                   else if (month == TT_UNKNOWN &&
    1008           0 :                                    (rest[1] == 'u' || rest[1] == 'U') &&
    1009           0 :                                    (rest[2] == 'g' || rest[2] == 'G'))
    1010           0 :                         month = TT_AUG;
    1011           0 :                   break;
    1012             :                 case 'b': case 'B':
    1013           0 :                   if (zone == TT_UNKNOWN &&
    1014           0 :                           (rest[1] == 's' || rest[1] == 'S') &&
    1015           0 :                           (rest[2] == 't' || rest[2] == 'T'))
    1016           0 :                         zone = TT_BST;
    1017           0 :                   break;
    1018             :                 case 'c': case 'C':
    1019           0 :                   if (zone == TT_UNKNOWN &&
    1020           0 :                           (rest[1] == 'd' || rest[1] == 'D') &&
    1021           0 :                           (rest[2] == 't' || rest[2] == 'T'))
    1022           0 :                         zone = TT_CDT;
    1023           0 :                   else if (zone == TT_UNKNOWN &&
    1024           0 :                                    (rest[1] == 's' || rest[1] == 'S') &&
    1025           0 :                                    (rest[2] == 't' || rest[2] == 'T'))
    1026           0 :                         zone = TT_CST;
    1027           0 :                   break;
    1028             :                 case 'd': case 'D':
    1029           0 :                   if (month == TT_UNKNOWN &&
    1030           0 :                           (rest[1] == 'e' || rest[1] == 'E') &&
    1031           0 :                           (rest[2] == 'c' || rest[2] == 'C'))
    1032           0 :                         month = TT_DEC;
    1033           0 :                   break;
    1034             :                 case 'e': case 'E':
    1035           0 :                   if (zone == TT_UNKNOWN &&
    1036           0 :                           (rest[1] == 'd' || rest[1] == 'D') &&
    1037           0 :                           (rest[2] == 't' || rest[2] == 'T'))
    1038           0 :                         zone = TT_EDT;
    1039           0 :                   else if (zone == TT_UNKNOWN &&
    1040           0 :                                    (rest[1] == 'e' || rest[1] == 'E') &&
    1041           0 :                                    (rest[2] == 't' || rest[2] == 'T'))
    1042           0 :                         zone = TT_EET;
    1043           0 :                   else if (zone == TT_UNKNOWN &&
    1044           0 :                                    (rest[1] == 's' || rest[1] == 'S') &&
    1045           0 :                                    (rest[2] == 't' || rest[2] == 'T'))
    1046           0 :                         zone = TT_EST;
    1047           0 :                   break;
    1048             :                 case 'f': case 'F':
    1049          16 :                   if (month == TT_UNKNOWN &&
    1050          16 :                           (rest[1] == 'e' || rest[1] == 'E') &&
    1051           0 :                           (rest[2] == 'b' || rest[2] == 'B'))
    1052           0 :                         month = TT_FEB;
    1053          16 :                   else if (dotw == TT_UNKNOWN &&
    1054          16 :                                    (rest[1] == 'r' || rest[1] == 'R') &&
    1055           8 :                                    (rest[2] == 'i' || rest[2] == 'I'))
    1056           8 :                         dotw = TT_FRI;
    1057           8 :                   break;
    1058             :                 case 'g': case 'G':
    1059          20 :                   if (zone == TT_UNKNOWN &&
    1060          30 :                           (rest[1] == 'm' || rest[1] == 'M') &&
    1061          20 :                           (rest[2] == 't' || rest[2] == 'T'))
    1062          10 :                         zone = TT_GMT;
    1063          10 :                   break;
    1064             :                 case 'j': case 'J':
    1065          20 :                   if (month == TT_UNKNOWN &&
    1066          20 :                           (rest[1] == 'a' || rest[1] == 'A') &&
    1067           0 :                           (rest[2] == 'n' || rest[2] == 'N'))
    1068           0 :                         month = TT_JAN;
    1069          20 :                   else if (zone == TT_UNKNOWN &&
    1070          20 :                                    (rest[1] == 's' || rest[1] == 'S') &&
    1071           0 :                                    (rest[2] == 't' || rest[2] == 'T'))
    1072           0 :                         zone = TT_JST;
    1073          20 :                   else if (month == TT_UNKNOWN &&
    1074          20 :                                    (rest[1] == 'u' || rest[1] == 'U') &&
    1075          10 :                                    (rest[2] == 'l' || rest[2] == 'L'))
    1076          10 :                         month = TT_JUL;
    1077           0 :                   else if (month == TT_UNKNOWN &&
    1078           0 :                                    (rest[1] == 'u' || rest[1] == 'U') &&
    1079           0 :                                    (rest[2] == 'n' || rest[2] == 'N'))
    1080           0 :                         month = TT_JUN;
    1081          10 :                   break;
    1082             :                 case 'm': case 'M':
    1083           4 :                   if (month == TT_UNKNOWN &&
    1084           4 :                           (rest[1] == 'a' || rest[1] == 'A') &&
    1085           0 :                           (rest[2] == 'r' || rest[2] == 'R'))
    1086           0 :                         month = TT_MAR;
    1087           4 :                   else if (month == TT_UNKNOWN &&
    1088           4 :                                    (rest[1] == 'a' || rest[1] == 'A') &&
    1089           0 :                                    (rest[2] == 'y' || rest[2] == 'Y'))
    1090           0 :                         month = TT_MAY;
    1091           4 :                   else if (zone == TT_UNKNOWN &&
    1092           4 :                                    (rest[1] == 'd' || rest[1] == 'D') &&
    1093           0 :                                    (rest[2] == 't' || rest[2] == 'T'))
    1094           0 :                         zone = TT_MDT;
    1095           4 :                   else if (zone == TT_UNKNOWN &&
    1096           4 :                                    (rest[1] == 'e' || rest[1] == 'E') &&
    1097           0 :                                    (rest[2] == 't' || rest[2] == 'T'))
    1098           0 :                         zone = TT_MET;
    1099           4 :                   else if (dotw == TT_UNKNOWN &&
    1100           4 :                                    (rest[1] == 'o' || rest[1] == 'O') &&
    1101           2 :                                    (rest[2] == 'n' || rest[2] == 'N'))
    1102           2 :                         dotw = TT_MON;
    1103           0 :                   else if (zone == TT_UNKNOWN &&
    1104           0 :                                    (rest[1] == 's' || rest[1] == 'S') &&
    1105           0 :                                    (rest[2] == 't' || rest[2] == 'T'))
    1106           0 :                         zone = TT_MST;
    1107           2 :                   break;
    1108             :                 case 'n': case 'N':
    1109           0 :                   if (month == TT_UNKNOWN &&
    1110           0 :                           (rest[1] == 'o' || rest[1] == 'O') &&
    1111           0 :                           (rest[2] == 'v' || rest[2] == 'V'))
    1112           0 :                         month = TT_NOV;
    1113           0 :                   else if (zone == TT_UNKNOWN &&
    1114           0 :                                    (rest[1] == 's' || rest[1] == 'S') &&
    1115           0 :                                    (rest[2] == 't' || rest[2] == 'T'))
    1116           0 :                         zone = TT_NST;
    1117           0 :                   break;
    1118             :                 case 'o': case 'O':
    1119           0 :                   if (month == TT_UNKNOWN &&
    1120           0 :                           (rest[1] == 'c' || rest[1] == 'C') &&
    1121           0 :                           (rest[2] == 't' || rest[2] == 'T'))
    1122           0 :                         month = TT_OCT;
    1123           0 :                   break;
    1124             :                 case 'p': case 'P':
    1125           0 :                   if (zone == TT_UNKNOWN &&
    1126           0 :                           (rest[1] == 'd' || rest[1] == 'D') &&
    1127           0 :                           (rest[2] == 't' || rest[2] == 'T'))
    1128           0 :                         zone = TT_PDT;
    1129           0 :                   else if (zone == TT_UNKNOWN &&
    1130           0 :                                    (rest[1] == 's' || rest[1] == 'S') &&
    1131           0 :                                    (rest[2] == 't' || rest[2] == 'T'))
    1132           0 :                         zone = TT_PST;
    1133           0 :                   break;
    1134             :                 case 's': case 'S':
    1135           0 :                   if (dotw == TT_UNKNOWN &&
    1136           0 :                           (rest[1] == 'a' || rest[1] == 'A') &&
    1137           0 :                           (rest[2] == 't' || rest[2] == 'T'))
    1138           0 :                         dotw = TT_SAT;
    1139           0 :                   else if (month == TT_UNKNOWN &&
    1140           0 :                                    (rest[1] == 'e' || rest[1] == 'E') &&
    1141           0 :                                    (rest[2] == 'p' || rest[2] == 'P'))
    1142           0 :                         month = TT_SEP;
    1143           0 :                   else if (dotw == TT_UNKNOWN &&
    1144           0 :                                    (rest[1] == 'u' || rest[1] == 'U') &&
    1145           0 :                                    (rest[2] == 'n' || rest[2] == 'N'))
    1146           0 :                         dotw = TT_SUN;
    1147           0 :                   break;
    1148             :                 case 't': case 'T':
    1149           0 :                   if (dotw == TT_UNKNOWN &&
    1150           0 :                           (rest[1] == 'h' || rest[1] == 'H') &&
    1151           0 :                           (rest[2] == 'u' || rest[2] == 'U'))
    1152           0 :                         dotw = TT_THU;
    1153           0 :                   else if (dotw == TT_UNKNOWN &&
    1154           0 :                                    (rest[1] == 'u' || rest[1] == 'U') &&
    1155           0 :                                    (rest[2] == 'e' || rest[2] == 'E'))
    1156           0 :                         dotw = TT_TUE;
    1157           0 :                   break;
    1158             :                 case 'u': case 'U':
    1159           0 :                   if (zone == TT_UNKNOWN &&
    1160           0 :                           (rest[1] == 't' || rest[1] == 'T') &&
    1161           0 :                           !(rest[2] >= 'A' && rest[2] <= 'Z') &&
    1162           0 :                           !(rest[2] >= 'a' && rest[2] <= 'z'))
    1163             :                         /* UT is the same as GMT but UTx is not. */
    1164           0 :                         zone = TT_GMT;
    1165           0 :                   break;
    1166             :                 case 'w': case 'W':
    1167           0 :                   if (dotw == TT_UNKNOWN &&
    1168           0 :                           (rest[1] == 'e' || rest[1] == 'E') &&
    1169           0 :                           (rest[2] == 'd' || rest[2] == 'D'))
    1170           0 :                         dotw = TT_WED;
    1171           0 :                   break;
    1172             : 
    1173             :                 case '+': case '-':
    1174             :                   {
    1175             :                         const char *end;
    1176             :                         int sign;
    1177           0 :                         if (zone_offset != -1)
    1178             :                           {
    1179             :                                 /* already got one... */
    1180           0 :                                 rest++;
    1181           0 :                                 break;
    1182             :                           }
    1183           0 :                         if (zone != TT_UNKNOWN && zone != TT_GMT)
    1184             :                           {
    1185             :                                 /* GMT+0300 is legal, but PST+0300 is not. */
    1186           0 :                                 rest++;
    1187           0 :                                 break;
    1188             :                           }
    1189             : 
    1190           0 :                         sign = ((*rest == '+') ? 1 : -1);
    1191           0 :                         rest++; /* move over sign */
    1192           0 :                         end = rest;
    1193           0 :                         while (*end >= '0' && *end <= '9')
    1194           0 :                           end++;
    1195           0 :                         if (rest == end) /* no digits here */
    1196           0 :                           break;
    1197             : 
    1198           0 :                         if ((end - rest) == 4)
    1199             :                           /* offset in HHMM */
    1200           0 :                           zone_offset = (((((rest[0]-'0')*10) + (rest[1]-'0')) * 60) +
    1201           0 :                                                          (((rest[2]-'0')*10) + (rest[3]-'0')));
    1202           0 :                         else if ((end - rest) == 2)
    1203             :                           /* offset in hours */
    1204           0 :                           zone_offset = (((rest[0]-'0')*10) + (rest[1]-'0')) * 60;
    1205           0 :                         else if ((end - rest) == 1)
    1206             :                           /* offset in hours */
    1207           0 :                           zone_offset = (rest[0]-'0') * 60;
    1208             :                         else
    1209             :                           /* 3 or >4 */
    1210           0 :                           break;
    1211             : 
    1212           0 :                         zone_offset *= sign;
    1213           0 :                         zone = TT_GMT;
    1214           0 :                         break;
    1215             :                   }
    1216             : 
    1217             :                 case '0': case '1': case '2': case '3': case '4':
    1218             :                 case '5': case '6': case '7': case '8': case '9':
    1219             :                   {
    1220          30 :                         int tmp_hour = -1;
    1221          30 :                         int tmp_min = -1;
    1222          30 :                         int tmp_sec = -1;
    1223          30 :                         const char *end = rest + 1;
    1224         110 :                         while (*end >= '0' && *end <= '9')
    1225          50 :                           end++;
    1226             : 
    1227             :                         /* end is now the first character after a range of digits. */
    1228             : 
    1229          30 :                         if (*end == ':')
    1230             :                           {
    1231          10 :                                 if (hour >= 0 && min >= 0) /* already got it */
    1232           0 :                                   break;
    1233             : 
    1234             :                                 /* We have seen "[0-9]+:", so this is probably HH:MM[:SS] */
    1235          10 :                                 if ((end - rest) > 2)
    1236             :                                   /* it is [0-9][0-9][0-9]+: */
    1237           0 :                                   break;
    1238          10 :                                 if ((end - rest) == 2)
    1239          20 :                                   tmp_hour = ((rest[0]-'0')*10 +
    1240          10 :                                                           (rest[1]-'0'));
    1241             :                                 else
    1242           0 :                                   tmp_hour = (rest[0]-'0');
    1243             : 
    1244             :                                 /* move over the colon, and parse minutes */
    1245             : 
    1246          10 :                                 rest = ++end;
    1247          40 :                                 while (*end >= '0' && *end <= '9')
    1248          20 :                                   end++;
    1249             : 
    1250          10 :                                 if (end == rest)
    1251             :                                   /* no digits after first colon? */
    1252           0 :                                   break;
    1253          10 :                                 if ((end - rest) > 2)
    1254             :                                   /* it is [0-9][0-9][0-9]+: */
    1255           0 :                                   break;
    1256          10 :                                 if ((end - rest) == 2)
    1257          20 :                                   tmp_min = ((rest[0]-'0')*10 +
    1258          10 :                                              (rest[1]-'0'));
    1259             :                                 else
    1260           0 :                                   tmp_min = (rest[0]-'0');
    1261             : 
    1262             :                                 /* now go for seconds */
    1263          10 :                                 rest = end;
    1264          10 :                                 if (*rest == ':')
    1265          10 :                                   rest++;
    1266          10 :                                 end = rest;
    1267          40 :                                 while (*end >= '0' && *end <= '9')
    1268          20 :                                   end++;
    1269             : 
    1270          10 :                                 if (end == rest)
    1271             :                                   /* no digits after second colon - that's ok. */
    1272             :                                   ;
    1273          10 :                                 else if ((end - rest) > 2)
    1274             :                                   /* it is [0-9][0-9][0-9]+: */
    1275           0 :                                   break;
    1276          10 :                                 if ((end - rest) == 2)
    1277          20 :                                   tmp_sec = ((rest[0]-'0')*10 +
    1278          10 :                                                          (rest[1]-'0'));
    1279             :                                 else
    1280           0 :                                   tmp_sec = (rest[0]-'0');
    1281             : 
    1282             :                                 /* If we made it here, we've parsed hour and min,
    1283             :                                    and possibly sec, so it worked as a unit. */
    1284             : 
    1285             :                                 /* skip over whitespace and see if there's an AM or PM
    1286             :                                    directly following the time.
    1287             :                                  */
    1288          10 :                                 if (tmp_hour <= 12)
    1289             :                                   {
    1290           2 :                                         const char *s = end;
    1291           6 :                                         while (*s && (*s == ' ' || *s == '\t'))
    1292           2 :                                           s++;
    1293           2 :                                         if ((s[0] == 'p' || s[0] == 'P') &&
    1294           0 :                                                 (s[1] == 'm' || s[1] == 'M'))
    1295             :                                           /* 10:05pm == 22:05, and 12:05pm == 12:05 */
    1296           0 :                                           tmp_hour = (tmp_hour == 12 ? 12 : tmp_hour + 12);
    1297           2 :                                         else if (tmp_hour == 12 &&
    1298           0 :                                                          (s[0] == 'a' || s[0] == 'A') &&
    1299           0 :                                                          (s[1] == 'm' || s[1] == 'M'))
    1300             :                                           /* 12:05am == 00:05 */
    1301           0 :                                           tmp_hour = 0;
    1302             :                                   }
    1303             : 
    1304          10 :                                 hour = tmp_hour;
    1305          10 :                                 min = tmp_min;
    1306          10 :                                 sec = tmp_sec;
    1307          10 :                                 rest = end;
    1308          10 :                                 break;
    1309             :                           }
    1310          20 :                         if ((*end == '/' || *end == '-') &&
    1311           0 :                                          end[1] >= '0' && end[1] <= '9')
    1312           0 :                           {
    1313             :                                 /* Perhaps this is 6/16/95, 16/6/95, 6-16-95, or 16-6-95
    1314             :                                    or even 95-06-05...
    1315             :                                    #### But it doesn't handle 1995-06-22.
    1316             :                                  */
    1317             :                                 int n1, n2, n3;
    1318             :                                 const char *s;
    1319             : 
    1320           0 :                                 if (month != TT_UNKNOWN)
    1321             :                                   /* if we saw a month name, this can't be. */
    1322           0 :                                   break;
    1323             : 
    1324           0 :                                 s = rest;
    1325             : 
    1326           0 :                                 n1 = (*s++ - '0');                                /* first 1 or 2 digits */
    1327           0 :                                 if (*s >= '0' && *s <= '9')
    1328           0 :                                   n1 = n1*10 + (*s++ - '0');
    1329             : 
    1330           0 :                                 if (*s != '/' && *s != '-')                /* slash */
    1331           0 :                                   break;
    1332           0 :                                 s++;
    1333             : 
    1334           0 :                                 if (*s < '0' || *s > '9')                /* second 1 or 2 digits */
    1335             :                                   break;
    1336           0 :                                 n2 = (*s++ - '0');
    1337           0 :                                 if (*s >= '0' && *s <= '9')
    1338           0 :                                   n2 = n2*10 + (*s++ - '0');
    1339             : 
    1340           0 :                                 if (*s != '/' && *s != '-')                /* slash */
    1341           0 :                                   break;
    1342           0 :                                 s++;
    1343             : 
    1344           0 :                                 if (*s < '0' || *s > '9')                /* third 1, 2, 4, or 5 digits */
    1345             :                                   break;
    1346           0 :                                 n3 = (*s++ - '0');
    1347           0 :                                 if (*s >= '0' && *s <= '9')
    1348           0 :                                   n3 = n3*10 + (*s++ - '0');
    1349             : 
    1350           0 :                                 if (*s >= '0' && *s <= '9')            /* optional digits 3, 4, and 5 */
    1351             :                                   {
    1352           0 :                                         n3 = n3*10 + (*s++ - '0');
    1353           0 :                                         if (*s < '0' || *s > '9')
    1354             :                                           break;
    1355           0 :                                         n3 = n3*10 + (*s++ - '0');
    1356           0 :                                         if (*s >= '0' && *s <= '9')
    1357           0 :                                           n3 = n3*10 + (*s++ - '0');
    1358             :                                   }
    1359             : 
    1360           0 :                                 if ((*s >= '0' && *s <= '9') ||        /* followed by non-alphanum */
    1361           0 :                                         (*s >= 'A' && *s <= 'Z') ||
    1362           0 :                                         (*s >= 'a' && *s <= 'z'))
    1363             :                                   break;
    1364             : 
    1365             :                                 /* Ok, we parsed three 1-2 digit numbers, with / or -
    1366             :                                    between them.  Now decide what the hell they are
    1367             :                                    (DD/MM/YY or MM/DD/YY or YY/MM/DD.)
    1368             :                                  */
    1369             : 
    1370           0 :                                 if (n1 > 31 || n1 == 0)  /* must be YY/MM/DD */
    1371             :                                   {
    1372           0 :                                         if (n2 > 12) break;
    1373           0 :                                         if (n3 > 31) break;
    1374           0 :                                         year = n1;
    1375           0 :                                         if (year < 70)
    1376           0 :                                             year += 2000;
    1377           0 :                                         else if (year < 100)
    1378           0 :                                             year += 1900;
    1379           0 :                                         month = (TIME_TOKEN)(n2 + ((int)TT_JAN) - 1);
    1380           0 :                                         date = n3;
    1381           0 :                                         rest = s;
    1382           0 :                                         break;
    1383             :                                   }
    1384             : 
    1385           0 :                                 if (n1 > 12 && n2 > 12)  /* illegal */
    1386             :                                   {
    1387           0 :                                         rest = s;
    1388           0 :                                         break;
    1389             :                                   }
    1390             : 
    1391           0 :                                 if (n3 < 70)
    1392           0 :                                     n3 += 2000;
    1393           0 :                                 else if (n3 < 100)
    1394           0 :                                     n3 += 1900;
    1395             : 
    1396           0 :                                 if (n1 > 12)  /* must be DD/MM/YY */
    1397             :                                   {
    1398           0 :                                         date = n1;
    1399           0 :                                         month = (TIME_TOKEN)(n2 + ((int)TT_JAN) - 1);
    1400           0 :                                         year = n3;
    1401             :                                   }
    1402             :                                 else                  /* assume MM/DD/YY */
    1403             :                                   {
    1404             :                                         /* #### In the ambiguous case, should we consult the
    1405             :                                            locale to find out the local default? */
    1406           0 :                                         month = (TIME_TOKEN)(n1 + ((int)TT_JAN) - 1);
    1407           0 :                                         date = n2;
    1408           0 :                                         year = n3;
    1409             :                                   }
    1410           0 :                                 rest = s;
    1411             :                           }
    1412          40 :                         else if ((*end >= 'A' && *end <= 'Z') ||
    1413          20 :                                          (*end >= 'a' && *end <= 'z'))
    1414             :                           /* Digits followed by non-punctuation - what's that? */
    1415             :                           ;
    1416          20 :                         else if ((end - rest) == 5)                /* five digits is a year */
    1417           0 :                           year = (year < 0
    1418           0 :                                           ? ((rest[0]-'0')*10000L +
    1419           0 :                                                  (rest[1]-'0')*1000L +
    1420           0 :                                                  (rest[2]-'0')*100L +
    1421           0 :                                                  (rest[3]-'0')*10L +
    1422           0 :                                                  (rest[4]-'0'))
    1423             :                                           : year);
    1424          20 :                         else if ((end - rest) == 4)                /* four digits is a year */
    1425          20 :                           year = (year < 0
    1426          20 :                                           ? ((rest[0]-'0')*1000L +
    1427          20 :                                                  (rest[1]-'0')*100L +
    1428          20 :                                                  (rest[2]-'0')*10L +
    1429          10 :                                                  (rest[3]-'0'))
    1430             :                                           : year);
    1431          10 :                         else if ((end - rest) == 2)                /* two digits - date or year */
    1432             :                           {
    1433          20 :                                 int n = ((rest[0]-'0')*10 +
    1434          10 :                                                  (rest[1]-'0'));
    1435             :                                 /* If we don't have a date (day of the month) and we see a number
    1436             :                                      less than 32, then assume that is the date.
    1437             : 
    1438             :                                          Otherwise, if we have a date and not a year, assume this is the
    1439             :                                          year.  If it is less than 70, then assume it refers to the 21st
    1440             :                                          century.  If it is two digits (>= 70), assume it refers to this
    1441             :                                          century.  Otherwise, assume it refers to an unambiguous year.
    1442             : 
    1443             :                                          The world will surely end soon.
    1444             :                                    */
    1445          10 :                                 if (date < 0 && n < 32)
    1446          10 :                                   date = n;
    1447           0 :                                 else if (year < 0)
    1448             :                                   {
    1449           0 :                                         if (n < 70)
    1450           0 :                                           year = 2000 + n;
    1451           0 :                                         else if (n < 100)
    1452           0 :                                           year = 1900 + n;
    1453             :                                         else
    1454           0 :                                           year = n;
    1455             :                                   }
    1456             :                                 /* else what the hell is this. */
    1457             :                           }
    1458           0 :                         else if ((end - rest) == 1)                /* one digit - date */
    1459           0 :                           date = (date < 0 ? (rest[0]-'0') : date);
    1460             :                         /* else, three or more than five digits - what's that? */
    1461             : 
    1462          20 :                         break;
    1463             :                   }
    1464             :                 }
    1465             : 
    1466             :           /* Skip to the end of this token, whether we parsed it or not.
    1467             :                  Tokens are delimited by whitespace, or ,;-/
    1468             :                  But explicitly not :+-.
    1469             :            */
    1470         470 :           while (*rest &&
    1471         520 :                          *rest != ' ' && *rest != '\t' &&
    1472         460 :                          *rest != ',' && *rest != ';' &&
    1473         450 :                          *rest != '-' && *rest != '+' &&
    1474         300 :                          *rest != '/' &&
    1475         300 :                          *rest != '(' && *rest != ')' && *rest != '[' && *rest != ']')
    1476         150 :                 rest++;
    1477             :           /* skip over uninteresting chars. */
    1478             :         SKIP_MORE:
    1479         290 :           while (*rest &&
    1480         230 :                          (*rest == ' ' || *rest == '\t' ||
    1481         160 :                           *rest == ',' || *rest == ';' || *rest == '/' ||
    1482         100 :                           *rest == '(' || *rest == ')' || *rest == '[' || *rest == ']'))
    1483          60 :                 rest++;
    1484             : 
    1485             :           /* "-" is ignored at the beginning of a token if we have not yet
    1486             :                  parsed a year (e.g., the second "-" in "30-AUG-1966"), or if
    1487             :                  the character after the dash is not a digit. */         
    1488          60 :           if (*rest == '-' && ((rest > string &&
    1489           0 :               isalpha((unsigned char)rest[-1]) && year < 0) ||
    1490           0 :               rest[1] < '0' || rest[1] > '9'))
    1491             :                 {
    1492           0 :                   rest++;
    1493           0 :                   goto SKIP_MORE;
    1494             :                 }
    1495             : 
    1496             :         }
    1497             : 
    1498          10 :   if (zone != TT_UNKNOWN && zone_offset == -1)
    1499             :         {
    1500          10 :           switch (zone)
    1501             :                 {
    1502           0 :                 case TT_PST: zone_offset = -8 * 60; break;
    1503           0 :                 case TT_PDT: zone_offset = -8 * 60; dst_offset = 1 * 60; break;
    1504           0 :                 case TT_MST: zone_offset = -7 * 60; break;
    1505           0 :                 case TT_MDT: zone_offset = -7 * 60; dst_offset = 1 * 60; break;
    1506           0 :                 case TT_CST: zone_offset = -6 * 60; break;
    1507           0 :                 case TT_CDT: zone_offset = -6 * 60; dst_offset = 1 * 60; break;
    1508           0 :                 case TT_EST: zone_offset = -5 * 60; break;
    1509           0 :                 case TT_EDT: zone_offset = -5 * 60; dst_offset = 1 * 60; break;
    1510           0 :                 case TT_AST: zone_offset = -4 * 60; break;
    1511           0 :                 case TT_NST: zone_offset = -3 * 60 - 30; break;
    1512          10 :                 case TT_GMT: zone_offset =  0 * 60; break;
    1513           0 :                 case TT_BST: zone_offset =  0 * 60; dst_offset = 1 * 60; break;
    1514           0 :                 case TT_MET: zone_offset =  1 * 60; break;
    1515           0 :                 case TT_EET: zone_offset =  2 * 60; break;
    1516           0 :                 case TT_JST: zone_offset =  9 * 60; break;
    1517             :                 default:
    1518           0 :                   PR_ASSERT (0);
    1519           0 :                   break;
    1520             :                 }
    1521             :         }
    1522             : 
    1523             :   /* If we didn't find a year, month, or day-of-the-month, we can't
    1524             :          possibly parse this, and in fact, mktime() will do something random
    1525             :          (I'm seeing it return "Tue Feb  5 06:28:16 2036", which is no doubt
    1526             :          a numerologically significant date... */
    1527          10 :   if (month == TT_UNKNOWN || date == -1 || year == -1 || year > PR_INT16_MAX)
    1528           0 :       return PR_FAILURE;
    1529             : 
    1530          10 :   memset(result, 0, sizeof(*result));
    1531          10 :   if (sec != -1)
    1532          10 :         result->tm_sec = sec;
    1533          10 :   if (min != -1)
    1534          10 :         result->tm_min = min;
    1535          10 :   if (hour != -1)
    1536          10 :         result->tm_hour = hour;
    1537          10 :   if (date != -1)
    1538          10 :         result->tm_mday = date;
    1539          10 :   if (month != TT_UNKNOWN)
    1540          10 :         result->tm_month = (((int)month) - ((int)TT_JAN));
    1541          10 :   if (year != -1)
    1542          10 :         result->tm_year = year;
    1543          10 :   if (dotw != TT_UNKNOWN)
    1544          10 :         result->tm_wday = (((int)dotw) - ((int)TT_SUN));
    1545             :   /*
    1546             :    * Mainly to compute wday and yday, but normalized time is also required
    1547             :    * by the check below that works around a Visual C++ 2005 mktime problem.
    1548             :    */
    1549          10 :   PR_NormalizeTime(result, PR_GMTParameters);
    1550             :   /* The remaining work is to set the gmt and dst offsets in tm_params. */
    1551             : 
    1552          10 :   if (zone == TT_UNKNOWN && default_to_gmt)
    1553             :         {
    1554             :           /* No zone was specified, so pretend the zone was GMT. */
    1555           0 :           zone = TT_GMT;
    1556           0 :           zone_offset = 0;
    1557             :         }
    1558             : 
    1559          10 :   if (zone_offset == -1)
    1560             :          {
    1561             :            /* no zone was specified, and we're to assume that everything
    1562             :              is local. */
    1563             :           struct tm localTime;
    1564             :           time_t secs;
    1565             : 
    1566           0 :           PR_ASSERT(result->tm_month > -1 &&
    1567             :                     result->tm_mday > 0 &&
    1568             :                     result->tm_hour > -1 &&
    1569             :                     result->tm_min > -1 &&
    1570             :                     result->tm_sec > -1);
    1571             : 
    1572             :             /*
    1573             :              * To obtain time_t from a tm structure representing the local
    1574             :              * time, we call mktime().  However, we need to see if we are
    1575             :              * on 1-Jan-1970 or before.  If we are, we can't call mktime()
    1576             :              * because mktime() will crash on win16. In that case, we
    1577             :              * calculate zone_offset based on the zone offset at 
    1578             :              * 00:00:00, 2 Jan 1970 GMT, and subtract zone_offset from the
    1579             :              * date we are parsing to transform the date to GMT.  We also
    1580             :              * do so if mktime() returns (time_t) -1 (time out of range).
    1581             :            */
    1582             : 
    1583             :           /* month, day, hours, mins and secs are always non-negative
    1584             :              so we dont need to worry about them. */  
    1585           0 :           if(result->tm_year >= 1970)
    1586             :                 {
    1587             :                   PRInt64 usec_per_sec;
    1588             : 
    1589           0 :                   localTime.tm_sec = result->tm_sec;
    1590           0 :                   localTime.tm_min = result->tm_min;
    1591           0 :                   localTime.tm_hour = result->tm_hour;
    1592           0 :                   localTime.tm_mday = result->tm_mday;
    1593           0 :                   localTime.tm_mon = result->tm_month;
    1594           0 :                   localTime.tm_year = result->tm_year - 1900;
    1595             :                   /* Set this to -1 to tell mktime "I don't care".  If you set
    1596             :                      it to 0 or 1, you are making assertions about whether the
    1597             :                      date you are handing it is in daylight savings mode or not;
    1598             :                      and if you're wrong, it will "fix" it for you. */
    1599           0 :                   localTime.tm_isdst = -1;
    1600             : 
    1601             : #if _MSC_VER == 1400  /* 1400 = Visual C++ 2005 (8.0) */
    1602             :                   /*
    1603             :                    * mktime will return (time_t) -1 if the input is a date
    1604             :                    * after 23:59:59, December 31, 3000, US Pacific Time (not
    1605             :                    * UTC as documented): 
    1606             :                    * http://msdn.microsoft.com/en-us/library/d1y53h2a(VS.80).aspx
    1607             :                    * But if the year is 3001, mktime also invokes the invalid
    1608             :                    * parameter handler, causing the application to crash.  This
    1609             :                    * problem has been reported in
    1610             :                    * http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=266036.
    1611             :                    * We avoid this crash by not calling mktime if the date is
    1612             :                    * out of range.  To use a simple test that works in any time
    1613             :                    * zone, we consider year 3000 out of range as well.  (See
    1614             :                    * bug 480740.)
    1615             :                    */
    1616             :                   if (result->tm_year >= 3000) {
    1617             :                       /* Emulate what mktime would have done. */
    1618             :                       errno = EINVAL;
    1619             :                       secs = (time_t) -1;
    1620             :                   } else {
    1621             :                       secs = mktime(&localTime);
    1622             :                   }
    1623             : #else
    1624           0 :                   secs = mktime(&localTime);
    1625             : #endif
    1626           0 :                   if (secs != (time_t) -1)
    1627             :                     {
    1628             :                       PRTime usecs64;
    1629           0 :                       LL_I2L(usecs64, secs);
    1630           0 :                       LL_I2L(usec_per_sec, PR_USEC_PER_SEC);
    1631           0 :                       LL_MUL(usecs64, usecs64, usec_per_sec);
    1632           0 :                       PR_ExplodeTime(usecs64, PR_LocalTimeParameters, result);
    1633           0 :                       return PR_SUCCESS;
    1634             :                     }
    1635             :                 }
    1636             :                 
    1637             :                 /* So mktime() can't handle this case.  We assume the
    1638             :                    zone_offset for the date we are parsing is the same as
    1639             :                    the zone offset on 00:00:00 2 Jan 1970 GMT. */
    1640           0 :                 secs = 86400;
    1641           0 :                 localTimeResult = MT_safe_localtime(&secs, &localTime);
    1642           0 :                 PR_ASSERT(localTimeResult != NULL);
    1643           0 :                 if (localTimeResult == NULL) {
    1644           0 :                     return PR_FAILURE;
    1645             :                 }
    1646           0 :                 zone_offset = localTime.tm_min
    1647           0 :                               + 60 * localTime.tm_hour
    1648           0 :                               + 1440 * (localTime.tm_mday - 2);
    1649             :         }
    1650             : 
    1651          10 :   result->tm_params.tp_gmt_offset = zone_offset * 60;
    1652          10 :   result->tm_params.tp_dst_offset = dst_offset * 60;
    1653             : 
    1654          10 :   return PR_SUCCESS;
    1655             : }
    1656             : 
    1657             : PR_IMPLEMENT(PRStatus)
    1658             : PR_ParseTimeString(
    1659             :         const char *string,
    1660             :         PRBool default_to_gmt,
    1661             :         PRTime *result)
    1662             : {
    1663             :   PRExplodedTime tm;
    1664             :   PRStatus rv;
    1665             : 
    1666          10 :   rv = PR_ParseTimeStringToExplodedTime(string,
    1667             :                                         default_to_gmt,
    1668             :                                         &tm);
    1669          10 :   if (rv != PR_SUCCESS)
    1670           0 :         return rv;
    1671             : 
    1672          10 :   *result = PR_ImplodeTime(&tm);
    1673             : 
    1674          10 :   return PR_SUCCESS;
    1675             : }
    1676             : 
    1677             : /*
    1678             :  *******************************************************************
    1679             :  *******************************************************************
    1680             :  **
    1681             :  **    OLD COMPATIBILITY FUNCTIONS
    1682             :  **
    1683             :  *******************************************************************
    1684             :  *******************************************************************
    1685             :  */
    1686             : 
    1687             : 
    1688             : /*
    1689             :  *-----------------------------------------------------------------------
    1690             :  *
    1691             :  * PR_FormatTime --
    1692             :  *
    1693             :  *     Format a time value into a buffer. Same semantics as strftime().
    1694             :  *
    1695             :  *-----------------------------------------------------------------------
    1696             :  */
    1697             : 
    1698             : PR_IMPLEMENT(PRUint32)
    1699             : PR_FormatTime(char *buf, int buflen, const char *fmt,
    1700             :               const PRExplodedTime *time)
    1701             : {
    1702             :     size_t rv;
    1703             :     struct tm a;
    1704             :     struct tm *ap;
    1705             : 
    1706           0 :     if (time) {
    1707           0 :         ap = &a;
    1708           0 :         a.tm_sec = time->tm_sec;
    1709           0 :         a.tm_min = time->tm_min;
    1710           0 :         a.tm_hour = time->tm_hour;
    1711           0 :         a.tm_mday = time->tm_mday;
    1712           0 :         a.tm_mon = time->tm_month;
    1713           0 :         a.tm_wday = time->tm_wday;
    1714           0 :         a.tm_year = time->tm_year - 1900;
    1715           0 :         a.tm_yday = time->tm_yday;
    1716           0 :         a.tm_isdst = time->tm_params.tp_dst_offset ? 1 : 0;
    1717             : 
    1718             :         /*
    1719             :          * On some platforms, for example SunOS 4, struct tm has two
    1720             :          * additional fields: tm_zone and tm_gmtoff.
    1721             :          */
    1722             : 
    1723             : #if (__GLIBC__ >= 2) || defined(XP_BEOS) \
    1724             :         || defined(NETBSD) || defined(OPENBSD) || defined(FREEBSD) \
    1725             :         || defined(DARWIN) || defined(SYMBIAN) || defined(ANDROID)
    1726           0 :         a.tm_zone = NULL;
    1727           0 :         a.tm_gmtoff = time->tm_params.tp_gmt_offset +
    1728           0 :                       time->tm_params.tp_dst_offset;
    1729             : #endif
    1730             :     } else {
    1731           0 :         ap = NULL;
    1732             :     }
    1733             : 
    1734           0 :     rv = strftime(buf, buflen, fmt, ap);
    1735           0 :     if (!rv && buf && buflen > 0) {
    1736             :         /*
    1737             :          * When strftime fails, the contents of buf are indeterminate.
    1738             :          * Some callers don't check the return value from this function,
    1739             :          * so store an empty string in buf in case they try to print it.
    1740             :          */
    1741           0 :         buf[0] = '\0';
    1742             :     }
    1743           0 :     return rv;
    1744             : }
    1745             : 
    1746             : 
    1747             : /*
    1748             :  * The following string arrays and macros are used by PR_FormatTimeUSEnglish().
    1749             :  */
    1750             : 
    1751             : static const char* abbrevDays[] =
    1752             : {
    1753             :    "Sun","Mon","Tue","Wed","Thu","Fri","Sat"
    1754             : };
    1755             : 
    1756             : static const char* days[] =
    1757             : {
    1758             :    "Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"
    1759             : };
    1760             : 
    1761             : static const char* abbrevMonths[] =
    1762             : {
    1763             :    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
    1764             :    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
    1765             : };
    1766             : 
    1767             : static const char* months[] =
    1768             : { 
    1769             :     "January", "February", "March", "April", "May", "June",
    1770             :     "July", "August", "September", "October", "November", "December"
    1771             : };
    1772             : 
    1773             : 
    1774             : /*
    1775             :  * Add a single character to the given buffer, incrementing the buffer pointer
    1776             :  * and decrementing the buffer size. Return 0 on error.
    1777             :  */
    1778             : #define ADDCHAR( buf, bufSize, ch )             \
    1779             : do                                              \
    1780             : {                                               \
    1781             :    if( bufSize < 1 )                            \
    1782             :    {                                            \
    1783             :       *(--buf) = '\0';                          \
    1784             :       return 0;                                 \
    1785             :    }                                            \
    1786             :    *buf++ = ch;                                 \
    1787             :    bufSize--;                                   \
    1788             : }                                               \
    1789             : while(0)
    1790             : 
    1791             : 
    1792             : /*
    1793             :  * Add a string to the given buffer, incrementing the buffer pointer
    1794             :  * and decrementing the buffer size appropriately.  Return 0 on error.
    1795             :  */
    1796             : #define ADDSTR( buf, bufSize, str )             \
    1797             : do                                              \
    1798             : {                                               \
    1799             :    PRUint32 strSize = strlen( str );              \
    1800             :    if( strSize > bufSize )                      \
    1801             :    {                                            \
    1802             :       if( bufSize==0 )                          \
    1803             :          *(--buf) = '\0';                       \
    1804             :       else                                      \
    1805             :          *buf = '\0';                           \
    1806             :       return 0;                                 \
    1807             :    }                                            \
    1808             :    memcpy(buf, str, strSize);                   \
    1809             :    buf += strSize;                              \
    1810             :    bufSize -= strSize;                          \
    1811             : }                                               \
    1812             : while(0)
    1813             : 
    1814             : /* Needed by PR_FormatTimeUSEnglish() */
    1815             : static unsigned int  pr_WeekOfYear(const PRExplodedTime* time,
    1816             :         unsigned int firstDayOfWeek);
    1817             : 
    1818             : 
    1819             : /***********************************************************************************
    1820             :  *
    1821             :  * Description:
    1822             :  *  This is a dumbed down version of strftime that will format the date in US
    1823             :  *  English regardless of the setting of the global locale.  This functionality is
    1824             :  *  needed to write things like MIME headers which must always be in US English.
    1825             :  *
    1826             :  **********************************************************************************/
    1827             :              
    1828             : PR_IMPLEMENT(PRUint32)
    1829             : PR_FormatTimeUSEnglish( char* buf, PRUint32 bufSize,
    1830             :                         const char* format, const PRExplodedTime* time )
    1831             : {
    1832           0 :    char*         bufPtr = buf;
    1833             :    const char*   fmtPtr;
    1834             :    char          tmpBuf[ 40 ];        
    1835           0 :    const int     tmpBufSize = sizeof( tmpBuf );
    1836             : 
    1837             :    
    1838           0 :    for( fmtPtr=format; *fmtPtr != '\0'; fmtPtr++ )
    1839             :    {
    1840           0 :       if( *fmtPtr != '%' )
    1841             :       {
    1842           0 :          ADDCHAR( bufPtr, bufSize, *fmtPtr );
    1843             :       }
    1844             :       else
    1845             :       {
    1846           0 :          switch( *(++fmtPtr) )
    1847             :          {
    1848             :          case '%':
    1849             :             /* escaped '%' character */
    1850           0 :             ADDCHAR( bufPtr, bufSize, '%' );
    1851           0 :             break;
    1852             :             
    1853             :          case 'a':
    1854             :             /* abbreviated weekday name */
    1855           0 :             ADDSTR( bufPtr, bufSize, abbrevDays[ time->tm_wday ] );
    1856           0 :             break;
    1857             :                
    1858             :          case 'A':
    1859             :             /* full weekday name */
    1860           0 :             ADDSTR( bufPtr, bufSize, days[ time->tm_wday ] );
    1861           0 :             break;
    1862             :         
    1863             :          case 'b':
    1864             :             /* abbreviated month name */
    1865           0 :             ADDSTR( bufPtr, bufSize, abbrevMonths[ time->tm_month ] );
    1866           0 :             break;
    1867             :         
    1868             :          case 'B':
    1869             :             /* full month name */
    1870           0 :             ADDSTR(bufPtr, bufSize,  months[ time->tm_month ] );
    1871           0 :             break;
    1872             :         
    1873             :          case 'c':
    1874             :             /* Date and time. */
    1875           0 :             PR_FormatTimeUSEnglish( tmpBuf, tmpBufSize, "%a %b %d %H:%M:%S %Y", time );
    1876           0 :             ADDSTR( bufPtr, bufSize, tmpBuf );
    1877           0 :             break;
    1878             :         
    1879             :          case 'd':
    1880             :             /* day of month ( 01 - 31 ) */
    1881           0 :             PR_snprintf(tmpBuf,tmpBufSize,"%.2ld",time->tm_mday );
    1882           0 :             ADDSTR( bufPtr, bufSize, tmpBuf ); 
    1883           0 :             break;
    1884             : 
    1885             :          case 'H':
    1886             :             /* hour ( 00 - 23 ) */
    1887           0 :             PR_snprintf(tmpBuf,tmpBufSize,"%.2ld",time->tm_hour );
    1888           0 :             ADDSTR( bufPtr, bufSize, tmpBuf ); 
    1889           0 :             break;
    1890             :         
    1891             :          case 'I':
    1892             :             /* hour ( 01 - 12 ) */
    1893           0 :             PR_snprintf(tmpBuf,tmpBufSize,"%.2ld",
    1894           0 :                         (time->tm_hour%12) ? time->tm_hour%12 : (PRInt32) 12 );
    1895           0 :             ADDSTR( bufPtr, bufSize, tmpBuf ); 
    1896           0 :             break;
    1897             :         
    1898             :          case 'j':
    1899             :             /* day number of year ( 001 - 366 ) */
    1900           0 :             PR_snprintf(tmpBuf,tmpBufSize,"%.3d",time->tm_yday + 1);
    1901           0 :             ADDSTR( bufPtr, bufSize, tmpBuf ); 
    1902           0 :             break;
    1903             :         
    1904             :          case 'm':
    1905             :             /* month number ( 01 - 12 ) */
    1906           0 :             PR_snprintf(tmpBuf,tmpBufSize,"%.2ld",time->tm_month+1);
    1907           0 :             ADDSTR( bufPtr, bufSize, tmpBuf ); 
    1908           0 :             break;
    1909             :         
    1910             :          case 'M':
    1911             :             /* minute ( 00 - 59 ) */
    1912           0 :             PR_snprintf(tmpBuf,tmpBufSize,"%.2ld",time->tm_min );
    1913           0 :             ADDSTR( bufPtr, bufSize, tmpBuf ); 
    1914           0 :             break;
    1915             :        
    1916             :          case 'p':
    1917             :             /* locale's equivalent of either AM or PM */
    1918           0 :             ADDSTR( bufPtr, bufSize, (time->tm_hour<12)?"AM":"PM" ); 
    1919           0 :             break;
    1920             :         
    1921             :          case 'S':
    1922             :             /* seconds ( 00 - 61 ), allows for leap seconds */
    1923           0 :             PR_snprintf(tmpBuf,tmpBufSize,"%.2ld",time->tm_sec );
    1924           0 :             ADDSTR( bufPtr, bufSize, tmpBuf ); 
    1925           0 :             break;
    1926             :      
    1927             :          case 'U':
    1928             :             /* week number of year ( 00 - 53  ),  Sunday  is  the first day of week 1 */
    1929           0 :             PR_snprintf(tmpBuf,tmpBufSize,"%.2d", pr_WeekOfYear( time, 0 ) );
    1930           0 :             ADDSTR( bufPtr, bufSize, tmpBuf );
    1931           0 :             break;
    1932             :         
    1933             :          case 'w':
    1934             :             /* weekday number ( 0 - 6 ), Sunday = 0 */
    1935           0 :             PR_snprintf(tmpBuf,tmpBufSize,"%d",time->tm_wday );
    1936           0 :             ADDSTR( bufPtr, bufSize, tmpBuf ); 
    1937           0 :             break;
    1938             :         
    1939             :          case 'W':
    1940             :             /* Week number of year ( 00 - 53  ),  Monday  is  the first day of week 1 */
    1941           0 :             PR_snprintf(tmpBuf,tmpBufSize,"%.2d", pr_WeekOfYear( time, 1 ) );
    1942           0 :             ADDSTR( bufPtr, bufSize, tmpBuf );
    1943           0 :             break;
    1944             :         
    1945             :          case 'x':
    1946             :             /* Date representation */
    1947           0 :             PR_FormatTimeUSEnglish( tmpBuf, tmpBufSize, "%m/%d/%y", time );
    1948           0 :             ADDSTR( bufPtr, bufSize, tmpBuf );
    1949           0 :             break;
    1950             :         
    1951             :          case 'X':
    1952             :             /* Time representation. */
    1953           0 :             PR_FormatTimeUSEnglish( tmpBuf, tmpBufSize, "%H:%M:%S", time );
    1954           0 :             ADDSTR( bufPtr, bufSize, tmpBuf );
    1955           0 :             break;
    1956             :         
    1957             :          case 'y':
    1958             :             /* year within century ( 00 - 99 ) */
    1959           0 :             PR_snprintf(tmpBuf,tmpBufSize,"%.2d",time->tm_year % 100 );
    1960           0 :             ADDSTR( bufPtr, bufSize, tmpBuf ); 
    1961           0 :             break;
    1962             :         
    1963             :          case 'Y':
    1964             :             /* year as ccyy ( for example 1986 ) */
    1965           0 :             PR_snprintf(tmpBuf,tmpBufSize,"%.4d",time->tm_year );
    1966           0 :             ADDSTR( bufPtr, bufSize, tmpBuf ); 
    1967           0 :             break;
    1968             :         
    1969             :          case 'Z':
    1970             :             /* Time zone name or no characters if  no  time  zone exists.
    1971             :              * Since time zone name is supposed to be independant of locale, we
    1972             :              * defer to PR_FormatTime() for this option.
    1973             :              */
    1974           0 :             PR_FormatTime( tmpBuf, tmpBufSize, "%Z", time );
    1975           0 :             ADDSTR( bufPtr, bufSize, tmpBuf ); 
    1976           0 :             break;
    1977             : 
    1978             :          default:
    1979             :             /* Unknown format.  Simply copy format into output buffer. */
    1980           0 :             ADDCHAR( bufPtr, bufSize, '%' );
    1981           0 :             ADDCHAR( bufPtr, bufSize, *fmtPtr );
    1982           0 :             break;
    1983             :             
    1984             :          }
    1985             :       }
    1986             :    }
    1987             : 
    1988           0 :    ADDCHAR( bufPtr, bufSize, '\0' );
    1989           0 :    return (PRUint32)(bufPtr - buf - 1);
    1990             : }
    1991             : 
    1992             : 
    1993             : 
    1994             : /***********************************************************************************
    1995             :  *
    1996             :  * Description:
    1997             :  *  Returns the week number of the year (0-53) for the given time.  firstDayOfWeek
    1998             :  *  is the day on which the week is considered to start (0=Sun, 1=Mon, ...).
    1999             :  *  Week 1 starts the first time firstDayOfWeek occurs in the year.  In other words,
    2000             :  *  a partial week at the start of the year is considered week 0.  
    2001             :  *
    2002             :  **********************************************************************************/
    2003             : 
    2004             : static unsigned int
    2005           0 : pr_WeekOfYear(const PRExplodedTime* time, unsigned int firstDayOfWeek)
    2006             : {
    2007             :    int dayOfWeek;
    2008             :    int dayOfYear;
    2009             : 
    2010             :   /* Get the day of the year for the given time then adjust it to represent the
    2011             :    * first day of the week containing the given time.
    2012             :    */
    2013           0 :   dayOfWeek = time->tm_wday - firstDayOfWeek;
    2014           0 :   if (dayOfWeek < 0)
    2015           0 :     dayOfWeek += 7;
    2016             : 
    2017           0 :   dayOfYear = time->tm_yday - dayOfWeek;
    2018             : 
    2019           0 :   if( dayOfYear <= 0 )
    2020             :   {
    2021             :      /* If dayOfYear is <= 0, it is in the first partial week of the year. */
    2022           0 :      return 0;
    2023             :   }
    2024             : 
    2025             :   /* Count the number of full weeks ( dayOfYear / 7 ) then add a week if there
    2026             :    * are any days left over ( dayOfYear % 7 ).  Because we are only counting to
    2027             :    * the first day of the week containing the given time, rather than to the
    2028             :    * actual day representing the given time, any days in week 0 will be "absorbed"
    2029             :    * as extra days in the given week.
    2030             :    */
    2031           0 :   return (dayOfYear / 7) + ( (dayOfYear % 7) == 0 ? 0 : 1 );
    2032             : 
    2033             : }
    2034             : 

Generated by: LCOV version 1.13