Back to index

nordugrid-arc-nox  1.1.0~rc6
DateTime.cpp
Go to the documentation of this file.
00001 // -*- indent-tabs-mode: nil -*-
00002 
00003 #ifdef HAVE_CONFIG_H
00004 #include "config.h"
00005 #endif
00006 
00007 #include <cstdio>
00008 #include <iomanip>
00009 #include <sstream>
00010 
00011 #include "DateTime.h"
00012 #include "StringConv.h"
00013 #include "Logger.h"
00014 #include "Utils.h"
00015 
00016 
00017 #ifndef HAVE_TIMEGM
00018 time_t timegm(struct tm *tm) {
00019   bool found;
00020   std::string tz = Arc::GetEnv("TZ", found);
00021   Arc::SetEnv("TZ", "UTC");
00022   tzset();
00023   tm->tm_isdst = -1;
00024   time_t ret = mktime(tm);
00025   if (found)
00026     Arc::SetEnv("TZ", tz);
00027   else
00028     Arc::UnsetEnv("TZ");
00029   tzset();
00030   return ret;
00031 }
00032 #endif
00033 
00034 
00035 #ifndef HAVE_LOCALTIME_R
00036 struct tm* localtime_r(const time_t *timep, struct tm *result) {
00037   struct tm *TM = localtime(timep);
00038   *result = *TM;
00039   return result;
00040 }
00041 #endif
00042 
00043 
00044 #ifndef HAVE_GMTIME_R
00045 struct tm* gmtime_r(const time_t *timep, struct tm *result) {
00046   struct tm *TM = gmtime(timep);
00047   *result = *TM;
00048   return result;
00049 }
00050 #endif
00051 
00052 
00053 namespace Arc {
00054 
00055   static Logger dateTimeLogger(Logger::getRootLogger(), "DateTime");
00056 
00057 
00058   TimeFormat Time::time_format = UserTime;
00059 
00060 
00061   Time::Time()
00062     : gtime(time(NULL)) {}
00063 
00064 
00065   Time::Time(const time_t& time)
00066     : gtime(time) {}
00067 
00068 
00069   Time::Time(const std::string& timestring)
00070     : gtime(-1) {
00071 
00072     if (timestring.empty()) {
00073       dateTimeLogger.msg(ERROR, "Empty string");
00074       return;
00075     }
00076 
00077     if (isdigit(timestring[0])) {
00078       tm timestr;
00079       std::string::size_type pos = 0;
00080 
00081       if (sscanf(timestring.substr(pos, 10).c_str(),
00082                  "%4d-%2d-%2d",
00083                  &timestr.tm_year,
00084                  &timestr.tm_mon,
00085                  &timestr.tm_mday) == 3)
00086         pos += 10;
00087       else if (sscanf(timestring.substr(pos, 8).c_str(),
00088                       "%4d%2d%2d",
00089                       &timestr.tm_year,
00090                       &timestr.tm_mon,
00091                       &timestr.tm_mday) == 3)
00092         pos += 8;
00093       else {
00094         dateTimeLogger.msg(ERROR, "Can not parse date: %s", timestring);
00095         return;
00096       }
00097 
00098       timestr.tm_year -= 1900;
00099       timestr.tm_mon--;
00100 
00101       if (timestring[pos] == 'T' || timestring[pos] == ' ')
00102         pos++;
00103 
00104       if (sscanf(timestring.substr(pos, 8).c_str(),
00105                  "%2d:%2d:%2d",
00106                  &timestr.tm_hour,
00107                  &timestr.tm_min,
00108                  &timestr.tm_sec) == 3)
00109         pos += 8;
00110       else if (sscanf(timestring.substr(pos, 6).c_str(),
00111                       "%2d%2d%2d",
00112                       &timestr.tm_hour,
00113                       &timestr.tm_min,
00114                       &timestr.tm_sec) == 3)
00115         pos += 6;
00116       else {
00117         dateTimeLogger.msg(ERROR, "Can not parse time: %s", timestring);
00118         return;
00119       }
00120 
00121       // skip fraction of second
00122       if (timestring[pos] == '.') {
00123         pos++;
00124         while (isdigit(timestring[pos]))
00125           pos++;
00126       }
00127 
00128       if (timestring[pos] == 'Z') {
00129         pos++;
00130         gtime = timegm(&timestr);
00131       }
00132       else if (timestring[pos] == '+' || timestring[pos] == '-') {
00133         bool tzplus = (timestring[pos] == '+');
00134         pos++;
00135         int tzh, tzm;
00136         if (sscanf(timestring.substr(pos, 5).c_str(),
00137                    "%2d:%2d",
00138                    &tzh,
00139                    &tzm) == 2)
00140           pos += 5;
00141         else if (sscanf(timestring.substr(pos, 4).c_str(),
00142                         "%2d%2d",
00143                         &tzh,
00144                         &tzm) == 2)
00145           pos += 4;
00146         else {
00147           dateTimeLogger.msg(ERROR, "Can not parse time zone offset: %s",
00148                              timestring);
00149           return;
00150         }
00151 
00152         gtime = timegm(&timestr);
00153 
00154         if (gtime != -1) {
00155           if (tzplus)
00156             gtime -= tzh * 3600 + tzm * 60;
00157           else
00158             gtime += tzh * 3600 + tzm * 60;
00159         }
00160       }
00161       else {
00162         timestr.tm_isdst = -1;
00163         gtime = mktime(&timestr);
00164       }
00165 
00166       if (timestring.size() != pos) {
00167         dateTimeLogger.msg(ERROR, "Illegal time format: %s", timestring);
00168         return;
00169       }
00170     }
00171     else if (timestring.length() == 24) {
00172       // C time
00173       tm timestr;
00174       char day[4];
00175       char month[4];
00176 
00177       if (sscanf(timestring.c_str(),
00178                  "%3s %3s %2d %2d:%2d:%2d %4d",
00179                  day,
00180                  month,
00181                  &timestr.tm_mday,
00182                  &timestr.tm_hour,
00183                  &timestr.tm_min,
00184                  &timestr.tm_sec,
00185                  &timestr.tm_year) != 7) {
00186         dateTimeLogger.msg(ERROR, "Illegal time format: %s", timestring);
00187         return;
00188       }
00189 
00190       timestr.tm_year -= 1900;
00191 
00192       if (strncmp(month, "Jan", 3) == 0)
00193         timestr.tm_mon = 0;
00194       else if (strncmp(month, "Feb", 3) == 0)
00195         timestr.tm_mon = 1;
00196       else if (strncmp(month, "Mar", 3) == 0)
00197         timestr.tm_mon = 2;
00198       else if (strncmp(month, "Apr", 3) == 0)
00199         timestr.tm_mon = 3;
00200       else if (strncmp(month, "May", 3) == 0)
00201         timestr.tm_mon = 4;
00202       else if (strncmp(month, "Jun", 3) == 0)
00203         timestr.tm_mon = 5;
00204       else if (strncmp(month, "Jul", 3) == 0)
00205         timestr.tm_mon = 6;
00206       else if (strncmp(month, "Aug", 3) == 0)
00207         timestr.tm_mon = 7;
00208       else if (strncmp(month, "Sep", 3) == 0)
00209         timestr.tm_mon = 8;
00210       else if (strncmp(month, "Oct", 3) == 0)
00211         timestr.tm_mon = 9;
00212       else if (strncmp(month, "Nov", 3) == 0)
00213         timestr.tm_mon = 10;
00214       else if (strncmp(month, "Dec", 3) == 0)
00215         timestr.tm_mon = 11;
00216       else {
00217         dateTimeLogger.msg(ERROR, "Can not parse month: %s", month);
00218         return;
00219       }
00220 
00221       timestr.tm_isdst = -1;
00222       gtime = mktime(&timestr);
00223     }
00224     else if (timestring.length() == 29) {
00225       // RFC 1123 time (used by HTTP protoccol)
00226       tm timestr;
00227       char day[4];
00228       char month[4];
00229 
00230       if (sscanf(timestring.c_str(),
00231                  "%3s, %2d %3s %4d %2d:%2d:%2d GMT",
00232                  day,
00233                  &timestr.tm_mday,
00234                  month,
00235                  &timestr.tm_year,
00236                  &timestr.tm_hour,
00237                  &timestr.tm_min,
00238                  &timestr.tm_sec) != 7) {
00239         dateTimeLogger.msg(ERROR, "Illegal time format: %s", timestring);
00240         return;
00241       }
00242 
00243       timestr.tm_year -= 1900;
00244 
00245       if (strncmp(month, "Jan", 3) == 0)
00246         timestr.tm_mon = 0;
00247       else if (strncmp(month, "Feb", 3) == 0)
00248         timestr.tm_mon = 1;
00249       else if (strncmp(month, "Mar", 3) == 0)
00250         timestr.tm_mon = 2;
00251       else if (strncmp(month, "Apr", 3) == 0)
00252         timestr.tm_mon = 3;
00253       else if (strncmp(month, "May", 3) == 0)
00254         timestr.tm_mon = 4;
00255       else if (strncmp(month, "Jun", 3) == 0)
00256         timestr.tm_mon = 5;
00257       else if (strncmp(month, "Jul", 3) == 0)
00258         timestr.tm_mon = 6;
00259       else if (strncmp(month, "Aug", 3) == 0)
00260         timestr.tm_mon = 7;
00261       else if (strncmp(month, "Sep", 3) == 0)
00262         timestr.tm_mon = 8;
00263       else if (strncmp(month, "Oct", 3) == 0)
00264         timestr.tm_mon = 9;
00265       else if (strncmp(month, "Nov", 3) == 0)
00266         timestr.tm_mon = 10;
00267       else if (strncmp(month, "Dec", 3) == 0)
00268         timestr.tm_mon = 11;
00269       else {
00270         dateTimeLogger.msg(ERROR, "Can not parse month: %s", month);
00271         return;
00272       }
00273 
00274       gtime = timegm(&timestr);
00275     }
00276 
00277     if (gtime == -1)
00278       dateTimeLogger.msg(ERROR, "Illegal time format: %s", timestring);
00279   }
00280 
00281 
00282   void Time::SetTime(const time_t& time) {
00283     gtime = time;
00284   }
00285 
00286 
00287   time_t Time::GetTime() const {
00288     return gtime;
00289   }
00290 
00291 
00292   void Time::SetFormat(const TimeFormat& format) {
00293     time_format = format;
00294   }
00295 
00296 
00297   TimeFormat Time::GetFormat() {
00298     return time_format;
00299   }
00300 
00301 
00302   Time::operator std::string() const {
00303     return str();
00304   }
00305 
00306 
00307   std::string Time::str(const TimeFormat& format) const {
00308 
00309     const char *day[] = {
00310       "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
00311     };
00312     // C week starts on Sunday - just live with it...
00313     const char *month[] = {
00314       "Jan", "Feb", "Mar", "Apr", "May", "Jun",
00315       "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
00316     };
00317 
00318     switch (format) {
00319 
00320     case ASCTime:  // Day Mon DD HH:MM:SS YYYY
00321       {
00322         tm tmtime;
00323         localtime_r(&gtime, &tmtime);
00324 
00325         std::stringstream ss;
00326 
00327         ss << std::setfill('0');
00328 
00329         ss << day[tmtime.tm_wday] << ' '
00330            << month[tmtime.tm_mon] << ' '
00331            << std::setw(2) << tmtime.tm_mday << ' '
00332            << std::setw(2) << tmtime.tm_hour << ':'
00333            << std::setw(2) << tmtime.tm_min << ':'
00334            << std::setw(2) << tmtime.tm_sec << ' '
00335            << std::setw(4) << tmtime.tm_year + 1900;
00336 
00337         return ss.str();
00338       }
00339 
00340     case UserTime:
00341       {
00342         tm tmtime;
00343         localtime_r(&gtime, &tmtime);
00344 
00345         std::stringstream ss;
00346 
00347         ss << std::setfill('0');
00348 
00349         ss << std::setw(4) << tmtime.tm_year + 1900 << '-'
00350            << std::setw(2) << tmtime.tm_mon + 1 << '-'
00351            << std::setw(2) << tmtime.tm_mday << ' '
00352            << std::setw(2) << tmtime.tm_hour << ':'
00353            << std::setw(2) << tmtime.tm_min << ':'
00354            << std::setw(2) << tmtime.tm_sec;
00355 
00356         return ss.str();
00357       }
00358 
00359     case MDSTime:
00360       {
00361         tm tmtime;
00362         gmtime_r(&gtime, &tmtime);
00363 
00364         std::stringstream ss;
00365 
00366         ss << std::setfill('0');
00367 
00368         ss << std::setw(4) << tmtime.tm_year + 1900
00369            << std::setw(2) << tmtime.tm_mon + 1
00370            << std::setw(2) << tmtime.tm_mday
00371            << std::setw(2) << tmtime.tm_hour
00372            << std::setw(2) << tmtime.tm_min
00373            << std::setw(2) << tmtime.tm_sec << 'Z';
00374 
00375         return ss.str();
00376       }
00377 
00378     case ISOTime:
00379       {
00380         tm tmtime;
00381         localtime_r(&gtime, &tmtime);
00382         time_t tzoffset = timegm(&tmtime) - gtime;
00383 
00384         std::stringstream ss;
00385 
00386         ss << std::setfill('0');
00387 
00388         ss << std::setw(4) << tmtime.tm_year + 1900 << '-'
00389            << std::setw(2) << tmtime.tm_mon + 1 << '-'
00390            << std::setw(2) << tmtime.tm_mday << 'T'
00391            << std::setw(2) << tmtime.tm_hour << ':'
00392            << std::setw(2) << tmtime.tm_min << ':'
00393            << std::setw(2) << tmtime.tm_sec << (tzoffset < 0 ? '-' : '+')
00394            << std::setw(2) << abs(tzoffset) / Time::HOUR << ':'
00395            << std::setw(2) << (abs(tzoffset) % Time::HOUR) / 60;
00396 
00397         return ss.str();
00398       }
00399 
00400     case UTCTime:
00401       {
00402         tm tmtime;
00403         gmtime_r(&gtime, &tmtime);
00404 
00405         std::stringstream ss;
00406 
00407         ss << std::setfill('0');
00408 
00409         ss << std::setw(4) << tmtime.tm_year + 1900 << '-'
00410            << std::setw(2) << tmtime.tm_mon + 1 << '-'
00411            << std::setw(2) << tmtime.tm_mday << 'T'
00412            << std::setw(2) << tmtime.tm_hour << ':'
00413            << std::setw(2) << tmtime.tm_min << ':'
00414            << std::setw(2) << tmtime.tm_sec << 'Z';
00415 
00416         return ss.str();
00417       }
00418 
00419     case RFC1123Time:
00420       {
00421         tm tmtime;
00422         gmtime_r(&gtime, &tmtime);
00423 
00424         std::stringstream ss;
00425 
00426         ss << std::setfill('0');
00427 
00428         ss << day[tmtime.tm_wday] << ", "
00429            << std::setw(2) << tmtime.tm_mday << ' '
00430            << month[tmtime.tm_mon] << ' '
00431            << std::setw(4) << tmtime.tm_year + 1900 << ' '
00432            << std::setw(2) << tmtime.tm_hour << ':'
00433            << std::setw(2) << tmtime.tm_min << ':'
00434            << std::setw(2) << tmtime.tm_sec << " GMT";
00435 
00436         return ss.str();
00437       }
00438 
00439     }
00440     return "";
00441   }
00442 
00443 
00444   bool Time::operator<(const Time& othertime) const {
00445     return gtime < othertime.GetTime();
00446   }
00447 
00448 
00449   bool Time::operator>(const Time& othertime) const {
00450     return gtime > othertime.GetTime();
00451   }
00452 
00453 
00454   bool Time::operator<=(const Time& othertime) const {
00455     return gtime <= othertime.GetTime();
00456   }
00457 
00458 
00459   bool Time::operator>=(const Time& othertime) const {
00460     return gtime >= othertime.GetTime();
00461   }
00462 
00463 
00464   bool Time::operator==(const Time& othertime) const {
00465     return gtime == othertime.GetTime();
00466   }
00467 
00468 
00469   bool Time::operator!=(const Time& othertime) const {
00470     return gtime != othertime.GetTime();
00471   }
00472 
00473   Time Time::operator+(const Period& duration) const {
00474     time_t t;
00475     t = gtime + duration.GetPeriod();
00476     return (Time(t));
00477   }
00478 
00479   Time Time::operator-(const Period& duration) const {
00480     time_t t;
00481     t = gtime - duration.GetPeriod();
00482     return (Time(t));
00483   }
00484 
00485   Period Time::operator-(const Time& other) const {
00486     time_t t;
00487     t = gtime - other.GetTime();
00488     return (Period(t));
00489   }
00490 
00491   Time& Time::operator=(const time_t& newtime) {
00492     gtime = newtime;
00493     return *this;
00494   }
00495 
00496   Time& Time::operator=(const Time& newtime) {
00497     gtime = newtime.GetTime();
00498     return *this;
00499   }
00500 
00501   Time& Time::operator=(const char* newtime) {
00502     return operator=(std::string(newtime));
00503   }
00504 
00505   Time& Time::operator=(const std::string& newtime) {
00506     return *this = Arc::Time(newtime);
00507   }
00508 
00509   std::ostream& operator<<(std::ostream& out, const Time& time) {
00510     return (out << time.str());
00511   }
00512 
00513 
00514   std::string TimeStamp(const TimeFormat& format) {
00515     Time now;
00516     return now.str(format);
00517   }
00518 
00519 
00520   std::string TimeStamp(Time newtime, const TimeFormat& format) {
00521     return newtime.str(format);
00522   }
00523 
00524 
00525   Period::Period()
00526     : seconds(0) {}
00527 
00528 
00529   Period::Period(const time_t& length)
00530     : seconds(length) {}
00531 
00532 
00533   Period::Period(const std::string& period, PeriodBase base)
00534     : seconds(0) {
00535 
00536     if (period.empty()) {
00537       dateTimeLogger.msg(ERROR, "Empty string");
00538       return;
00539     }
00540 
00541     if (period[0] == 'P') {
00542       // ISO duration
00543       std::string::size_type pos = 1;
00544       bool min = false; // months or minutes?
00545       while (pos < period.size()) {
00546         if (period[pos] == 'T')
00547           min = true;
00548         else {
00549           std::string::size_type pos2 = pos;
00550           while (pos2 < period.size() && isdigit(period[pos2]))
00551             pos2++;
00552           if (pos2 == pos || pos2 == period.size()) {
00553             dateTimeLogger.msg(ERROR, "Invalid ISO duration format: %s",
00554                                period);
00555             seconds = 0;
00556             return;
00557           }
00558           int num = stringtoi(period.substr(pos, pos2 - pos));
00559           pos = pos2;
00560           switch (period[pos]) {
00561           case 'Y':
00562             seconds += num * Time::YEAR;
00563             break;
00564 
00565           case 'W':
00566             seconds += num * Time::WEEK;
00567             min = true;
00568             break;
00569 
00570           case 'D':
00571             seconds += num * Time::DAY;
00572             min = true;
00573             break;
00574 
00575           case 'H':
00576             seconds += num * Time::HOUR;
00577             min = true;
00578             break;
00579 
00580           case 'M':
00581             if (min)
00582               seconds += num * 60;
00583             else {
00584               seconds += num * Time::MONTH;
00585               min = true;
00586             }
00587             break;
00588 
00589           case 'S':
00590             seconds += num;
00591             break;
00592 
00593           default:
00594             dateTimeLogger.msg(ERROR, "Invalid ISO duration format: %s",
00595                                period);
00596             seconds = 0;
00597             return;
00598             break;
00599           }
00600         }
00601         pos++;
00602       }
00603     }
00604     else {
00605       // "free" format
00606       std::string::size_type pos = std::string::npos;
00607       int len = 0;
00608 
00609       for (std::string::size_type i = 0; i != period.length(); i++) {
00610         if (isdigit(period[i])) {
00611           if (pos == std::string::npos) {
00612             pos = i;
00613             len = 0;
00614           }
00615           len++;
00616         }
00617         else if (pos != std::string::npos) {
00618           switch (period[i]) {
00619           case 'w':
00620           case 'W':
00621             seconds += stringtoi(period.substr(pos, len)) * Time::WEEK;
00622             pos = std::string::npos;
00623             base = PeriodDays;
00624             break;
00625 
00626           case 'd':
00627           case 'D':
00628             seconds += stringtoi(period.substr(pos, len)) * Time::DAY;
00629             pos = std::string::npos;
00630             base = PeriodHours;
00631             break;
00632 
00633           case 'h':
00634           case 'H':
00635             seconds += stringtoi(period.substr(pos, len)) * Time::HOUR;
00636             pos = std::string::npos;
00637             base = PeriodMinutes;
00638             break;
00639 
00640           case 'm':
00641           case 'M':
00642             seconds += stringtoi(period.substr(pos, len)) * 60;
00643             pos = std::string::npos;
00644             base = PeriodSeconds;
00645             break;
00646 
00647           case 's':
00648           case 'S':
00649             seconds += stringtoi(period.substr(pos, len));
00650             pos = std::string::npos;
00651             base = PeriodMiliseconds;
00652             break;
00653 
00654           case ' ':
00655             break;
00656 
00657           default:
00658             dateTimeLogger.msg(ERROR, "Invalid period string: %s", period);
00659             seconds = 0;
00660             return;
00661             break;
00662           }
00663         }
00664       }
00665 
00666       if (pos != std::string::npos) {
00667         int n = stringtoi(period.substr(pos, len));
00668         switch (base) {
00669         case PeriodMiliseconds:
00670           n /= 1000;
00671           break;
00672 
00673         case PeriodSeconds:
00674           break;
00675 
00676         case PeriodMinutes:
00677           n *= 60;
00678           break;
00679 
00680         case PeriodHours:
00681           n *= Time::HOUR;
00682           break;
00683 
00684         case PeriodDays:
00685           n *= Time::DAY;
00686           break;
00687 
00688         case PeriodWeeks:
00689           n *= Time::WEEK;
00690           break;
00691         }
00692         seconds += n;
00693       }
00694     }
00695   }
00696 
00697 
00698   Period& Period::operator=(const time_t& length) {
00699     seconds = length;
00700     return *this;
00701   }
00702 
00703   Period& Period::operator=(const Period& newperiod) {
00704     seconds = newperiod.GetPeriod();
00705     return *this;
00706   }
00707 
00708   void Period::SetPeriod(const time_t& length) {
00709     seconds = length;
00710   }
00711 
00712 
00713   time_t Period::GetPeriod() const {
00714     return seconds;
00715   }
00716 
00717   const sigc::slot<const char*>* Period::istr() const {
00718     const_cast<Period*>(this)->slot = sigc::mem_fun(this, &Arc::Period::IStr);
00719     return &slot;
00720   }
00721 
00722   const char* Period::IStr() const {
00723 
00724     time_t remain = seconds;
00725 
00726     std::stringstream ss;
00727 
00728     if (remain >= Time::YEAR) {
00729       ss << remain / Time::YEAR << " "
00730          << FindNTrans("year", "years", remain / Time::YEAR);
00731       remain %= Time::YEAR;
00732     }
00733     if (remain >= Time::MONTH) {
00734       if (remain != seconds) ss << " ";
00735       ss << remain / Time::MONTH << " "
00736          << FindNTrans("month", "months", remain / Time::MONTH);
00737       remain %= Time::MONTH;
00738     }
00739     if (remain >= Time::DAY) {
00740       if (remain != seconds) ss << " ";
00741       ss << remain / Time::DAY << " "
00742          << FindNTrans("day", "days", remain / Time::DAY);
00743       remain %= Time::DAY;
00744     }
00745     if (remain >= Time::HOUR) {
00746       if (remain != seconds) ss << " ";
00747       ss << remain / Time::HOUR << " "
00748          << FindNTrans("hour", "hours", remain / Time::HOUR);
00749       remain %= Time::HOUR;
00750     }
00751     if (remain >= 60) {
00752       if (remain != seconds) ss << " ";
00753       ss << remain / 60 << " "
00754          << FindNTrans("minute", "minutes", remain / 60);
00755       remain %= 60;
00756     }
00757     if (remain >= 1) {
00758       if (remain != seconds) ss << " ";
00759       ss << remain << " "
00760          << FindNTrans("second", "seconds", remain);
00761     }
00762 
00763     const_cast<Period*>(this)->is = ss.str();
00764     return is.c_str();
00765   }
00766 
00767   Period::operator std::string() const {
00768     time_t remain = seconds;
00769 
00770     std::stringstream ss;
00771 
00772     ss << 'P';
00773     if (remain >= Time::YEAR) {
00774       ss << remain / Time::YEAR << 'Y';
00775       remain %= Time::YEAR;
00776     }
00777     if (remain >= Time::MONTH) {
00778       ss << remain / Time::MONTH << 'M';
00779       remain %= Time::MONTH;
00780     }
00781     if (remain >= Time::DAY) {
00782       ss << remain / Time::DAY << 'D';
00783       remain %= Time::DAY;
00784     }
00785     if (remain)
00786       ss << 'T';
00787     if (remain >= Time::HOUR) {
00788       ss << remain / Time::HOUR << 'H';
00789       remain %= Time::HOUR;
00790     }
00791     if (remain >= 60) {
00792       ss << remain / 60 << 'M';
00793       remain %= 60;
00794     }
00795     if (remain >= 1)
00796       ss << remain << 'S';
00797 
00798     return ss.str();
00799   }
00800 
00801 
00802   bool Period::operator<(const Period& othertime) const {
00803     return seconds < othertime.GetPeriod();
00804   }
00805 
00806 
00807   bool Period::operator>(const Period& othertime) const {
00808     return seconds > othertime.GetPeriod();
00809   }
00810 
00811 
00812   bool Period::operator<=(const Period& othertime) const {
00813     return seconds <= othertime.GetPeriod();
00814   }
00815 
00816 
00817   bool Period::operator>=(const Period& othertime) const {
00818     return seconds >= othertime.GetPeriod();
00819   }
00820 
00821 
00822   bool Period::operator==(const Period& othertime) const {
00823     return seconds == othertime.GetPeriod();
00824   }
00825 
00826 
00827   bool Period::operator!=(const Period& othertime) const {
00828     return seconds != othertime.GetPeriod();
00829   }
00830 
00831 
00832   std::ostream& operator<<(std::ostream& out, const Period& period) {
00833     return (out << (std::string)period);
00834   }
00835 
00836 } // namespace Arc