00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include <lib/htime.h>
00018
00019 #include <stdio.h>
00020 #include <ctype.h>
00021
00022
00023
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
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
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(¤t);
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(¤t);
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
00163
00164
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
00257
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
00270
00271 if(tv.tv_sec<0)
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)
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
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
00341
00342 int HTime::_DoReadTime(const char *str)
00343 {
00344
00345 time_t timep;
00346 ::time(&timep);
00347 struct tm t;
00348 ::localtime_r(&timep,&t);
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358 short int state=0,done=0;
00359 int mode=0;
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)
00370 {
00371 if(*s=='+') mode=1;
00372 else if(*s=='-') mode=-1;
00373 else return(-2);
00374
00375 ++s; done|=6;
00376
00377
00378 while(isspace(*s)) ++s;
00379
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;
00388 }
00389
00390 }
00391
00392
00393 }
00394
00395
00396 if(strchr(s,'-'))
00397 { return(-1); }
00398
00399 int data[3];
00400 int di=0;
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
00410 return(-1);
00411 }
00412 s=end;
00413
00414 switch(state)
00415 {
00416 case 0:
00417 switch(*s)
00418 {
00419 case '.': state=1; break;
00420 case '/': state=2; break;
00421 case ':': state=3; break;
00422 default:
00423
00424 return(-1);
00425 }
00426 if(state)
00427 {
00428 if(done & (1<<state))
00429 {
00430
00431 return(-2);
00432 }
00433 data[di++]=tmp;
00434 ++s;
00435 }
00436 break;
00437 case 1:
00438 if(*s=='.' && di==1)
00439 {
00440 data[di++]=tmp;
00441 ++s;
00442 if(!(*s) || isspace(*s) || *s==',')
00443 { goto datedone1; }
00444 }
00445 else if(di==2)
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
00456 return(-1);
00457 }
00458 break;
00459 case 2:
00460 if(*s=='/' && di==1)
00461 {
00462 data[di++]=tmp;
00463 ++s;
00464 }
00465 else if(di==2)
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
00475 return(-1);
00476 }
00477 break;
00478 case 3:
00479 if((*s==':' || !(*s) || isspace(*s) || *s==',') && di==1)
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)
00487 {
00488 data[di++]=tmp;
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
00507 return(-1);
00508 }
00509 break;
00510 }
00511 }
00512 if(di)
00513 {
00514
00515 return(-1);
00516 }
00517
00518 timep=mktime(&t);
00519 if(timep<0)
00520 {
00521
00522 return(-3);
00523 }
00524
00525
00526 tv.tv_sec=timep;
00527 tv.tv_usec=0;
00528
00529
00530
00531
00532
00533 return(0);
00534 }