PSTime/src/Duration.cpp

Go to the documentation of this file.
00001 //--------------------------------------------------------------------------
00002 // File and Version Information:
00003 //      $Id: Duration.cpp 5166 2013-01-25 18:57:11Z salnikov@SLAC.STANFORD.EDU $
00004 //
00005 // Description:
00006 //      Class Duration...
00007 //
00008 // Author List:
00009 //      Mikhail S. Dubrovin
00010 //
00011 //------------------------------------------------------------------------
00012 
00013 //-----------------------
00014 // This Class's Header --
00015 //-----------------------
00016 #include "PSTime/Duration.h"
00017 
00018 //-----------------
00019 // C/C++ Headers --
00020 //-----------------
00021 #include <iostream>
00022 #include <iomanip>
00023 #include <math.h>
00024 #include <stdint.h>
00025 #include <stdio.h>
00026 #include <stdlib.h>
00027 
00028 using namespace std;
00029 
00030 namespace {
00031 
00032   // number of nanoseconds in a second
00033   const uint32_t nsecInASec = 1000000000U;
00034 
00035 }  
00036   
00037 namespace PSTime {
00038 
00039 //----------------
00040 // Constructors --
00041 //----------------
00042 Duration::Duration () : m_sec( 0 ), m_nsec( 0 )
00043 {
00044 }
00045 
00046 
00047 Duration::Duration( const Duration & d ) : m_sec( d.m_sec ), m_nsec( d.m_nsec )
00048 {
00049 }
00050 
00051 
00052 Duration::Duration( time_t sec, time_t nsec ) 
00053 {
00054     if ( nsec >= ::nsecInASec )
00055         {
00056             // carry over nanoseconds into seconds
00057             time_t extraSec   = nsec / ::nsecInASec;
00058             time_t remainNsec = nsec % ::nsecInASec;
00059             sec              += extraSec;
00060             nsec              = remainNsec;
00061         }
00062 
00063     m_sec  = sec;
00064     m_nsec = nsec;
00065 }
00066 
00067 
00068 Duration::Duration( time_t Years, 
00069                     time_t Days, 
00070                     time_t Hours, 
00071                     time_t Mins, 
00072                     time_t Secs,
00073                     time_t Nsecs )
00074 {
00075   time_t SecsInYDHMS = Secs + 60*(Mins + 60*(Hours + 24*(Days + 364*Years)));
00076   Duration total( SecsInYDHMS, Nsecs );    
00077   m_sec  = total.m_sec;  
00078   m_nsec = total.m_nsec;
00079 }
00080 
00081 
00082 //-------------
00083 // Operators --
00084 //-------------
00085 
00086 // d = |d2 - d1|
00087 Duration Duration::operator - ( const Duration & d1 ) const
00088 {
00089     // This code forms |d2-d1| without having to use signed intergers.
00090 
00091     time_t  d2Sec;
00092     time_t  d2Nsec;
00093     time_t  d1Sec;
00094     time_t  d1Nsec;
00095    
00096     if ( *this > d1 )
00097         {
00098             d2Sec  = m_sec;
00099             d2Nsec = m_nsec;
00100             d1Sec  = d1.m_sec;
00101             d1Nsec = d1.m_nsec;
00102         }
00103     else
00104         {
00105             d2Sec  = d1.m_sec;
00106             d2Nsec = d1.m_nsec;
00107             d1Sec  = m_sec;
00108             d1Nsec = m_nsec;
00109         }
00110 
00111     if ( d2Nsec < d1Nsec )
00112         {
00113             // borrow a second from d2Sec
00114             d2Nsec += ::nsecInASec;
00115             d2Sec--;
00116         }
00117 
00118     time_t  sec  = d2Sec  - d1Sec;
00119     time_t  nsec = d2Nsec - d1Nsec;
00120 
00121     Duration diff( sec, nsec );
00122     return   diff;
00123 }
00124 
00125 
00126 // d = d2 + d1
00127 Duration Duration::operator + ( const Duration & d1 ) const
00128 {
00129     time_t totalSec  = m_sec  + d1.m_sec;
00130     time_t totalNsec = m_nsec + d1.m_nsec;
00131 
00132     if ( totalNsec >= ::nsecInASec )
00133         {
00134             // carry nanoseconds over into seconds
00135             time_t extraSec   = totalNsec / ::nsecInASec;
00136             time_t remainNsec = totalNsec % ::nsecInASec;
00137             totalSec         += extraSec;
00138             totalNsec         = remainNsec;
00139         }
00140 
00141     Duration sum( totalSec, totalNsec );
00142     
00143     return sum;
00144 }
00145 
00146 
00147 // d2 = d1
00148 Duration & Duration::operator = ( const Duration & d1 ) 
00149 {
00150     m_sec  = d1.m_sec;
00151     m_nsec = d1.m_nsec;
00152     return *this;
00153 }
00154 
00155 
00156 // d2 += d1
00157 Duration & Duration::operator += ( const Duration & d1 ) 
00158 {
00159     time_t totalSec  = m_sec  + d1.m_sec;
00160     time_t totalNsec = m_nsec + d1.m_nsec;
00161 
00162     if ( totalNsec >= ::nsecInASec )
00163         {
00164             // carry nanoseconds over into seconds
00165             time_t  extraSec   = totalNsec / ::nsecInASec;
00166             time_t  remainNsec = totalNsec % ::nsecInASec;
00167             totalSec          += extraSec;
00168             totalNsec          = remainNsec;
00169         }
00170 
00171     m_sec  = totalSec;
00172     m_nsec = totalNsec;    
00173     return *this;
00174 }
00175 
00176 //--------------------
00177 //  -- Public methods
00178 //--------------------
00179 
00180 void Duration::Print() const
00181 {
00182     printf ( "Duration:: m_sec = %ld   m_nsec = %ld \n", m_sec, m_nsec);
00183 
00184       time_t Years(0); 
00185       time_t DaysAfterY(0);
00186       time_t HoursAfterD(0); 
00187       time_t MinsAfterH(0); 
00188       time_t SecsAfterM(0);
00189 
00190     splitDurationSecsForYDHMS( Years, 
00191                              DaysAfterY, 
00192                              HoursAfterD, 
00193                              MinsAfterH, 
00194                              SecsAfterM );
00195 
00196     printf ( "Duration:  P%ldY%ldDT%dH%dM%dS  ",
00197                              Years, 
00198                              DaysAfterY, 
00199                              (int)HoursAfterD, 
00200                              (int)MinsAfterH, 
00201                              (int)SecsAfterM );
00202     printf ( " or P%ldY %ldD T%dH %dM %dS  ",
00203                              Years, 
00204                              DaysAfterY, 
00205                              (int)HoursAfterD, 
00206                              (int)MinsAfterH, 
00207                              (int)SecsAfterM );
00208 
00209     printf ( " or %s  \n", strDurationBasic().data() );
00210 }
00211 
00212 
00213 string Duration::strDurationBasic() const
00214 {
00215       time_t Years(0); 
00216       time_t DaysAfterY(0);
00217       time_t HoursAfterD(0); 
00218       time_t MinsAfterH(0); 
00219       time_t SecsAfterM(0);
00220 
00221     splitDurationSecsForYDHMS( Years, 
00222                                DaysAfterY, 
00223                                HoursAfterD, 
00224                                MinsAfterH, 
00225                                SecsAfterM );
00226     time_t NsecAfterS = m_nsec;
00227 
00228     string strD = "P";
00229 
00230     if ( Years      != 0 ) { char charY[8];   snprintf( charY, sizeof charY, "%ldY",Years );       strD += charY; }
00231     if ( DaysAfterY != 0 ) { char charD[8];   snprintf( charD, sizeof charD, "%ldD",DaysAfterY );  strD += charD; }
00232 
00233            strD += "T";
00234 
00235     if ( HoursAfterD!= 0 ) { char charH[8];   snprintf( charH, sizeof charH,"%ldH",HoursAfterD ); strD += charH; }
00236     if ( MinsAfterH != 0 ) { char charM[8];   snprintf( charM, sizeof charM,"%ldM",MinsAfterH );  strD += charM; }
00237     if ( SecsAfterM != 0 ) { char charS[8];   snprintf( charS, sizeof charS,"%ldS",SecsAfterM );  strD += charS; }
00238     if ( NsecAfterS != 0 ) { char charN[16];   snprintf( charN, sizeof charN,"%ldN",NsecAfterS );  strD += charN; }
00239 
00240     return strD;
00241 }
00242 
00243 //--------------------
00244 //  -- Static methods
00245 //--------------------
00246 
00247 /** The parsification engine,
00248  *  the string in standard format P[nY][nM][nD][T[nH][nM][n[.f]S]] is parsed in Duration
00249  */
00250 int Duration::parseStringToDuration( const std::string& str_dur, Duration& d )
00251 {
00252   d.m_sec  = 0;
00253   d.m_nsec = 0;
00254 
00255   // Check the duration string size
00256   size_t len_str_dur = str_dur.size();
00257   if( len_str_dur < 3 ) {return DURATION_STRING_TOO_SHORT;} // i.e. P2D
00258   if( len_str_dur > 30) {return DURATION_STRING_TOO_LONG;} // 20 w/o ns P01Y01M01DT01H01M01S
00259 
00260   // Find position of separators, if available
00261   size_t posP   = str_dur.find('P'); // Period
00262   size_t posY   = str_dur.find('Y'); // Year
00263   size_t posD   = str_dur.find('D'); // Day
00264   size_t posT   = str_dur.find('T'); // Time of the duration in Hours, Minutes, Seconds
00265   size_t posH   = str_dur.find('H'); // Hours
00266   size_t posF   = str_dur.find('.'); // Fraction of the second's decimal point
00267   size_t posS   = str_dur.find('S'); // Seconds
00268   size_t posM   = str_dur.find_first_of('M'); // Month
00269   size_t posMin = str_dur.find_last_of('M');  // Minutes
00270 
00271   if ( posP == string::npos ) { return DURATION_STRING_WRONG_FORMAT_MISSING_P; }
00272 
00273   size_t posN1 = posP + 1;
00274   size_t posNN;
00275 
00276   // sparse duration Y:
00277   if ( posY != string::npos ) { 
00278        posNN = posY - 1;
00279        size_t lenY = posNN - posN1 + 1;
00280        if( lenY > 7 ) {return DURATION_TOO_LONG_FIELD_FOR_YEARS;} 
00281        char charY[8];
00282        size_t lenY_copy=str_dur.copy(charY,lenY,posN1); charY[lenY_copy] = '\0';      
00283        d.m_sec += atoi(charY)*3600*24*364;
00284        posN1 = posY + 1;
00285   }
00286 
00287   // sparse duration M:
00288   if ( posM != string::npos ) {
00289        posNN = posM - 1;
00290        size_t lenM = posNN - posN1 + 1;
00291        if( lenM > 7 ) {return DURATION_TOO_LONG_FIELD_FOR_MONTHS;} 
00292        char charM[8];
00293        size_t lenM_copy=str_dur.copy(charM,lenM,posN1); charM[lenM_copy] = '\0';
00294        d.m_sec += atoi(charM)*3600*24*30;
00295        posN1 = posM + 1;
00296   }
00297 
00298   // sparse duration D:
00299   if ( posD != string::npos ) {
00300        posNN = posD - 1;
00301        size_t lenD = posNN - posN1 + 1;
00302        if( lenD > 7 ) {return DURATION_TOO_LONG_FIELD_FOR_DAYS;} 
00303        char charD[8];
00304        size_t lenD_copy=str_dur.copy(charD,lenD,posN1); charD[lenD_copy] = '\0';
00305        d.m_sec += atoi(charD)*3600*24;
00306        posN1 = posD + 2;
00307   }
00308 
00309   // check duration T:
00310   if ( posT != string::npos ) { // T info (H, M, S) is missing
00311     posN1 = posT + 1;
00312   }
00313   else
00314   {
00315     return PARSE_IS_OK;
00316   }
00317 
00318   // sparse duration H:
00319   if ( posH != string::npos ) {
00320     posNN = posH - 1;
00321     size_t lenH = posNN - posN1 + 1;
00322     if( lenH > 7 ) {return DURATION_TOO_LONG_FIELD_FOR_HOURS;} 
00323     char charH[8];
00324     size_t lenH_copy=str_dur.copy(charH,lenH,posN1); charH[lenH_copy] = '\0';
00325     d.m_sec += atoi(charH)*3600;
00326     posN1 = posH + 1;
00327   }
00328 
00329   // sparse duration M:
00330   if ( posMin != string::npos ) {
00331     posNN = posMin - 1;
00332     size_t lenM = posNN - posN1 + 1;
00333     if( lenM > 7 ) {return DURATION_TOO_LONG_FIELD_FOR_MINUTES;} 
00334     char charM[8];
00335     size_t lenM_copy=str_dur.copy(charM,lenM,posN1); charM[lenM_copy] = '\0';
00336     d.m_sec += atoi(charM)*60;
00337     posN1 = posMin + 1;
00338   }
00339 
00340   // Case of fractional second:
00341   // sparse duration S integer part of seconds:
00342   if ( posF != string::npos && posS != string::npos) {
00343     posNN = posF - 1;
00344     size_t lenS = posNN - posN1 + 1;
00345     if( lenS > 15 ) {return DURATION_TOO_LONG_FIELD_FOR_SECONDS;} 
00346     char charS[16];
00347     size_t lenS_copy=str_dur.copy(charS,lenS,posN1); charS[lenS_copy] = '\0';
00348     d.m_sec += atoi(charS);
00349     posN1 = posF + 1;
00350 
00351   // sparse duration S fractional part of second:
00352     posNN = posS - 1;
00353     size_t lenF = posNN - posN1 + 1;
00354     if( lenF > 9 ) {return DURATION_TOO_LONG_FIELD_FOR_SECOND_FRACTION;} 
00355     char charF[16];
00356     size_t lenF_copy=str_dur.copy(charF,lenF,posN1); charF[lenF_copy] = '\0';
00357     double frac_of_sec  = (double)atoi(charF);
00358     d.m_nsec = (size_t)(frac_of_sec * pow(10,9-lenF_copy));
00359     return PARSE_IS_OK;
00360   }
00361 
00362   // sparse duration S in integer seconds:
00363   if ( posS != string::npos) {
00364     posNN = posS - 1;
00365     size_t lenS = posNN - posN1 + 1;
00366     if( lenS > 7 ) {return DURATION_TOO_LONG_FIELD_FOR_SECONDS;} 
00367     char charS[16];
00368     size_t lenS_copy=str_dur.copy(charS,lenS,posN1); charS[lenS_copy] = '\0';
00369     d.m_sec += atoi(charS);
00370     posN1 = posF + 1;
00371   }
00372     return PARSE_IS_OK;
00373 }
00374 
00375 //--------------------
00376 //  -- Private methods
00377 //--------------------
00378 
00379 void Duration::splitDurationSecsForYDHMS(time_t &Years, 
00380                                          time_t &DaysAfterY, 
00381                                          time_t &HoursAfterD, 
00382                                          time_t &MinsAfterH, 
00383                                          time_t &SecsAfterM) const
00384 {
00385   Years             = m_sec / (364*24*3600);  
00386   time_t SecsAfterY = m_sec % (364*24*3600);
00387   DaysAfterY        = SecsAfterY / (24*3600); 
00388   time_t SecsAfterD = SecsAfterY % (24*3600); 
00389   HoursAfterD       = SecsAfterD / 3600;
00390   time_t SecsAfterH = SecsAfterD % 3600; 
00391   MinsAfterH        = SecsAfterH / 60;
00392   SecsAfterM        = SecsAfterH % 60; 
00393 }
00394 
00395 
00396 //-----------
00397 // Friends --
00398 //-----------
00399 
00400 // overloaded stream-insertion operator <<
00401 ostream & operator << ( ostream & os, const Duration & d )
00402 {
00403     if ( d.m_nsec == 0 )
00404         {
00405             os << d.m_sec << " sec";
00406             return os;
00407         }
00408     else
00409         {
00410             cout.fill( '0' );
00411             os << d.m_sec << "." << setw(9) << d.m_nsec << " sec";
00412             cout.fill( ' ' );
00413             return os;
00414         }
00415 }
00416 
00417 } // namespace PSTime

Generated on 19 Dec 2016 for PSANAclasses by  doxygen 1.4.7