Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

/ray/src/lib/htime.cc

Go to the documentation of this file.
00001 /*
00002  * lib/htime.cc
00003  * 
00004  * Implementation of methods supporting class HTime. 
00005  * 
00006  * Copyright (c) 2001--2004 by Wolfgang Wieser ] wwieser (a) gmx <*> de [ 
00007  * 
00008  * This file may be distributed and/or modified under the terms of the 
00009  * GNU General Public License version 2 as published by the Free Software 
00010  * Foundation. (See COPYING.GPL for details.)
00011  * 
00012  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00013  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00014  * 
00015  */
00016 
00017 #include <lib/htime.h>
00018 
00019 #include <stdio.h>   /* for snprintf() */
00020 #include <ctype.h>
00021 
00022 
00023 // Used constants: 
00024 const int64_t HTime::conv_fact[HTime::_tslast]=
00025 { 1LL, 1000LL, 1000000LL, 60000000LL, 3600000000LL, 86400000000LL };
00026 
00027 const int64_t HTime::round_delta[HTime::_tslast]=
00028 { 0LL,  500LL,  500000LL, 30000000LL, 1800000000LL, 43200000000LL };
00029 
00030 const double HTime::conv_factD[HTime::_tslast]=
00031 { 1.0, 1000.0, 1000000.0, 60000000.0, 3600000000.0, 86400000000.0 };
00032 
00033 
00034 static const char *_is_invalid_str="[invalid time]";
00035 
00036 
00037 #if HTIME_WITH_MOST_CURRENT
00038 // Static data: 
00039 HTime HTime::most_current(HTime::Curr);
00040 FastMutex HTime::most_current_mutex;
00041 #endif
00042 
00043 
00044 void HTime::_SetVal(long val,TimeSpec sp,timeval *tv)
00045 {
00046     tv->tv_usec=0L;
00047     switch(sp)
00048     {
00049         case usec:
00050         {
00051             register long m=val/1000000;
00052             if(val<0)  --m;
00053             tv->tv_sec=m;
00054             tv->tv_usec=val-m*1000000;
00055         }  break;
00056         case msec:
00057         {
00058             register long m=val/1000;
00059             if(val<0)  --m;
00060             tv->tv_sec=m;
00061             tv->tv_usec=1000*(val-m*1000);
00062         }  break;
00063         case seconds:  tv->tv_sec=val;        break;
00064         case minutes:  tv->tv_sec=val*60;     break;
00065         case hours:    tv->tv_sec=val*3600;   break;
00066         case days:     tv->tv_sec=val*86400;  break;
00067         default:  tv->tv_sec=0;  break;
00068     }
00069 }
00070 
00071 void HTime::_SetValL(int64_t val,TimeSpec sp,timeval *tv)
00072 {
00073     switch(sp)
00074     {
00075         case usec:
00076         {
00077             register int64_t m=val/1000000;
00078             if(val<0)  --m;
00079             tv->tv_sec=m;
00080             tv->tv_usec=val-m*1000000;
00081         }  break;
00082         case msec:
00083         {
00084             register int64_t m=val/1000;
00085             if(val<0)  --m;
00086             tv->tv_sec=m;
00087             tv->tv_usec=1000*(val-m*1000);
00088         }  break;
00089         case seconds:
00090             tv->tv_sec=val;
00091             tv->tv_usec=0L;
00092             break;
00093         default:  _SetVal(val,sp,tv);
00094     }
00095 }
00096 
00097 
00098 HTime &HTime::Add(long val,TimeSpec sp)
00099 {
00100     if(!IsInvalid())
00101     {
00102         timeval tmp;
00103         _SetVal(val,sp,&tmp);
00104         tv.tv_sec+=tmp.tv_sec;
00105         tv.tv_usec+=tmp.tv_usec;
00106         _Normalize(&tv);
00107     }
00108     return(*this);
00109 }
00110 
00111 
00112 HTime &HTime::Sub(long val,TimeSpec sp)
00113 {
00114     if(!IsInvalid())
00115     {
00116         timeval tmp;
00117         _SetVal(val,sp,&tmp);
00118         tv.tv_sec-=tmp.tv_sec;
00119         tv.tv_usec-=tmp.tv_usec;
00120         _Normalize(&tv);
00121     }
00122     return(*this);
00123 }
00124 
00125 
00126 int64_t HTime::_Delta(const HTime *endtime) const
00127 {
00128     // May not be called if time is invalid. 
00129     timeval tmp;
00130     const timeval *end;
00131     if(endtime)
00132     {  end=&endtime->tv;  }
00133     else
00134     {  do_gettimeofday(&tmp);  end=&tmp;  }
00135     return(
00136         (int64_t(end->tv_sec)*int64_t(1000000) + int64_t(end->tv_usec)) - 
00137         (int64_t(  tv.tv_sec)*int64_t(1000000) + int64_t(  tv.tv_usec)) );
00138 }
00139 
00140 
00141 long HTime::MsecElapsed() const
00142 {
00143     timeval current;
00144     do_gettimeofday(&current);
00145     return(
00146         (current.tv_sec  - tv.tv_sec )*1000L + 
00147         (current.tv_usec - tv.tv_usec)/1000L );
00148 }
00149 
00150 long HTime::MsecElapsedR() const
00151 {
00152     timeval current;
00153     long du;
00154     do_gettimeofday(&current);
00155     du = (current.tv_usec - tv.tv_usec);
00156     return(
00157         (current.tv_sec  - tv.tv_sec)*1000L + 
00158         ((du<0L) ? (du-500) : (du+500) )/1000L );
00159 }
00160 
00161 
00162 // NOTE on sec and usec values: 
00163 // True value is always sec+usec/1000000. 
00164 // However, usec is ALWAYS in range 0...999999; NEVER negative. 
00165 
00166 HTime HTime::operator-(const HTime &start) const
00167 {
00168     HTime r(Invalid);
00169     
00170     if(!IsInvalid() && !start.IsInvalid())
00171     {
00172         r.tv.tv_sec= tv.tv_sec- start.tv.tv_sec;
00173         r.tv.tv_usec=tv.tv_usec-start.tv.tv_usec;
00174         _Normalize(&r.tv);
00175     }
00176     
00177     return(r);
00178 }
00179 
00180 HTime &HTime::operator-=(const HTime &start)
00181 {
00182     if(!IsInvalid())
00183     {
00184         if(start.IsInvalid())
00185         {  SetInvalid();  }
00186         else
00187         {
00188             tv.tv_sec-= start.tv.tv_sec;
00189             tv.tv_usec-=start.tv.tv_usec;
00190             _Normalize(&tv);
00191         }
00192     }
00193     return(*this);
00194 }
00195 
00196 
00197 HTime HTime::operator+(const HTime &start) const
00198 {
00199     HTime r(Invalid);
00200     
00201     if(!IsInvalid() && !start.IsInvalid())
00202     {
00203         r.tv.tv_sec= tv.tv_sec+ start.tv.tv_sec;
00204         r.tv.tv_usec=tv.tv_usec+start.tv.tv_usec;
00205         _Normalize(&r.tv);
00206     }
00207     
00208     return(r);
00209 }
00210 
00211 HTime &HTime::operator+=(const HTime &start)
00212 {
00213     if(!IsInvalid())
00214     {
00215         if(start.IsInvalid())
00216         {  SetInvalid();  }
00217         else
00218         {
00219             tv.tv_sec+= start.tv.tv_sec;
00220             tv.tv_usec+=start.tv.tv_usec;
00221             _Normalize(&tv);
00222         }
00223     }
00224     return(*this);
00225 }
00226 
00227 
00228 HTime &HTime::operator-()
00229 {
00230     if(!IsInvalid())
00231     {
00232         tv.tv_sec=-tv.tv_sec;
00233         tv.tv_usec=-tv.tv_usec;
00234         _Normalize(&tv);
00235     }
00236     return(*this);
00237 }
00238 
00239 
00240 HTime &HTime::Div(int fact)
00241 {
00242     if(!IsInvalid())
00243     {
00244         if(!fact)
00245         {  SetInvalid();  }
00246         else
00247         {
00248             if(fact<0)
00249             {
00250                 tv.tv_sec=-tv.tv_sec;
00251                 tv.tv_usec=-tv.tv_usec;
00252                 _Normalize(&tv);
00253                 fact=-fact;
00254             }
00255             
00256             // This may overflow if fact is large 
00257             // (around 2000 on 32bit systems). 
00258             tv.tv_usec=((tv.tv_sec%fact)*1000000+tv.tv_usec)/fact;
00259             tv.tv_sec/=fact;
00260             _Normalize(&tv);
00261         }
00262     }
00263     return(*this);
00264 }
00265 
00266 
00267 char *HTime::PrintTime(char *buf,size_t len,int local,int with_msec) const
00268 {
00269     // Negative times do not make sense here. 
00270     // (Or should that be before 1970?!)
00271     if(tv.tv_sec<0)  // This check is correct and sufficient. (usec NEVER negative)
00272     {  snprintf(buf,len,"[negative time]");  return(buf);  }
00273     if(IsInvalid())
00274     {  snprintf(buf,len,_is_invalid_str);  return(buf);  }
00275     
00276     time_t timep=tv.tv_sec;
00277     int msec=(tv.tv_usec+500)/1000;
00278     if(msec>=1000)
00279     {  ++timep;  msec-=1000;  }
00280     if(msec>=500 && !with_msec)  ++timep;  
00281     
00282     struct tm stm;
00283     if(local)  localtime_r(&timep,&stm);
00284     else       gmtime_r(&timep,&stm);
00285     
00286     char *ptr=buf;
00287     char *end=buf+len;
00288     ptr+=strftime(ptr,end-buf,"%a %b %d %Y, %H:%M:%S",&stm);
00289     if(with_msec && end>buf)
00290     {  ptr+=snprintf(ptr,end-ptr,".%03d",msec);  }
00291     if(end>buf)
00292     {  strftime(ptr,end-buf," %Z",&stm);  }
00293     
00294     return(buf);
00295 }
00296 
00297 
00298 char *HTime::PrintElapsed(char *buf,size_t len,int with_msec) const
00299 {
00300     if(IsInvalid())
00301     {  snprintf(buf,len,_is_invalid_str);  return(buf);  }
00302     
00303     char *ptr=buf;
00304     char *end=buf+len;
00305     
00306     long sec,msec;
00307     if(tv.tv_sec>=0)  // This check is correct and sufficient. (usec NEVER negative)
00308     {
00309         sec=tv.tv_sec;
00310         msec=(tv.tv_usec+500)/1000;
00311     }
00312     else
00313     {
00314         sec=-tv.tv_sec-1;
00315         msec=((1000000-tv.tv_usec)+500)/1000;
00316         *(ptr++)='-';
00317     }
00318     if(msec>=1000)
00319     {  --sec;  msec-=1000;  }
00320     // Correct rounding. (sec>=0 here because negative case handeled above). 
00321     if(!with_msec && msec>=500)
00322     {  ++sec;  }
00323     
00324     long hours=(sec/3600);
00325     if(hours>48)
00326     {
00327         ptr+=snprintf(ptr,end-ptr,"%ldd ",hours/24);
00328         hours%=24;
00329     }
00330     snprintf(ptr,end-ptr,with_msec ? "%02ld:%02ld:%02ld.%03ld" : "%02ld:%02ld:%02ld",
00331         hours,
00332         (sec/60)%60,
00333         sec%60,
00334         msec);
00335     
00336     return(buf);
00337 }
00338 
00339 
00340 //                            ** WARNING: **
00341 // DO NOT TOUCH THIS FUNCTION UNLESS YOU REALLY KNOW WHAT YOU ARE DOING. 
00342 int HTime::_DoReadTime(const char *str)
00343 {
00344     // First, set up t with current local time: 
00345     time_t timep;
00346     ::time(&timep);
00347     struct tm t;
00348     ::localtime_r(&timep,&t);
00349     
00350     // state: 
00351     //   0 -> decide
00352     //   1 -> read date 15.06.[2002]
00353     //   2 -> read date 2002/06/15
00354     //   3 -> read time 17:22[:32]
00355     // done: bit 1,2 -> date
00356     //       bit   3 -> time
00357     //       ( so that we can check (done & (1<<state)) )
00358     short int state=0,done=0;
00359     int mode=0;  // mode=1 for "+"; mode=-1 for "-". 
00360     
00361     const char *s=str;
00362     int tmp;
00363     char *end;
00364     while(isspace(*s))  ++s;
00365     if(!strncmp(s,"now",3) || !strncmp(s,"NOW",3))
00366     {
00367         s+=3;
00368         while(isspace(*s))  ++s;
00369         if(*s)  // specified something after "now"
00370         {
00371             if(*s=='+')  mode=1;
00372             else if(*s=='-')  mode=-1;
00373             else  return(-2);
00374             // In this case I only allow to add a time, not a date. 
00375             ++s;  done|=6;
00376             
00377             // Special cases: "now + DD" and "now + :SS": 
00378             while(isspace(*s))  ++s;
00379             // DO NOT modify s below here. 
00380             short int issec = (*s==':') ? 1 : 0;
00381             tmp=(int)strtol(s+issec,&end,10);
00382             while(isspace(*end))  ++end;
00383             if(!(*end) && tmp>=0 && end>s+issec)
00384             {
00385                 if(issec)  t.tm_sec+=mode*tmp;
00386                 else       t.tm_mday+=mode*tmp;
00387                 s=end;   // --> *s='\0'
00388             }
00389             // fall through to rest
00390         }
00391         // If !(*s) we will not enter the while loop and set 
00392         // current date and time. 
00393     }
00394     
00395     // Prevent any negative values...
00396     if(strchr(s,'-'))
00397     {  return(-1);  }
00398     
00399     int data[3];
00400     int di=0;  // data index
00401     while(*s)
00402     {
00403         while(isspace(*s) || (state==0 && *s==','))  ++s;
00404         if(!(*s))  break;
00405         
00406         tmp=(int)strtol(s,&end,10);
00407         if(s==end)
00408         {
00409             //fprintf(stderr,"format error: %s\n",s);
00410             return(-1);
00411         }
00412         s=end;
00413         
00414         switch(state)
00415         {
00416             case 0:  // decide what to do
00417                 switch(*s)
00418                 {
00419                     case '.':  state=1;  break;
00420                     case '/':  state=2;  break;
00421                     case ':':  state=3;  break;
00422                     default:
00423                         //fprintf(stderr,"format error: %s\n",s);
00424                         return(-1);
00425                 }
00426                 if(state)
00427                 {
00428                     if(done & (1<<state))
00429                     {
00430                         //fprintf(stderr,"specified more than once\n");
00431                         return(-2);
00432                     }
00433                     data[di++]=tmp;
00434                     ++s;
00435                 }
00436                 break;
00437             case 1:  // "15.06.2002" or "15.06."
00438                 if(*s=='.' && di==1)  // month
00439                 {
00440                     data[di++]=tmp;
00441                     ++s;
00442                     if(!(*s) || isspace(*s) || *s==',')
00443                     {  goto datedone1;  }
00444                 }
00445                 else if(di==2)  // year
00446                 {
00447                     t.tm_year=tmp-1900;
00448                     datedone1:
00449                     t.tm_mday=data[0];
00450                     t.tm_mon=data[1]-1;
00451                     state=0;  di=0;  done|=6;
00452                 }
00453                 else
00454                 {
00455                     //fprintf(stderr,"format error: %s\n",s);
00456                     return(-1);
00457                 }
00458                 break;
00459             case 2:  // "2002/06/15"
00460                 if(*s=='/' && di==1)  // month
00461                 {
00462                     data[di++]=tmp;
00463                     ++s;
00464                 }
00465                 else if(di==2)   // day
00466                 {
00467                     t.tm_mday=tmp;
00468                     t.tm_mon=data[1]-1;
00469                     t.tm_year=data[0]-1900;
00470                     state=0;  di=0;  done|=6;
00471                 }
00472                 else
00473                 {
00474                     //fprintf(stderr,"format error: %s\n",s);
00475                     return(-1);
00476                 }
00477                 break;
00478             case 3:  // "17:22:32" or "17:22"
00479                 if((*s==':' || !(*s) || isspace(*s) || *s==',') && di==1)  // minutes
00480                 {
00481                     data[di++]=tmp;
00482                     tmp=0;
00483                     if(*s==':')  ++s;
00484                     if(!(*s) || isspace(*s) || *s==',')  goto  timedone;
00485                 }
00486                 else if(di==2)  // seconds
00487                 {
00488                     data[di++]=tmp;  // yes! [DO NOT REMOVE]
00489                     timedone:
00490                     if(mode==0)
00491                     {
00492                         t.tm_hour=data[0];
00493                         t.tm_min=data[1];
00494                         t.tm_sec=tmp;
00495                     }
00496                     else
00497                     {
00498                                  t.tm_sec+=mode*data[--di];
00499                         if(di) { t.tm_min+=mode*data[--di];
00500                         if(di)   t.tm_hour+=mode*data[--di]; }
00501                     }
00502                     state=0;  di=0;  done|=8;
00503                 }
00504                 else
00505                 {
00506                     //fprintf(stderr,"format error: %s\n",s);
00507                     return(-1);
00508                 }
00509                 break;
00510         }
00511     }
00512     if(di)
00513     {
00514         //fprintf(stderr,"format error: di=%d\n",di);
00515         return(-1);
00516     }
00517     
00518     timep=mktime(&t);
00519     if(timep<0)
00520     {
00521         //fprintf(stderr,"mktime error\n");
00522         return(-3);
00523     }
00524     
00525     // Store it...
00526     tv.tv_sec=timep;
00527     tv.tv_usec=0;
00528     
00529     // Check: This may show a time difference becuase LOCAL time 
00530     //        was read in. 
00531     //fprintf(stderr,"SUCCESS= %s",ctime(&timep));  // <-- NOT thread-safe!
00532     
00533     return(0);
00534 }

Generated on Sat Feb 19 22:33:45 2005 for Ray by doxygen 1.3.5