home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / js / src / prmjtime.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  32.0 KB  |  1,177 lines

  1. /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. /*
  20.  * PR time code.
  21.  */
  22. #ifdef SOLARIS
  23. #define _REENTRANT 1
  24. #endif
  25. #include <string.h>
  26. #include <time.h>
  27. #include "prtypes.h"
  28. #ifndef NSPR20
  29. #include "prosdep.h"
  30. #else
  31. #ifdef XP_MAC
  32. #include "prosdep.h"
  33. #else
  34. #include "md/prosdep.h"
  35. #endif
  36. #endif
  37. #include "prprf.h"
  38. #include "prmjtime.h"
  39.  
  40. #define PRMJ_DO_MILLISECONDS 1
  41.  
  42. #ifdef XP_PC
  43. #include <sys/timeb.h>
  44. #endif
  45.  
  46. #ifdef XP_MAC
  47. #include <OSUtils.h>
  48. #include <TextUtils.h>
  49. #include <Resources.h>
  50. #include <Timer.h>
  51. #endif
  52.  
  53. #ifdef XP_UNIX
  54.  
  55. #ifdef SOLARIS
  56. extern int gettimeofday(struct timeval *tv);
  57. #endif
  58.  
  59. #include <sys/time.h>
  60.  
  61. #endif /* XP_UNIX */
  62.  
  63. #ifdef XP_MAC
  64. extern UnsignedWide        dstLocalBaseMicroseconds;
  65. extern PRUintn            gJanuaryFirst1970Seconds;
  66. extern void MyReadLocation(MachineLocation* l);
  67. #endif
  68.  
  69. #define IS_LEAP(year) \
  70.    (year != 0 && ((((year & 0x3) == 0) &&  \
  71.            ((year - ((year/100) * 100)) != 0)) || \
  72.           (year - ((year/400) * 400)) == 0))
  73.  
  74. #define PRMJ_HOUR_SECONDS  3600L
  75. #define PRMJ_DAY_SECONDS  (24L * PRMJ_HOUR_SECONDS)
  76. #define PRMJ_YEAR_SECONDS (PRMJ_DAY_SECONDS * 365L)
  77. #define PRMJ_MAX_UNIX_TIMET 2145859200L /*time_t value equiv. to 12/31/2037 */
  78. /* function prototypes */
  79. static void PRMJ_basetime(PRInt64 tsecs, PRMJTime *prtm);
  80. /*
  81.  * get the difference in seconds between this time zone and UTC (GMT)
  82.  */
  83. PR_IMPLEMENT(time_t) PRMJ_LocalGMTDifference()
  84. {
  85. #if defined(XP_UNIX) || defined(XP_PC)
  86.     struct tm ltime;
  87.     /* get the difference between this time zone and GMT */
  88.     memset((char *)<ime,0,sizeof(ltime));
  89.     ltime.tm_mday = 2;
  90.     ltime.tm_year = 70;
  91. #ifdef SUNOS4
  92.     ltime.tm_zone = 0;
  93.     ltime.tm_gmtoff = 0;
  94.     return timelocal(<ime) - (24 * 3600);
  95. #else
  96.     return mktime(<ime) - (24L * 3600L);
  97. #endif
  98. #endif
  99. #if defined(XP_MAC)
  100.     static time_t    zone = -1L;
  101.     MachineLocation  machineLocation;
  102.     PRUint64         gmtOffsetSeconds;
  103.     PRUint64         gmtDelta;
  104.     PRUint64         dlsOffset;
  105.     PRInt32         offset;
  106.  
  107.     /* difference has been set no need to recalculate */
  108.     if(zone != -1)
  109.     return zone;
  110.  
  111.     /* Get the information about the local machine, including
  112.      * its GMT offset and its daylight savings time info.
  113.      * Convert each into wides that we can add to
  114.      * startupTimeMicroSeconds.
  115.      */
  116.  
  117.     MyReadLocation(&machineLocation);
  118.  
  119.     /* Mask off top eight bits of gmtDelta, sign extend lower three. */
  120.  
  121.     if ((machineLocation.u.gmtDelta & 0x00800000) != 0) {
  122.     gmtOffsetSeconds.lo = (machineLocation.u.gmtDelta & 0x00FFFFFF) | 0xFF000000;
  123.     gmtOffsetSeconds.hi = 0xFFFFFFFF;
  124.     LL_UI2L(gmtDelta,0);
  125.     }
  126.     else {
  127.  
  128.     gmtOffsetSeconds.lo = (machineLocation.u.gmtDelta & 0x00FFFFFF);
  129.     gmtOffsetSeconds.hi = 0;
  130.     LL_UI2L(gmtDelta,PRMJ_DAY_SECONDS);
  131.     }
  132.     /* normalize time to be positive if you are behind GMT. gmtDelta will always
  133.      * be positive.
  134.      */
  135.     LL_SUB(gmtDelta,gmtDelta,gmtOffsetSeconds);
  136.  
  137.     /* Is Daylight Savings On?  If so, we need to add an hour to the offset. */
  138.     if (machineLocation.u.dlsDelta != 0) {
  139.     LL_UI2L(dlsOffset, PRMJ_HOUR_SECONDS);
  140.     }
  141.     else
  142.     LL_I2L(dlsOffset, 0);
  143.  
  144.     LL_ADD(gmtDelta,gmtDelta, dlsOffset);
  145.     LL_L2I(offset,gmtDelta);
  146.  
  147.     zone = offset;
  148.     return (time_t)offset;
  149. #endif
  150. }
  151.  
  152. /*
  153.  * get information about the DST status of this time zone
  154.  */
  155. PR_IMPLEMENT(void)
  156. PRMJ_setDST(PRMJTime *prtm)
  157. {
  158. #ifdef XP_MAC
  159.     MachineLocation machineLocation;
  160.  
  161.     if(prtm->tm_isdst < 0){
  162.     MyReadLocation(&machineLocation);
  163.     /* Figure out daylight savings time. */
  164.     prtm->tm_isdst = (machineLocation.u.dlsDelta != 0);
  165.     }
  166. #else
  167.     struct tm time;
  168.  
  169.     if(prtm->tm_isdst < 0){
  170.     if(prtm->tm_year >= 1970 && prtm->tm_year <= 2037){
  171.         time.tm_sec  = prtm->tm_sec ;
  172.         time.tm_min  = prtm->tm_min ;
  173.         time.tm_hour = prtm->tm_hour;
  174.         time.tm_mday = prtm->tm_mday;
  175.         time.tm_mon  = prtm->tm_mon ;
  176.         time.tm_wday = prtm->tm_wday;
  177.         time.tm_year = prtm->tm_year-1900;
  178.         time.tm_yday = prtm->tm_yday;
  179.         time.tm_isdst = -1;
  180.         mktime(&time);
  181.         prtm->tm_isdst = time.tm_isdst;
  182.     }
  183.     else {
  184.         prtm->tm_isdst = 0;
  185.     }
  186.     }
  187. #endif /* XP_MAC */
  188. }
  189.  
  190. /* Constants for GMT offset from 1970 */
  191. #define G1970GMTMICROHI        0x00dcdcad /* micro secs to 1970 hi */
  192. #define G1970GMTMICROLOW       0x8b3fa000 /* micro secs to 1970 low */
  193.  
  194. #define G2037GMTMICROHI        0x00e45fab /* micro secs to 2037 high */
  195. #define G2037GMTMICROLOW       0x7a238000 /* micro secs to 2037 low */
  196. /* Convert from extended time to base time (time since Jan 1 1970) it
  197. *  truncates dates if time is before 1970 and after 2037.
  198.  */
  199.  
  200. PR_IMPLEMENT(PRInt32)
  201. PRMJ_ToBaseTime(PRInt64 time)
  202. {
  203.     PRInt64 g1970GMTMicroSeconds;
  204.     PRInt64 g2037GMTMicroSeconds;
  205.     PRInt64 low;
  206.     PRInt32 result;
  207.  
  208.     LL_UI2L(g1970GMTMicroSeconds,G1970GMTMICROHI);
  209.     LL_UI2L(low,G1970GMTMICROLOW);
  210. #ifndef HAVE_LONG_LONG
  211.     LL_SHL(g1970GMTMicroSeconds,g1970GMTMicroSeconds,16);
  212.     LL_SHL(g1970GMTMicroSeconds,g1970GMTMicroSeconds,16);
  213. #else
  214.     LL_SHL(g1970GMTMicroSeconds,g1970GMTMicroSeconds,32);
  215. #endif
  216.     LL_ADD(g1970GMTMicroSeconds,g1970GMTMicroSeconds,low);
  217.  
  218.     LL_UI2L(g2037GMTMicroSeconds,G2037GMTMICROHI);
  219.     LL_UI2L(low,G2037GMTMICROLOW);
  220. #ifndef HAVE_LONG_LONG
  221.     LL_SHL(g2037GMTMicroSeconds,g2037GMTMicroSeconds,16);
  222.     LL_SHL(g2037GMTMicroSeconds,g2037GMTMicroSeconds,16);
  223. #else
  224.     LL_SHL(g2037GMTMicroSeconds,g2037GMTMicroSeconds,32);
  225. #endif
  226.  
  227.     LL_ADD(g2037GMTMicroSeconds,g2037GMTMicroSeconds,low);
  228.  
  229.  
  230.     if(LL_CMP(time, <, g1970GMTMicroSeconds) ||
  231.        LL_CMP(time, >, g2037GMTMicroSeconds)){
  232.     return -1;
  233.     }
  234.  
  235.     LL_SUB(time,time,g1970GMTMicroSeconds);
  236.     LL_L2I(result,time);
  237.     return result;
  238. }
  239.  
  240. /* Convert from base time to extended time */
  241. PR_IMPLEMENT(PRInt64)
  242. PRMJ_ToExtendedTime(PRInt32 time)
  243. {
  244.     PRInt64 exttime;
  245.     PRInt64 g1970GMTMicroSeconds;
  246.     PRInt64 low;
  247.     time_t diff;
  248.     PRInt64  tmp;
  249.     PRInt64  tmp1;
  250.  
  251.     diff = PRMJ_LocalGMTDifference();
  252.     LL_UI2L(tmp, PRMJ_USEC_PER_SEC);
  253.     LL_I2L(tmp1,diff);
  254.     LL_MUL(tmp,tmp,tmp1);
  255.  
  256.     LL_UI2L(g1970GMTMicroSeconds,G1970GMTMICROHI);
  257.     LL_UI2L(low,G1970GMTMICROLOW);
  258. #ifndef HAVE_LONG_LONG
  259.     LL_SHL(g1970GMTMicroSeconds,g1970GMTMicroSeconds,16);
  260.     LL_SHL(g1970GMTMicroSeconds,g1970GMTMicroSeconds,16);
  261. #else
  262.     LL_SHL(g1970GMTMicroSeconds,g1970GMTMicroSeconds,32);
  263. #endif
  264.     LL_ADD(g1970GMTMicroSeconds,g1970GMTMicroSeconds,low);
  265.  
  266.     LL_I2L(exttime,time);
  267.     LL_ADD(exttime,exttime,g1970GMTMicroSeconds);
  268.     LL_SUB(exttime,exttime,tmp);
  269.     return exttime;
  270. }
  271.  
  272. PR_IMPLEMENT(PRInt64)
  273. PRMJ_Now(void)
  274. {
  275. #ifdef XP_PC
  276.     PRInt64 s, us, ms2us, s2us;
  277.     struct timeb b;
  278. #endif /* XP_PC */
  279. #ifdef XP_UNIX
  280.     struct timeval tv;
  281.     PRInt64 s, us, s2us;
  282. #endif /* XP_UNIX */
  283. #ifdef XP_MAC
  284.     UnsignedWide upTime;
  285.     PRInt64     localTime;
  286.     PRInt64       gmtOffset;
  287.     PRInt64    dstOffset;
  288.     time_t       gmtDiff;
  289.     PRInt64     s2us;
  290. #endif /* XP_MAC */
  291.  
  292. #ifdef XP_PC
  293.     ftime(&b);
  294.     LL_UI2L(ms2us, PRMJ_USEC_PER_MSEC);
  295.     LL_UI2L(s2us, PRMJ_USEC_PER_SEC);
  296.     LL_UI2L(s, b.time);
  297.     LL_UI2L(us, b.millitm);
  298.     LL_MUL(us, us, ms2us);
  299.     LL_MUL(s, s, s2us);
  300.     LL_ADD(s, s, us);
  301.     return s;
  302. #endif
  303.  
  304. #ifdef XP_UNIX
  305. #if defined(SOLARIS)
  306.     gettimeofday(&tv);
  307. #else
  308.     gettimeofday(&tv, 0);
  309. #endif /* SOLARIS */
  310.     LL_UI2L(s2us, PRMJ_USEC_PER_SEC);
  311.     LL_UI2L(s, tv.tv_sec);
  312.     LL_UI2L(us, tv.tv_usec);
  313.     LL_MUL(s, s, s2us);
  314.     LL_ADD(s, s, us);
  315.     return s;
  316. #endif /* XP_UNIX */
  317. #ifdef XP_MAC
  318.     LL_UI2L(localTime,0);
  319.     gmtDiff = PRMJ_LocalGMTDifference();
  320.     LL_I2L(gmtOffset,gmtDiff);
  321.     LL_UI2L(s2us, PRMJ_USEC_PER_SEC);
  322.     LL_MUL(gmtOffset,gmtOffset,s2us);
  323.     LL_UI2L(dstOffset,0);
  324.     dstOffset = PRMJ_DSTOffset(dstOffset);
  325.     LL_SUB(gmtOffset,gmtOffset,dstOffset);
  326.     /* don't adjust for DST since it sets ctime and gmtime off on the MAC */
  327.     Microseconds(&upTime);
  328.     LL_ADD(localTime,localTime,gmtOffset);
  329.     LL_ADD(localTime,localTime, *((PRUint64 *)&dstLocalBaseMicroseconds));
  330.     LL_ADD(localTime,localTime, *((PRUint64 *)&upTime));
  331.  
  332.     return *((PRUint64 *)&localTime);
  333. #endif /* XP_MAC */
  334. }
  335. /*
  336.  * Return the current local time in milli-seconds.
  337.  */
  338. PR_IMPLEMENT(PRInt64)
  339. PRMJ_NowMS(void)
  340. {
  341.     PRInt64 us, us2ms;
  342.  
  343.     us = PRMJ_Now();
  344.     LL_UI2L(us2ms, PRMJ_USEC_PER_MSEC);
  345.     LL_DIV(us, us, us2ms);
  346.  
  347.     return us;
  348. }
  349.  
  350. /*
  351.  * Return the current local time in seconds.
  352.  */
  353. PR_IMPLEMENT(PRInt64)
  354. PRMJ_NowS(void)
  355. {
  356.     PRInt64 us, us2s;
  357.  
  358.     us = PRMJ_Now();
  359.     LL_UI2L(us2s, PRMJ_USEC_PER_SEC);
  360.     LL_DIV(us, us, us2s);
  361.     return us;
  362. }
  363.  
  364. /* Get the DST timezone offset for the time passed in
  365.  */
  366. PR_IMPLEMENT(PRInt64)
  367. PRMJ_DSTOffset(PRInt64 time)
  368. {
  369.     PRInt64 us2s;
  370. #ifdef XP_MAC
  371.     MachineLocation  machineLocation;
  372.     PRInt64 dlsOffset;
  373.     /*    Get the information about the local machine, including
  374.      *    its GMT offset and its daylight savings time info.
  375.      *    Convert each into wides that we can add to
  376.      *    startupTimeMicroSeconds.
  377.      */
  378.     MyReadLocation(&machineLocation);
  379.     /* Is Daylight Savings On?  If so, we need to add an hour to the offset. */
  380.     if (machineLocation.u.dlsDelta != 0) {
  381.     LL_UI2L(us2s, PRMJ_USEC_PER_SEC); /* seconds in a microseconds */
  382.     LL_UI2L(dlsOffset, PRMJ_HOUR_SECONDS);  /* seconds in one hour       */
  383.     LL_MUL(dlsOffset, dlsOffset, us2s);
  384.     }
  385.     else
  386.     LL_I2L(dlsOffset, 0);
  387.     return(dlsOffset);
  388. #else
  389.     time_t local;
  390.     PRInt32 diff;
  391.     PRInt64  maxtimet;
  392.     struct tm tm;
  393. #if defined( XP_PC ) || defined( FREEBSD )
  394.     struct tm *ptm;
  395. #endif
  396.     PRMJTime prtm;
  397.  
  398.  
  399.     LL_UI2L(us2s, PRMJ_USEC_PER_SEC);
  400.     LL_DIV(time, time, us2s);
  401.     /* get the maximum of time_t value */
  402.     LL_UI2L(maxtimet,PRMJ_MAX_UNIX_TIMET);
  403.  
  404.     if(LL_CMP(time,>,maxtimet)){
  405.       LL_UI2L(time,PRMJ_MAX_UNIX_TIMET);
  406.     } else if(!LL_GE_ZERO(time)){
  407.       /*go ahead a day to make localtime work (does not work with 0) */
  408.       LL_UI2L(time,PRMJ_DAY_SECONDS);
  409.     }
  410.     LL_L2UI(local,time);
  411.     PRMJ_basetime(time,&prtm);
  412. #if defined( XP_PC ) || defined( FREEBSD )
  413.     ptm = localtime(&local);
  414.     if(!ptm){
  415.       return LL_ZERO;
  416.     }
  417.     tm = *ptm;
  418. #else
  419.     localtime_r(&local,&tm); /* get dst information */
  420. #endif
  421.  
  422.     diff = ((tm.tm_hour - prtm.tm_hour) * PRMJ_HOUR_SECONDS) +
  423.     ((tm.tm_min - prtm.tm_min) * 60);
  424.  
  425.     if(diff < 0){
  426.     diff += PRMJ_DAY_SECONDS;
  427.     }
  428.  
  429.     LL_UI2L(time,diff);
  430.  
  431.     LL_MUL(time,time,us2s);
  432.  
  433.     return(time);
  434. #endif
  435. }
  436.  
  437. PR_IMPLEMENT(PRInt64)
  438. PRMJ_ToGMT(PRInt64 time)
  439. {
  440.     time_t gmtDiff;
  441.     PRInt64 s2us, diff;
  442.     PRInt64 dstdiff;
  443.  
  444.     gmtDiff = PRMJ_LocalGMTDifference();
  445.     LL_I2L(diff, gmtDiff);
  446.     LL_UI2L(s2us, PRMJ_USEC_PER_SEC);
  447.     LL_MUL(diff,diff,s2us);
  448.     dstdiff = PRMJ_DSTOffset(time);
  449.     LL_SUB(diff,diff,dstdiff);
  450.     LL_ADD(time,time,diff);
  451.     return time;
  452. }
  453.  
  454. /* Convert a GMT time value into a local time value */
  455. PR_IMPLEMENT(PRInt64)
  456. PRMJ_ToLocal(PRInt64 time)
  457. {
  458.     time_t gmtDiff;
  459.     PRInt64 s2us, diff, dstdiff;
  460.  
  461.     gmtDiff = PRMJ_LocalGMTDifference();
  462.  
  463.     dstdiff = PRMJ_DSTOffset(time);
  464.     LL_I2L(diff, gmtDiff);
  465.     LL_UI2L(s2us, PRMJ_USEC_PER_SEC);
  466.     LL_MUL(diff,diff,s2us);
  467.     LL_SUB(time,time,diff);
  468.     LL_ADD(time,time,dstdiff);
  469.     return time;
  470. }
  471.  
  472.  
  473. /* Explode a 64 bit time value into its components */
  474. PR_IMPLEMENT(void)
  475. PRMJ_ExplodeTime(PRMJTime *to, PRInt64 time)
  476. {
  477.     PRInt64 s, us2s;
  478. #ifdef PRMJ_DO_MILLISECONDS
  479.     PRInt64 round, stime, us;
  480. #endif
  481.  
  482.     /* Convert back to seconds since 0 */
  483.     LL_UI2L(us2s,  PRMJ_USEC_PER_SEC);
  484.  
  485. #ifdef PRMJ_DO_MILLISECONDS
  486.     if (!LL_GE_ZERO(time)) {
  487.     /* correct for rounding of negative numbers */
  488.     LL_UI2L(round, PRMJ_USEC_PER_SEC-1);
  489.     LL_UI2L(stime,0);
  490.     LL_ADD(stime,time,stime);
  491.     LL_SUB(time,time,round);
  492.     LL_DIV(s, time, us2s);
  493.     LL_MUL(time,s,us2s);
  494.     LL_SUB(us,stime,time);
  495.     } else {
  496.     LL_MOD(us,time,us2s);
  497.     LL_DIV(s, time, us2s);
  498.     }
  499. #else
  500.     LL_DIV(s, time, us2s);
  501. #endif
  502.     PRMJ_localtime(s,to);
  503. #ifdef PRMJ_DO_MILLISECONDS
  504.     LL_L2I(to->tm_usec, us);
  505. #endif
  506. }
  507.  
  508. /* Compute the 64 bit time value from the components */
  509. PR_IMPLEMENT(PRInt64)
  510. PRMJ_ComputeTime(PRMJTime *prtm)
  511. {
  512.     PRInt64 s, s2us;
  513.  
  514.     s = PRMJ_mktime(prtm);
  515.  
  516.     LL_UI2L(s2us, PRMJ_USEC_PER_SEC);
  517.     LL_MUL(s, s, s2us);
  518.  
  519. #ifdef PRMJ_DO_MILLISECONDS
  520.     {
  521.     PRInt64 us;
  522.     LL_UI2L(us, prtm->tm_usec);
  523.     LL_ADD(s, s, us);
  524.     }
  525. #endif
  526.     return s;
  527. }
  528.  
  529. /* Format a time value into a buffer. Same semantics as strftime() */
  530. PR_IMPLEMENT(size_t)
  531. PRMJ_FormatTime(char *buf, int buflen, char *fmt, PRMJTime *prtm)
  532. {
  533. #if defined(XP_UNIX) || defined(XP_PC) || defined(XP_MAC)
  534.     struct tm a;
  535.     a.tm_sec = prtm->tm_sec;
  536.     a.tm_min = prtm->tm_min;
  537.     a.tm_hour = prtm->tm_hour;
  538.     a.tm_mday = prtm->tm_mday;
  539.     a.tm_mon = prtm->tm_mon;
  540.     a.tm_wday = prtm->tm_wday;
  541.     a.tm_year = prtm->tm_year - 1900;
  542.     a.tm_yday = prtm->tm_yday;
  543.     a.tm_isdst = prtm->tm_isdst;
  544. #ifdef SUNOS4
  545. {
  546.     time_t now;
  547.     struct tm *lt;
  548.  
  549.     now = time((time_t *)0);
  550.     lt = localtime(&now);
  551.     if (lt == 0) {
  552.     PR_snprintf(buf, buflen, "can't get timezone");
  553.     return 0;
  554.     }
  555.     a.tm_zone = lt->tm_zone;
  556.     a.tm_gmtoff = lt->tm_gmtoff;
  557. }
  558. #endif
  559.     return strftime(buf, buflen, fmt, &a);
  560. #endif
  561. }
  562.  
  563. /* table for number of days in a month */
  564. static int mtab[] = {
  565.   /* jan, feb,mar,apr,may,jun */
  566.   31,28,31,30,31,30,
  567.   /* july,aug,sep,oct,nov,dec */
  568.   31,31,30,31,30,31
  569. };
  570.  
  571. /*
  572.  * This function replaces the mktime on each platform. mktime unfortunately
  573.  * only handles time from January 1st 1970 until January 1st 2038. This
  574.  * is not sufficient for most applications. This application will produce
  575.  * time in seconds for any date.
  576.  * XXX We also need to account for leap seconds...
  577.  */
  578. PR_IMPLEMENT(PRInt64)
  579. PRMJ_mktime(PRMJTime *prtm)
  580. {
  581.   PRInt64 seconds;
  582.   PRInt64 result;
  583.   PRInt64 result1;
  584.   PRInt64 result2;
  585.   PRInt64 base;
  586.   time_t secs;
  587.   PRInt32   year = prtm->tm_year;
  588.   PRInt32   month = prtm->tm_mon;
  589.   PRInt32   day   = prtm->tm_mday;
  590.   PRInt32   isleap = IS_LEAP(year);
  591.   struct tm time;
  592. #ifdef XP_MAC
  593.   PRInt64  dstdiff;
  594.   PRInt64  s2us;
  595.   PRInt32  dstOffset;
  596. #endif
  597.  
  598.   /* if between years we support just use standard mktime */
  599.   if(year >= 1970 && year <= 2037){
  600.       time.tm_sec  = prtm->tm_sec ;
  601.       time.tm_min  = prtm->tm_min ;
  602.       time.tm_hour = prtm->tm_hour;
  603.       time.tm_mday = prtm->tm_mday;
  604.       time.tm_mon  = prtm->tm_mon ;
  605.       time.tm_wday = prtm->tm_wday;
  606.       time.tm_year = prtm->tm_year-1900;
  607.       time.tm_yday = prtm->tm_yday;
  608.       time.tm_isdst = prtm->tm_isdst;
  609.       if((secs = mktime(&time)) < 0){
  610.     /* out of range use extended time */
  611.     goto extended_time;
  612.       }
  613. #ifdef XP_MAC
  614.       /* adjust MAC time to make relative to UNIX epoch */
  615.       secs -= gJanuaryFirst1970Seconds;
  616.       secs += PRMJ_LocalGMTDifference();
  617.       LL_UI2L(dstdiff,0);
  618.       dstdiff = PRMJ_DSTOffset(dstdiff);
  619.       LL_UI2L(s2us,  PRMJ_USEC_PER_SEC);
  620.       LL_DIV(dstdiff,dstdiff,s2us);
  621.       LL_L2I(dstOffset,dstdiff);
  622.       secs -= dstOffset;
  623.       PRMJ_setDST(prtm);
  624. #else
  625.       prtm->tm_isdst = time.tm_isdst;
  626. #endif
  627.       prtm->tm_mday = time.tm_mday;
  628.       prtm->tm_wday = time.tm_wday;
  629.       prtm->tm_yday = time.tm_yday;
  630.       prtm->tm_hour = time.tm_hour;
  631.       prtm->tm_min  = time.tm_min;
  632.       prtm->tm_mon  = time.tm_mon;
  633.  
  634.       LL_UI2L(seconds,secs);
  635.       return(seconds);
  636.   }
  637.  
  638. extended_time:
  639.   LL_UI2L(seconds,0);
  640.   LL_UI2L(result,0);
  641.   LL_UI2L(result1,0);
  642.   LL_UI2L(result2,0);
  643.  
  644.   /* calculate seconds in years */
  645.   if(year > 0){
  646.     LL_UI2L(result,year);
  647.     LL_UI2L(result1,(365L * 24L));
  648.     LL_MUL(result,result,result1);
  649.     LL_UI2L(result1,PRMJ_HOUR_SECONDS);
  650.     LL_MUL(result,result,result1);
  651.     LL_UI2L(result1,((year-1)/4 - (year-1)/100 + (year-1)/400));
  652.     LL_UI2L(result2,PRMJ_DAY_SECONDS);
  653.     LL_MUL(result1,result1,result2);
  654.     LL_ADD(seconds,result,result1);
  655.   }
  656.  
  657.   /* calculate seconds in months */
  658.   month--;
  659.  
  660.   for(;month >= 0; month--){
  661.     LL_UI2L(result,(PRMJ_DAY_SECONDS * mtab[month]));
  662.     LL_ADD(seconds,seconds,result);
  663.     /* it's  a Feb */
  664.     if(month == 1 && isleap != 0){
  665.       LL_UI2L(result,PRMJ_DAY_SECONDS);
  666.       LL_ADD(seconds,seconds,result);
  667.     }
  668.   }
  669.  
  670.   /* get the base time via UTC */
  671.   base = PRMJ_ToExtendedTime(0);
  672.   LL_UI2L(result,  PRMJ_USEC_PER_SEC);
  673.   LL_DIV(base,base,result);
  674.  
  675.   /* calculate seconds for days */
  676.   LL_UI2L(result,((day-1) * PRMJ_DAY_SECONDS));
  677.   LL_ADD(seconds,seconds,result);
  678.   /* calculate seconds for hours, minutes and seconds */
  679.   LL_UI2L(result, (prtm->tm_hour * PRMJ_HOUR_SECONDS + prtm->tm_min * 60 +
  680.            prtm->tm_sec));
  681.   LL_ADD(seconds,seconds,result);
  682.   /* normalize to time base on positive for 1970, - for before that period */
  683.   LL_SUB(seconds,seconds,base);
  684.  
  685.   /* set dst information */
  686.   if(prtm->tm_isdst < 0)
  687.       prtm->tm_isdst = 0;
  688.   return seconds;
  689. }
  690.  
  691. /*
  692.  * basic time calculation functionality for localtime and gmtime
  693.  * setups up prtm argument with correct values based upon input number
  694.  * of seconds.
  695.  */
  696. static void
  697. PRMJ_basetime(PRInt64 tsecs, PRMJTime *prtm)
  698. {
  699.     /* convert tsecs back to year,month,day,hour,secs */
  700.     PRInt32 year    = 0;
  701.     PRInt32 month   = 0;
  702.     PRInt32 yday    = 0;
  703.     PRInt32 mday    = 0;
  704.     PRInt32 wday    = 6; /* start on a Sunday */
  705.     PRInt32 days    = 0;
  706.     PRInt32 seconds = 0;
  707.     PRInt32 minutes = 0;
  708.     PRInt32 hours   = 0;
  709.     PRInt32 isleap  = 0;
  710.     PRInt64 result;
  711.     PRInt64    result1;
  712.     PRInt64    result2;
  713.     PRInt64 base;
  714.  
  715.     LL_UI2L(result,0);
  716.     LL_UI2L(result1,0);
  717.     LL_UI2L(result2,0);
  718.  
  719.     /* get the base time via UTC */
  720.     base = PRMJ_ToExtendedTime(0);
  721.     LL_UI2L(result,  PRMJ_USEC_PER_SEC);
  722.     LL_DIV(base,base,result);
  723.     LL_ADD(tsecs,tsecs,base);
  724.  
  725.     LL_UI2L(result, PRMJ_YEAR_SECONDS);
  726.     LL_UI2L(result1,PRMJ_DAY_SECONDS);
  727.     LL_ADD(result2,result,result1);
  728.  
  729.   /* get the year */
  730.     while ((isleap == 0) ? !LL_CMP(tsecs,<,result) : !LL_CMP(tsecs,<,result2)) {
  731.     /* subtract a year from tsecs */
  732.     LL_SUB(tsecs,tsecs,result);
  733.     days += 365;
  734.     /* is it a leap year ? */
  735.     if(IS_LEAP(year)){
  736.         LL_SUB(tsecs,tsecs,result1);
  737.         days++;
  738.     }
  739.     year++;
  740.     isleap = IS_LEAP(year);
  741.     }
  742.  
  743.     LL_UI2L(result1,PRMJ_DAY_SECONDS);
  744.  
  745.     LL_DIV(result,tsecs,result1);
  746.     LL_L2I(mday,result);
  747.  
  748.   /* let's find the month */
  749.     while(((month == 1 && isleap) ?
  750.        (mday >= mtab[month] + 1) :
  751.        (mday >= mtab[month]))){
  752.     yday += mtab[month];
  753.     days += mtab[month];
  754.  
  755.     mday -= mtab[month];
  756.  
  757.     /* it's a Feb, check if this is a leap year */
  758.     if(month == 1 && isleap != 0){
  759.         yday++;
  760.         days++;
  761.         mday--;
  762.     }
  763.     month++;
  764.     }
  765.  
  766.     /* now adjust tsecs */
  767.     LL_MUL(result,result,result1);
  768.     LL_SUB(tsecs,tsecs,result);
  769.  
  770.     mday++; /* day of month always start with 1 */
  771.     days += mday;
  772.     wday = (days + wday) % 7;
  773.  
  774.     yday += mday;
  775.  
  776.     /* get the hours */
  777.     LL_UI2L(result1,PRMJ_HOUR_SECONDS);
  778.     LL_DIV(result,tsecs,result1);
  779.     LL_L2I(hours,result);
  780.     LL_MUL(result,result,result1);
  781.     LL_SUB(tsecs,tsecs,result);
  782.  
  783.  
  784.     /* get minutes */
  785.     LL_UI2L(result1,60);
  786.     LL_DIV(result,tsecs,result1);
  787.     LL_L2I(minutes,result);
  788.     LL_MUL(result,result,result1);
  789.     LL_SUB(tsecs,tsecs,result);
  790.  
  791.     LL_L2I(seconds,tsecs);
  792.  
  793.     prtm->tm_usec  = 0L;
  794.     prtm->tm_sec   = (PRInt8)seconds;
  795.     prtm->tm_min   = (PRInt8)minutes;
  796.     prtm->tm_hour  = (PRInt8)hours;
  797.     prtm->tm_mday  = (PRInt8)mday;
  798.     prtm->tm_mon   = (PRInt8)month;
  799.     prtm->tm_wday  = (PRInt8)wday;
  800.     prtm->tm_year  = (PRInt16)year;
  801.     prtm->tm_yday  = (PRInt16)yday;
  802. }
  803.  
  804. /*
  805.  * This function replaces the localtime on each platform. localtime
  806.  * unfortunately only handles time from January 1st 1970 until January 1st
  807.  * 2038. This is not sufficient for most applications. This application will
  808.  * produce time in seconds for any date.
  809.  * TO Fix:
  810.  * We also need to account for leap seconds...
  811.  */
  812. PR_IMPLEMENT(void)
  813. PRMJ_localtime(PRInt64 tsecs,PRMJTime *prtm)
  814. {
  815.     time_t seconds;
  816.     PRInt32    year;
  817.     struct tm lt;
  818. #ifdef XP_MAC
  819.     PRInt64  dstdiff;
  820.     PRInt64  s2us;
  821.     PRInt32  dstOffset;
  822. #endif
  823. #ifdef XP_MAC
  824.     LL_UI2L(dstdiff,0);
  825.     dstdiff = PRMJ_DSTOffset(dstdiff);
  826.     LL_UI2L(s2us,  PRMJ_USEC_PER_SEC);
  827.     LL_DIV(dstdiff,dstdiff,s2us);
  828.     LL_L2I(dstOffset,dstdiff);
  829.     LL_ADD(tsecs,tsecs,dstdiff);
  830. #endif
  831.     PRMJ_basetime(tsecs,prtm);
  832.  
  833.     /* Adjust DST information in prtm
  834.      * possible for us now only between 1970 and 2037
  835.       */
  836.     if((year = prtm->tm_year) >= 1970 && year <= 2037){
  837.     LL_L2I(seconds,tsecs);
  838. #ifdef XP_MAC
  839.     /* adjust to the UNIX epoch  and add DST*/
  840.     seconds += gJanuaryFirst1970Seconds;
  841.     seconds -= PRMJ_LocalGMTDifference();
  842.  
  843. /* On the Mac PRMJ_LocalGMTDifference adjusts for DST */
  844. /*    seconds += dstOffset;*/
  845.  
  846. #endif
  847. #if defined(XP_PC) || defined(XP_MAC) || defined( FREEBSD )
  848.     lt = *localtime(&seconds);
  849. #else
  850.     localtime_r(&seconds,<);
  851. #endif
  852. #ifdef XP_MAC
  853.     PRMJ_setDST(prtm);
  854. #else
  855.     prtm->tm_isdst = lt.tm_isdst;
  856. #endif
  857.     prtm->tm_mday  = lt.tm_mday;
  858.     prtm->tm_wday  = lt.tm_wday;
  859.     prtm->tm_yday  = lt.tm_yday;
  860.     prtm->tm_hour  = lt.tm_hour;
  861.     prtm->tm_min   = lt.tm_min;
  862.     prtm->tm_mon   = lt.tm_mon;
  863.     prtm->tm_sec   = lt.tm_sec;
  864.     prtm->tm_usec  = 0;
  865.     }
  866.     else
  867.     prtm->tm_isdst = 0;
  868. }
  869.  
  870.  
  871.  
  872. /*
  873.  * This function takes the local time unadjusted for DST and returns
  874.  * the GMT time.
  875.  */
  876. PR_IMPLEMENT(void)
  877. PRMJ_gmtime(PRInt64 tsecs,PRMJTime *prtm)
  878. {
  879.     PRInt64 s2us;
  880.  
  881.     LL_UI2L(s2us, PRMJ_USEC_PER_SEC);
  882.     LL_MUL(tsecs,tsecs,s2us);
  883.  
  884.     tsecs = PRMJ_ToGMT(tsecs);
  885.  
  886.     LL_DIV(tsecs,tsecs,s2us);
  887.     PRMJ_basetime(tsecs,prtm);
  888. }
  889.  
  890.  
  891.  
  892. /* The following string arrays and macros are used by PRMJ_FormatTimeUSEnglish().
  893.  * XXX export for use by jsdate.c etc.
  894.  */
  895.  
  896. static const char* abbrevDays[] =
  897. {
  898.    "Sun","Mon","Tue","Wed","Thu","Fri","Sat"
  899. };
  900.  
  901. static const char* days[] =
  902. {
  903.    "Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"
  904. };
  905.  
  906. static const char* abbrevMonths[] =
  907. {
  908.    "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
  909. };
  910.  
  911. static const char* months[] =
  912.  {
  913.     "January", "February", "March", "April", "May", "June",
  914.     "July", "August", "September", "October", "November", "December"
  915. };
  916.  
  917.  
  918. /* Add a single character to the given buffer, incrementing the buffer pointer
  919.  * and decrementing the buffer size. Return 0 on error.
  920.  */
  921. #define ADDCHAR( buf, bufSize, ch )             \
  922. do                                              \
  923. {                                               \
  924.    if( bufSize < 1 )                            \
  925.    {                                            \
  926.       *(--buf) = '\0';                          \
  927.       return 0;                                 \
  928.    }                                            \
  929.    *buf++ = ch;                                 \
  930.    bufSize--;                                   \
  931. }                                               \
  932. while(0)
  933.  
  934.  
  935. /* Add a string to the given buffer, incrementing the buffer pointer and decrementing
  936.  * the buffer size appropriately. Return 0 on error.
  937.  */
  938. #define ADDSTR( buf, bufSize, str )             \
  939. do                                              \
  940. {                                               \
  941.    size_t strSize = strlen( str );              \
  942.    if( strSize > bufSize )                      \
  943.    {                                            \
  944.       if( bufSize==0 )                          \
  945.          *(--buf) = '\0';                       \
  946.       else                                      \
  947.          *buf = '\0';                           \
  948.       return 0;                                 \
  949.    }                                            \
  950.    memcpy(buf, str, strSize);                   \
  951.    buf += strSize;                              \
  952.    bufSize -= strSize;                          \
  953. }                                               \
  954. while(0)
  955.  
  956. /* Needed by PR_FormatTimeUSEnglish() */
  957. static unsigned int  pr_WeekOfYear(const PRMJTime* time, unsigned int firstDayOfWeek);
  958.  
  959.  
  960. /***********************************************************************************
  961.  *
  962.  * Description:
  963.  *  This is a dumbed down version of strftime that will format the date in US
  964.  *  English regardless of the setting of the global locale.  This functionality is
  965.  *  needed to write things like MIME headers which must always be in US English.
  966.  *
  967.  **********************************************************************************/
  968.  
  969. PR_IMPLEMENT(size_t)
  970. PRMJ_FormatTimeUSEnglish( char* buf, size_t bufSize,
  971.                         const char* format, const PRMJTime* time )
  972. {
  973.    char*         bufPtr = buf;
  974.    const char*   fmtPtr;
  975.    char          tmpBuf[ 40 ];
  976.    const int     tmpBufSize = sizeof( tmpBuf );
  977.  
  978.  
  979.    for( fmtPtr=format; *fmtPtr != '\0'; fmtPtr++ )
  980.    {
  981.       if( *fmtPtr != '%' )
  982.       {
  983.          ADDCHAR( bufPtr, bufSize, *fmtPtr );
  984.       }
  985.       else
  986.       {
  987.          switch( *(++fmtPtr) )
  988.          {
  989.          case '%':
  990.             /* escaped '%' character */
  991.             ADDCHAR( bufPtr, bufSize, '%' );
  992.             break;
  993.  
  994.          case 'a':
  995.             /* abbreviated weekday name */
  996.             ADDSTR( bufPtr, bufSize, abbrevDays[ time->tm_wday ] );
  997.             break;
  998.  
  999.          case 'A':
  1000.             /* full weekday name */
  1001.             ADDSTR( bufPtr, bufSize, days[ time->tm_wday ] );
  1002.             break;
  1003.  
  1004.          case 'b':
  1005.             /* abbreviated month name */
  1006.             ADDSTR( bufPtr, bufSize, abbrevMonths[ time->tm_mon ] );
  1007.             break;
  1008.  
  1009.          case 'B':
  1010.             /* full month name */
  1011.             ADDSTR(bufPtr, bufSize,  months[ time->tm_mon ] );
  1012.             break;
  1013.  
  1014.          case 'c':
  1015.             /* Date and time. */
  1016.             PRMJ_FormatTimeUSEnglish( tmpBuf, tmpBufSize, "%a %b %d %H:%M:%S %Y", time );
  1017.             ADDSTR( bufPtr, bufSize, tmpBuf );
  1018.             break;
  1019.  
  1020.          case 'd':
  1021.             /* day of month ( 01 - 31 ) */
  1022.             PR_snprintf(tmpBuf,tmpBufSize,"%.2d",time->tm_mday );
  1023.             ADDSTR( bufPtr, bufSize, tmpBuf );
  1024.             break;
  1025.  
  1026.          case 'H':
  1027.             /* hour ( 00 - 23 ) */
  1028.             PR_snprintf(tmpBuf,tmpBufSize,"%.2d",time->tm_hour );
  1029.             ADDSTR( bufPtr, bufSize, tmpBuf );
  1030.             break;
  1031.  
  1032.          case 'I':
  1033.             /* hour ( 01 - 12 ) */
  1034.             PR_snprintf(tmpBuf,tmpBufSize,"%.2d",
  1035.                         (time->tm_hour%12) ? time->tm_hour%12 : 12 );
  1036.             ADDSTR( bufPtr, bufSize, tmpBuf );
  1037.             break;
  1038.  
  1039.          case 'j':
  1040.             /* day number of year ( 001 - 366 ) */
  1041.             PR_snprintf(tmpBuf,tmpBufSize,"%.3d",time->tm_yday + 1);
  1042.             ADDSTR( bufPtr, bufSize, tmpBuf );
  1043.             break;
  1044.  
  1045.          case 'm':
  1046.             /* month number ( 01 - 12 ) */
  1047.             PR_snprintf(tmpBuf,tmpBufSize,"%.2d",time->tm_mon+1);
  1048.             ADDSTR( bufPtr, bufSize, tmpBuf );
  1049.             break;
  1050.  
  1051.          case 'M':
  1052.             /* minute ( 00 - 59 ) */
  1053.             PR_snprintf(tmpBuf,tmpBufSize,"%.2d",time->tm_min );
  1054.             ADDSTR( bufPtr, bufSize, tmpBuf );
  1055.             break;
  1056.  
  1057.          case 'p':
  1058.             /* locale's equivalent of either AM or PM */
  1059.             ADDSTR( bufPtr, bufSize, (time->tm_hour<12)?"AM":"PM" );
  1060.             break;
  1061.  
  1062.          case 'S':
  1063.             /* seconds ( 00 - 61 ), allows for leap seconds */
  1064.             PR_snprintf(tmpBuf,tmpBufSize,"%.2d",time->tm_sec );
  1065.             ADDSTR( bufPtr, bufSize, tmpBuf );
  1066.             break;
  1067.  
  1068.          case 'U':
  1069.             /* week number of year ( 00 - 53  ),  Sunday  is  the first day of week 1 */
  1070.             PR_snprintf(tmpBuf,tmpBufSize,"%.2d", pr_WeekOfYear( time, 0 ) );
  1071.             ADDSTR( bufPtr, bufSize, tmpBuf );
  1072.             break;
  1073.  
  1074.          case 'w':
  1075.             /* weekday number ( 0 - 6 ), Sunday = 0 */
  1076.             PR_snprintf(tmpBuf,tmpBufSize,"%d",time->tm_wday );
  1077.             ADDSTR( bufPtr, bufSize, tmpBuf );
  1078.             break;
  1079.  
  1080.          case 'W':
  1081.             /* Week number of year ( 00 - 53  ),  Monday  is  the first day of week 1 */
  1082.             PR_snprintf(tmpBuf,tmpBufSize,"%.2d", pr_WeekOfYear( time, 1 ) );
  1083.             ADDSTR( bufPtr, bufSize, tmpBuf );
  1084.             break;
  1085.  
  1086.          case 'x':
  1087.             /* Date representation */
  1088.             PRMJ_FormatTimeUSEnglish( tmpBuf, tmpBufSize, "%m/%d/%y", time );
  1089.             ADDSTR( bufPtr, bufSize, tmpBuf );
  1090.             break;
  1091.  
  1092.          case 'X':
  1093.             /* Time representation. */
  1094.             PRMJ_FormatTimeUSEnglish( tmpBuf, tmpBufSize, "%H:%M:%S", time );
  1095.             ADDSTR( bufPtr, bufSize, tmpBuf );
  1096.             break;
  1097.  
  1098.          case 'y':
  1099.             /* year within century ( 00 - 99 ) */
  1100.             PR_snprintf(tmpBuf,tmpBufSize,"%.2d",time->tm_year % 100 );
  1101.             ADDSTR( bufPtr, bufSize, tmpBuf );
  1102.             break;
  1103.  
  1104.          case 'Y':
  1105.             /* year as ccyy ( for example 1986 ) */
  1106.             PR_snprintf(tmpBuf,tmpBufSize,"%.4d",time->tm_year );
  1107.             ADDSTR( bufPtr, bufSize, tmpBuf );
  1108.             break;
  1109.  
  1110.          case 'Z':
  1111.             /* Time zone name or no characters if  no  time  zone exists.
  1112.              * Since time zone name is supposed to be independant of locale, we
  1113.              * defer to PR_FormatTime() for this option.
  1114.              */
  1115.             PRMJ_FormatTime( tmpBuf, tmpBufSize, "%Z", (PRMJTime*)time );
  1116.             ADDSTR( bufPtr, bufSize, tmpBuf );
  1117.             break;
  1118.  
  1119.          default:
  1120.             /* Unknown format.  Simply copy format into output buffer. */
  1121.             ADDCHAR( bufPtr, bufSize, '%' );
  1122.             ADDCHAR( bufPtr, bufSize, *fmtPtr );
  1123.             break;
  1124.  
  1125.          }
  1126.       }
  1127.    }
  1128.  
  1129.    ADDCHAR( bufPtr, bufSize, '\0' );
  1130.    return (size_t)(bufPtr - buf - 1);
  1131. }
  1132.  
  1133.  
  1134.  
  1135. /***********************************************************************************
  1136.  *
  1137.  * Description:
  1138.  *  Returns the week number of the year (0-53) for the given time.  firstDayOfWeek
  1139.  *  is the day on which the week is considered to start (0=Sun, 1=Mon, ...).
  1140.  *  Week 1 starts the first time firstDayOfWeek occurs in the year.  In other words,
  1141.  *  a partial week at the start of the year is considered week 0.
  1142.  *
  1143.  **********************************************************************************/
  1144.  
  1145. static unsigned int pr_WeekOfYear(const PRMJTime* time, unsigned int firstDayOfWeek)
  1146. {
  1147.    int dayOfWeek;
  1148.    int dayOfYear;
  1149.  
  1150.   /* Get the day of the year for the given time then adjust it to represent the
  1151.    * first day of the week containing the given time.
  1152.    */
  1153.   dayOfWeek = time->tm_wday - firstDayOfWeek;
  1154.   if (dayOfWeek < 0)
  1155.     dayOfWeek += 7;
  1156.  
  1157.   dayOfYear = time->tm_yday - dayOfWeek;
  1158.  
  1159.  
  1160.   if( dayOfYear <= 0 )
  1161.   {
  1162.      /* If dayOfYear is <= 0, it is in the first partial week of the year. */
  1163.      return 0;
  1164.   }
  1165.   else
  1166.   {
  1167.      /* Count the number of full weeks ( dayOfYear / 7 ) then add a week if there
  1168.       * are any days left over ( dayOfYear % 7 ).  Because we are only counting to
  1169.       * the first day of the week containing the given time, rather than to the
  1170.       * actual day representing the given time, any days in week 0 will be "absorbed"
  1171.       * as extra days in the given week.
  1172.       */
  1173.      return (dayOfYear / 7) + ( (dayOfYear % 7) == 0 ? 0 : 1 );
  1174.   }
  1175. }
  1176.  
  1177.