G:/ScriptBasic/source/mygmtime.c

Go to the documentation of this file.
00001 /*
00002 FILE: mygmtime.c
00003 HEADER: mygmtime.h
00004 
00005 TO_HEADER:
00006 #define _DAY_SEC           (24L * 60L * 60L)
00007 #define _YEAR_SEC          (365L * _DAY_SEC)
00008 #define _FOUR_YEAR_SEC     (1461L * _DAY_SEC)
00009 #define _BASE_DOW          4                
00010 #define _BASE_YEAR         70L              
00011 #define _MAX_YEAR          138L             
00012 #define _LEAP_YEAR_ADJUST  17L              
00013 
00014 */
00015 
00016 /*--------------------------------------------------------------------------------------------
00017 
00018  This file implements the time and date handling ScriptBasic functions. Before
00019  strating the real COMMANDs we have to implement a few standard functions. These are
00020  mktime and gmtime. Why should we reinvent the wheel?
00021 
00022  For two reasons: mktime converts GMT time to local time. We do not need this conversion.
00023  mktime adjust the year value in case month value is out of range (less than zero or larger
00024  than eleven). It is implemented this way on Windows NT, but man pages do not say anything
00025  about this feature. To be sure, I copied and a bit modified to our needs the code here.
00026  Just to be sure that it works on all system the same way.
00027 
00028  The problem with the function gmtime is more serious. NEVER USE POSIX gmtime() !!!!!!
00029 
00030  The reason: I am paranoid. The POSIX definition of the function is that it has to
00031  return a pointer to a structure containing the values. But where does the structure
00032  come from? Is it static or is it allocated? If this is static, then it is not thread
00033  safe. If this is allocated, who will release the memory.
00034 
00035  Instead here is a modified versio that requests the caller to pass a pointer to an allocated and
00036  available struct tm buffer, and the returned pointer will point to this buffer.
00037 
00038  --------------------------------------------------------------------------------------------*/
00039 #include <time.h>
00040 #include "mygmtime.h"
00041 static int _lpdays[] = { -1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
00042 static int _days[] = { -1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364 };
00043 /*
00044  * ChkAdd evaluates to TRUE if dest = src1 + src2 has overflowed
00045  */
00046 #define ChkAdd(dest, src1, src2)   ( ((src1 >= 0L) && (src2 >= 0L) \
00047     && (dest < 0L)) || ((src1 < 0L) && (src2 < 0L) && (dest >= 0L)) )
00048 
00049 /*
00050  * ChkMul evaluates to TRUE if dest = src1 * src2 has overflowed
00051  */
00052 #define ChkMul(dest, src1, src2)   ( src1 ? (dest/src1 != src2) : 0 )
00053 
00054 /*FUNCTION*/
00055 long mygmktime(struct tm *tb
00056   ){
00057   time_t tmptm1, tmptm2, tmptm3;
00058   struct tm *tbtemp,Qtbtemp;
00059 
00060   /*
00061   * First, make sure tm_year is reasonably close to being in range.
00062   */
00063   if( ((tmptm1 = tb->tm_year) < _BASE_YEAR - 1) || (tmptm1 > _MAX_YEAR+ 1) )
00064      goto err_mktime;
00065 
00066   /*
00067   * Adjust month value so it is in the range 0 - 11.  This is because
00068   * we don't know how many days are in months 12, 13, 14, etc.
00069   */
00070   if( (tb->tm_mon < 0) || (tb->tm_mon > 11) ) {
00071 
00072   /* no danger of overflow because the range check above.  */
00073   tmptm1 += (tb->tm_mon / 12);
00074   if( (tb->tm_mon %= 12) < 0 ) {
00075     tb->tm_mon += 12;
00076     tmptm1--;
00077     }
00078 
00079   /*
00080   * Make sure year count is still in range.
00081   */
00082   if( (tmptm1 < _BASE_YEAR - 1) || (tmptm1 > _MAX_YEAR + 1) )
00083      goto err_mktime;
00084   }
00085 
00086   /***** HERE: tmptm1 holds number of elapsed years *****/
00087 
00088   /*
00089   * Calculate days elapsed minus one, in the given year, to the given
00090   * month. Check for leap year and adjust if necessary.
00091   */
00092   tmptm2 = _days[tb->tm_mon];
00093   if( !(tmptm1 & 3) && (tb->tm_mon > 1) )
00094     tmptm2++;
00095 
00096   /*
00097   * Calculate elapsed days since base date (midnight, 1/1/70, UTC)
00098   *
00099   * 365 days for each elapsed year since 1970, plus one more day for
00100   * each elapsed leap year. no danger of overflow because of the range
00101   * check (above) on tmptm1.
00102   */
00103   tmptm3 = (tmptm1 - _BASE_YEAR) * 365L + ((tmptm1 - 1L) >> 2)
00104           - _LEAP_YEAR_ADJUST;
00105 
00106   /* elapsed days to current month (still no possible overflow) */
00107   tmptm3 += tmptm2;
00108 
00109   /* elapsed days to current date. overflow is now possible. */
00110   tmptm1 = tmptm3 + (tmptm2 = (long)(tb->tm_mday));
00111   if( ChkAdd(tmptm1, tmptm3, tmptm2) ) goto err_mktime;
00112 
00113   /***** HERE: tmptm1 holds number of elapsed days *****/
00114 
00115   /* Calculate elapsed hours since base date */
00116   tmptm2 = tmptm1 * 24L;
00117   if( ChkMul(tmptm2, tmptm1, 24L) )goto err_mktime;
00118 
00119   tmptm1 = tmptm2 + (tmptm3 = (long)tb->tm_hour);
00120   if( ChkAdd(tmptm1, tmptm2, tmptm3) )goto err_mktime;
00121 
00122   /***** HERE: tmptm1 holds number of elapsed hours *****/
00123 
00124   /* Calculate elapsed minutes since base date */
00125 
00126   tmptm2 = tmptm1 * 60L;
00127   if( ChkMul(tmptm2, tmptm1, 60L) )goto err_mktime;
00128 
00129   tmptm1 = tmptm2 + (tmptm3 = (long)tb->tm_min);
00130   if ( ChkAdd(tmptm1, tmptm2, tmptm3) )goto err_mktime;
00131 
00132   /***** HERE: tmptm1 holds number of elapsed minutes *****/
00133 
00134   /* Calculate elapsed seconds since base date */
00135 
00136   tmptm2 = tmptm1 * 60L;
00137   if( ChkMul(tmptm2, tmptm1, 60L) )goto err_mktime;
00138 
00139   tmptm1 = tmptm2 + (tmptm3 = (long)tb->tm_sec);
00140   if ( ChkAdd(tmptm1, tmptm2, tmptm3) )goto err_mktime;
00141 
00142   /***** HERE: tmptm1 holds number of elapsed seconds *****/
00143   if( (tbtemp = mygmtime(&tmptm1,&Qtbtemp)) == NULL )goto err_mktime;
00144 
00145   *tb = *tbtemp;
00146   return tmptm1;
00147 
00148 err_mktime:
00149   /* All errors come to here */
00150   return -1L;
00151 }
00152 
00153 /*FUNCTION*/
00154 struct tm * mygmtime (time_t *timp, struct tm *ptb
00155   ){
00156   long caltim = *timp;            /* calendar time to convert */
00157   int islpyr = 0;                 /* is-current-year-a-leap-year flag */
00158   int tmptim;
00159   int *mdays;                /* pointer to days or lpdays */
00160 
00161   if( caltim < 0L )return NULL;
00162 
00163   /*
00164    * Determine years since 1970. First, identify the four-year interval
00165    * since this makes handling leap-years easy (note that 2000 IS a
00166    * leap year and 2100 is out-of-range).
00167    */
00168   tmptim = (int)(caltim / _FOUR_YEAR_SEC);
00169   caltim -= ((long)tmptim * _FOUR_YEAR_SEC);
00170 
00171   /*
00172    * Determine which year of the interval
00173    */
00174   tmptim = (tmptim * 4) + 70;         /* 1970, 1974, 1978,...,etc. */
00175 
00176   if( caltim >= _YEAR_SEC ) {
00177     tmptim++;                       /* 1971, 1975, 1979,...,etc. */
00178     caltim -= _YEAR_SEC;
00179 
00180     if( caltim >= _YEAR_SEC ) {
00181       tmptim++;                   /* 1972, 1976, 1980,...,etc. */
00182       caltim -= _YEAR_SEC;
00183 
00184       /*
00185       * Note, it takes 366 days-worth of seconds to get past a leap
00186       * year.
00187       */
00188       if( caltim >= (_YEAR_SEC + _DAY_SEC) ){
00189         tmptim++;           /* 1973, 1977, 1981,...,etc. */
00190         caltim -= (_YEAR_SEC + _DAY_SEC);
00191         }else {
00192         /*
00193         * In a leap year after all, set the flag.
00194         */
00195         islpyr++;
00196         }
00197       }
00198     }
00199 
00200   /*
00201   * tmptim now holds the value for tm_year. caltim now holds the
00202   * number of elapsed seconds since the beginning of that year.
00203   */
00204   ptb->tm_year = tmptim;
00205 
00206   /*
00207    * Determine days since January 1 (0 - 365). This is the tm_yday value.
00208    * Leave caltim with number of elapsed seconds in that day.
00209    */
00210   ptb->tm_yday = (int)(caltim / _DAY_SEC);
00211   caltim -= (long)(ptb->tm_yday) * _DAY_SEC;
00212 
00213   /*
00214   * Determine months since January (0 - 11) and day of month (1 - 31)
00215   */
00216   if( islpyr )mdays = _lpdays; else mdays = _days;
00217 
00218   for ( tmptim = 1 ; mdays[tmptim] < ptb->tm_yday ; tmptim++ ) ;
00219 
00220   ptb->tm_mon = --tmptim;
00221 
00222   ptb->tm_mday = ptb->tm_yday - mdays[tmptim];
00223 
00224   /*
00225    * Determine days since Sunday (0 - 6)
00226    */
00227   ptb->tm_wday = ((int)(*timp / _DAY_SEC) + _BASE_DOW) % 7;
00228 
00229   /*
00230    *  Determine hours since midnight (0 - 23), minutes after the hour
00231    *  (0 - 59), and seconds after the minute (0 - 59).
00232    */
00233   ptb->tm_hour = (int)(caltim / 3600);
00234   caltim -= (long)ptb->tm_hour * 3600L;
00235 
00236   ptb->tm_min = (int)(caltim / 60);
00237   ptb->tm_sec = (int)(caltim - (ptb->tm_min) * 60);
00238 
00239   ptb->tm_isdst = 0;
00240   return( (struct tm *)ptb );
00241   }
00242 
00243 static long TimeDifference(void){
00244   time_t lTime;
00245   struct tm GmTime,*pGmTime;
00246 
00247 /* calculate the time zone difference and day light saving hour together */
00248 /* not too elegant, but works */
00249   lTime = (time_t)time(NULL);
00250   pGmTime = mygmtime(&lTime,&GmTime);
00251   pGmTime->tm_isdst = -1;
00252   return (long)(lTime - mktime(pGmTime));
00253   }

Generated on Sun Mar 12 23:56:31 2006 for ScriptBasic by  doxygen 1.4.6-NO