ptime.cxx
上传用户:hzhsqp
上传日期:2007-01-06
资源大小:1600k
文件大小:18k
源码类别:

IP电话/视频会议

开发平台:

Visual C++

  1. /*
  2.  * ptime.cxx
  3.  *
  4.  * Time and date classes.
  5.  *
  6.  * Portable Windows Library
  7.  *
  8.  * Copyright (c) 1993-1998 Equivalence Pty. Ltd.
  9.  *
  10.  * The contents of this file are subject to the Mozilla Public License
  11.  * Version 1.0 (the "License"); you may not use this file except in
  12.  * compliance with the License. You may obtain a copy of the License at
  13.  * http://www.mozilla.org/MPL/
  14.  *
  15.  * Software distributed under the License is distributed on an "AS IS"
  16.  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  17.  * the License for the specific language governing rights and limitations
  18.  * under the License.
  19.  *
  20.  * The Original Code is Portable Windows Library.
  21.  *
  22.  * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
  23.  *
  24.  * Portions are Copyright (C) 1993 Free Software Foundation, Inc.
  25.  * All Rights Reserved.
  26.  *
  27.  * Contributor(s): ______________________________________.
  28.  *
  29.  * $Log: ptime.cxx,v $
  30.  * Revision 1.35  2000/04/29 08:11:06  robertj
  31.  * Fixed problem with stream output width in PTimeInterval
  32.  *
  33.  * Revision 1.34  2000/04/29 04:50:16  robertj
  34.  * Added microseconds to string output.
  35.  * Fixed uninitialised microseconds on some constructors.
  36.  *
  37.  * Revision 1.33  2000/04/28 13:23:25  robertj
  38.  * Fixed printing of negative time intervals.
  39.  *
  40.  * Revision 1.32  2000/04/18 06:01:01  robertj
  41.  * Fixed integer overflow bug in PTime addition functions, thanks Ian MacDonald
  42.  *
  43.  * Revision 1.31  2000/04/05 02:50:17  robertj
  44.  * Added microseconds to PTime class.
  45.  *
  46.  * Revision 1.30  2000/03/08 17:56:33  rogerh
  47.  * Fix error in creation of a PStringStream from a PString
  48.  *
  49.  * Revision 1.29  2000/03/06 04:09:23  robertj
  50.  * Added constructor to do PString conversion to PTimeInterval
  51.  *
  52.  * Revision 1.28  1999/10/14 08:23:20  robertj
  53.  * Fixed display of decimals in milliseconds when precision other than 3.
  54.  *
  55.  * Revision 1.27  1999/08/08 12:39:24  robertj
  56.  * Fixed bug in display of PTimeIntervals larger than 24 hours.
  57.  *
  58.  * Revision 1.26  1999/06/14 07:58:39  robertj
  59.  * Fixed bug in PTimeInteerval output, left stream fill char as '0'.
  60.  * Added ability to set the width of the PTimeInterval stream output.
  61.  *
  62.  * Revision 1.25  1999/03/29 03:38:58  robertj
  63.  * Improved time & date parser.
  64.  *
  65.  * Revision 1.24  1998/11/30 12:31:46  robertj
  66.  * Removed redundent conditionals.
  67.  *
  68.  * Revision 1.23  1998/11/14 01:11:45  robertj
  69.  * PPC linux GNU compatibility.
  70.  *
  71.  * Revision 1.22  1998/09/23 06:22:36  robertj
  72.  * Added open source copyright license.
  73.  *
  74.  * Revision 1.21  1998/03/05 12:49:53  robertj
  75.  * MemCheck fixes.
  76.  *
  77.  * Revision 1.20  1998/01/26 00:48:30  robertj
  78.  * Removed days from PTimeInterval PrintOn(), can get it back by using negative precision.
  79.  * Fixed Y2K problem in parsing dates.
  80.  *
  81.  * Revision 1.19  1998/01/04 07:24:32  robertj
  82.  * Added operating system specific versions of gmtime and localtime.
  83.  *
  84.  * Revision 1.18  1997/07/08 13:05:21  robertj
  85.  * Fixed bug in parsing time zone incorrectly.
  86.  *
  87.  * Revision 1.17  1997/05/16 12:05:57  robertj
  88.  * Changed PTimeInterval to guarentee no overflow in millisecond calculations.
  89.  *
  90.  * Revision 1.16  1997/03/18 21:24:19  robertj
  91.  * Fixed parsing of time putting back token after time zone.
  92.  *
  93.  * Revision 1.15  1997/01/03 04:40:03  robertj
  94.  * Changed default time so if no year goes to last 12 months rather than current year.
  95.  *
  96.  * Revision 1.14  1996/10/26 01:40:12  robertj
  97.  * Fixed bug in time parser that caused endless looping.
  98.  *
  99.  * Revision 1.13  1996/08/20 12:07:29  robertj
  100.  * Fixed volatile milliseconds member of PTimeInterval for printing.
  101.  *
  102.  * Revision 1.12  1996/07/27 04:11:28  robertj
  103.  * Added bullet proofing for invlid times - especially in Western time zones.
  104.  *
  105.  * Revision 1.11  1996/07/15 12:43:01  robertj
  106.  * Fixed MSVC 4.1 compiler bug.
  107.  *
  108.  * Revision 1.10  1996/06/17 11:34:48  robertj
  109.  * Fixed bug in NOT localising RFC1123 time.
  110.  *
  111.  * Revision 1.9  1996/05/09 12:18:16  robertj
  112.  * Fixed syntax error found by Mac platform.
  113.  * Resolved C++ problems with 64 bit PTimeInterval for Mac platform.
  114.  *
  115.  * Revision 1.8  1996/03/17 05:43:42  robertj
  116.  * Changed PTimeInterval to 64 bit integer.
  117.  *
  118.  * Revision 1.7  1996/03/05 14:09:20  robertj
  119.  * Fixed bugs in PTimerInterval stream output.
  120.  *
  121.  * Revision 1.6  1996/03/04 12:21:42  robertj
  122.  * Fixed output of leading zeros in PTimeInterval stream output.
  123.  *
  124.  * Revision 1.5  1996/02/25 11:22:13  robertj
  125.  * Added check for precision field in stream when outputting time interval..
  126.  *
  127.  * Revision 1.4  1996/02/25 03:07:47  robertj
  128.  * Changed PrintOn and ReadFrom on PTimeInterval to use dd:hh:mm:ss.mmm format.
  129.  *
  130.  * Revision 1.3  1996/02/15 14:47:35  robertj
  131.  * Fixed bugs in time zone compensation (some in the C library).
  132.  *
  133.  * Revision 1.2  1996/02/13 12:59:32  robertj
  134.  * Changed GetTimeZone() so can specify standard/daylight time.
  135.  * Split PTime into separate module after major change to ReadFrom().
  136.  *
  137.  * Revision 1.1  1996/02/13 10:11:52  robertj
  138.  * Initial revision
  139.  *
  140.  */
  141. #include <ptlib.h>
  142. #include <ctype.h>
  143. ///////////////////////////////////////////////////////////////////////////////
  144. // PTimeInterval
  145. PTimeInterval::PTimeInterval(long millisecs,
  146.                              long seconds,
  147.                              long minutes,
  148.                              long hours,
  149.                              int days)
  150. {
  151.   SetInterval(millisecs, seconds, minutes, hours, days);
  152. }
  153. PTimeInterval::PTimeInterval(const PString & str)
  154. {
  155.   PStringStream strm(str);
  156.   ReadFrom(strm);
  157. }
  158. PObject::Comparison PTimeInterval::Compare(const PObject & obj) const
  159. {
  160.   PAssert(obj.IsDescendant(PTimeInterval::Class()), PInvalidCast);
  161.   const PTimeInterval & other = (const PTimeInterval &)obj;
  162.   return milliseconds < other.milliseconds ? LessThan :
  163.          milliseconds > other.milliseconds ? GreaterThan : EqualTo;
  164. }
  165. void PTimeInterval::PrintOn(ostream & stream) const
  166. {
  167.   int width = stream.width();
  168.   int precision = stream.precision();
  169.   if (precision > 3)
  170.     precision = 3;
  171.   BOOL hadPrevious = FALSE;
  172.   long tmp;
  173.   PStringStream str;
  174.   str.fill('0');
  175.   PInt64 ms = milliseconds;
  176.   if (ms < 0) {
  177.     str << '-';
  178.     ms = -ms;
  179.   }
  180.   if (precision < 0) {
  181.     precision = -precision;
  182.     if (precision > 3)
  183.       precision = 3;
  184.     tmp = (long)(ms/86400000);
  185.     if (tmp > 0 || width > (precision+10)) {
  186.       str << tmp << 'd';
  187.       hadPrevious = TRUE;
  188.     }
  189.     tmp = (long)(ms%86400000)/3600000;
  190.   }
  191.   else
  192.     tmp = (long)(ms/3600000);
  193.   if (hadPrevious || tmp > 0 || width > (precision+7)) {
  194.     if (hadPrevious)
  195.       str.width(2);
  196.     str << tmp << ':';
  197.     hadPrevious = TRUE;
  198.   }
  199.   tmp = (long)(ms%3600000)/60000;
  200.   if (hadPrevious || tmp > 0 || width > (precision+4)) {
  201.     if (hadPrevious)
  202.       str.width(2);
  203.     str << tmp << ':';
  204.     hadPrevious = TRUE;
  205.   }
  206.   if (hadPrevious)
  207.     str.width(2);
  208.   str << (long)(ms%60000)/1000;
  209.   switch (precision) {
  210.     case 1 :
  211.       str << '.' << (int)(ms%1000)/100;
  212.       break;
  213.     case 2 :
  214.       str << '.' << setw(2) << (int)(ms%1000)/10;
  215.       break;
  216.     case 3 :
  217.       str << '.' << setw(3) << (int)(ms%1000);
  218.     default :
  219.       break;
  220.   }
  221.   stream << str;
  222. }
  223. void PTimeInterval::ReadFrom(istream &strm)
  224. {
  225.   long day = 0;
  226.   long hour = 0;
  227.   long min = 0;
  228.   float sec;
  229.   strm >> sec;
  230.   while (strm.peek() == ':') {
  231.     day = hour;
  232.     hour = min;
  233.     min = (long)sec;
  234.     strm.get();
  235.     strm >> sec;
  236.   }
  237.   SetInterval(((long)(sec*1000))%1000, (int)sec, min, hour, day);
  238. }
  239. void PTimeInterval::SetInterval(PInt64 millisecs,
  240.                                 long seconds,
  241.                                 long minutes,
  242.                                 long hours,
  243.                                 int days)
  244. {
  245.   milliseconds = days;
  246.   milliseconds *= 24;
  247.   milliseconds += hours;
  248.   milliseconds *= 60;
  249.   milliseconds += minutes;
  250.   milliseconds *= 60;
  251.   milliseconds += seconds;
  252.   milliseconds *= 1000;
  253.   milliseconds += millisecs;
  254. }
  255. ///////////////////////////////////////////////////////////////////////////////
  256. // PTime
  257. static time_t p_mktime(struct tm * t, int zone)
  258. {
  259.   // mktime returns GMT, calculated using input_time - timezone. However, this
  260.   // assumes that the input time was a local time. If the input time wasn't a
  261.   // local time, then we have have to add the local timezone (without daylight
  262.   // savings) and subtract the specified zone offset to get GMT
  263.   // and then subtract
  264.   t->tm_isdst = PTime::IsDaylightSavings() ? 1 : 0;
  265.   time_t theTime = mktime(t);
  266.   if (theTime == (time_t)-1)
  267.     theTime = 0;
  268.   else if (zone != PTime::Local) {
  269.     theTime += PTime::GetTimeZone()*60;  // convert to local time
  270.     if (theTime > zone*60)
  271.       theTime -= zone*60;           // and then to GMT
  272.   }
  273.   return theTime;
  274. }
  275. PTime::PTime(const PString & str)
  276. {
  277.   PStringStream s(str);
  278.   ReadFrom(s);
  279. }
  280. PTime::PTime(int second, int minute, int hour,
  281.              int day,    int month,  int year,
  282.              int zone)
  283. {
  284.   microseconds = 0;
  285.   struct tm t;
  286.   PAssert(second >= 0 && second <= 59, PInvalidParameter);
  287.   t.tm_sec = second;
  288.   PAssert(minute >= 0 && minute <= 59, PInvalidParameter);
  289.   t.tm_min = minute;
  290.   PAssert(hour >= 0 && hour <= 23, PInvalidParameter);
  291.   t.tm_hour = hour;
  292.   PAssert(day >= 1 && day <= 31, PInvalidParameter);
  293.   t.tm_mday = day;
  294.   PAssert(month >= 1 && month <= 12, PInvalidParameter);
  295.   t.tm_mon = month-1;
  296.   PAssert(year >= 1970 && year <= 2038, PInvalidParameter);
  297.   t.tm_year   = year-1900;
  298.   theTime = p_mktime(&t, zone);
  299. }
  300. PObject::Comparison PTime::Compare(const PObject & obj) const
  301. {
  302.   PAssert(obj.IsDescendant(PTime::Class()), PInvalidCast);
  303.   const PTime & other = (const PTime &)obj;
  304.   if (theTime < other.theTime)
  305.     return LessThan;
  306.   if (theTime > other.theTime)
  307.     return GreaterThan;
  308.   if (microseconds < other.microseconds)
  309.     return LessThan;
  310.   if (microseconds > other.microseconds)
  311.     return GreaterThan;
  312.   return EqualTo;
  313. }
  314. PString PTime::AsString(TimeFormat format, int zone) const
  315. {
  316.   if (format == RFC1123)
  317.     return AsString("wwwe, dd MMME yyyy hh:mm:ss z", zone);
  318.   PString fmt, dsep;
  319.   PString tsep = GetTimeSeparator();
  320.   BOOL is12hour = GetTimeAMPM();
  321.   switch (format & 7) {
  322.     case LongDateTime :
  323.     case LongTime :
  324.     case MediumDateTime :
  325.     case ShortDateTime :
  326.     case ShortTime :
  327.       if (!is12hour)
  328.         fmt = "h";
  329.       fmt += "h" + tsep + "mm";
  330.       switch (format) {
  331.         case LongDateTime :
  332.         case LongTime :
  333.           fmt += tsep + "ss";
  334.         default :
  335.           break;
  336.       }
  337.       if (is12hour)
  338.         fmt += "a";
  339.       break;
  340.     default :
  341.       break;
  342.   }
  343.   switch (format & 7) {
  344.     case LongDateTime :
  345.     case MediumDateTime :
  346.     case ShortDateTime :
  347.       fmt += ' ';
  348.       break;
  349.     default :
  350.       break;
  351.   }
  352.   switch (format & 7) {
  353.     case LongDateTime :
  354.     case LongDate :
  355.       fmt += "wwww ";
  356.       switch (GetDateOrder()) {
  357.         case MonthDayYear :
  358.           fmt += "MMMM d, yyyy";
  359.           break;
  360.         case DayMonthYear :
  361.           fmt += "d MMMM yyyy";
  362.           break;
  363.         case YearMonthDay :
  364.           fmt += "yyyy MMMM d";
  365.       }
  366.       break;
  367.     case MediumDateTime :
  368.     case MediumDate :
  369.       fmt += "www ";
  370.       switch (GetDateOrder()) {
  371.         case MonthDayYear :
  372.           fmt += "MMM d, yy";
  373.           break;
  374.         case DayMonthYear :
  375.           fmt += "d MMM yy";
  376.           break;
  377.         case YearMonthDay :
  378.           fmt += "yy MMM d";
  379.       }
  380.       break;
  381.     case ShortDateTime :
  382.     case ShortDate :
  383.       dsep = GetDateSeparator();
  384.       switch (GetDateOrder()) {
  385.         case MonthDayYear :
  386.           fmt += "MM" + dsep + "dd" + dsep + "yy";
  387.           break;
  388.         case DayMonthYear :
  389.           fmt += "dd" + dsep + "MM" + dsep + "yy";
  390.           break;
  391.         case YearMonthDay :
  392.           fmt += "yy" + dsep + "MM" + dsep + "dd";
  393.       }
  394.       break;
  395.     default :
  396.       break;
  397.   }
  398.   if (zone != Local)
  399.     fmt += " z";
  400.   return AsString(fmt, zone);
  401. }
  402. PString PTime::AsString(const char * format, int zone) const
  403. {
  404.   PAssert(format != NULL, PInvalidParameter);
  405.   BOOL is12hour = strchr(format, 'a') != NULL;
  406.   PStringStream str;
  407.   str.fill('0');
  408.   // the localtime call automatically adjusts for daylight savings time
  409.   // so take this into account when converting non-local times
  410.   if (zone == Local)
  411.     zone = GetTimeZone();  // includes daylight savings time
  412.   time_t realTime = theTime + zone*60;     // to correct timezone
  413.   struct tm ts;
  414.   struct tm * t = os_gmtime(&realTime, &ts);
  415.   PINDEX repeatCount;
  416.   while (*format != '') {
  417.     repeatCount = 1;
  418.     switch (*format) {
  419.       case 'a' :
  420.         while (*++format == 'a')
  421.           ;
  422.         if (t->tm_hour < 12)
  423.           str << GetTimeAM();
  424.         else
  425.           str << GetTimePM();
  426.         break;
  427.       case 'h' :
  428.         while (*++format == 'h')
  429.           repeatCount++;
  430.         str << setw(repeatCount) << (is12hour ? (t->tm_hour+11)%12+1 : t->tm_hour);
  431.         break;
  432.       case 'm' :
  433.         while (*++format == 'm')
  434.           repeatCount++;
  435.         str << setw(repeatCount) << t->tm_min;
  436.         break;
  437.       case 's' :
  438.         while (*++format == 's')
  439.           repeatCount++;
  440.         str << setw(repeatCount) << t->tm_sec;
  441.         break;
  442.       case 'w' :
  443.         while (*++format == 'w')
  444.           repeatCount++;
  445.         if (repeatCount != 3 || *format != 'e')
  446.           str << GetDayName((Weekdays)t->tm_wday, repeatCount <= 3 ? Abbreviated : FullName);
  447.         else {
  448.           static const char * const EnglishDayName[] = {
  449.             "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
  450.           };
  451.           str << EnglishDayName[t->tm_wday];
  452.           format++;
  453.         }
  454.         break;
  455.       case 'M' :
  456.         while (*++format == 'M')
  457.           repeatCount++;
  458.         if (repeatCount < 3)
  459.           str << setw(repeatCount) << (t->tm_mon+1);
  460.         else if (repeatCount > 3 || *format != 'E')
  461.           str << GetMonthName((Months)(t->tm_mon+1),
  462.                                     repeatCount == 3 ? Abbreviated : FullName);
  463.         else {
  464.           static const char * const EnglishMonthName[] = {
  465.             "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  466.             "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
  467.           };
  468.           str << EnglishMonthName[t->tm_mon];
  469.           format++;
  470.         }
  471.         break;
  472.       case 'd' :
  473.         while (*++format == 'd')
  474.           repeatCount++;
  475.         str << setw(repeatCount) << t->tm_mday;
  476.         break;
  477.       case 'y' :
  478.         while (*++format == 'y')
  479.           repeatCount++;
  480.         if (repeatCount < 3)
  481.           str << setw(2) << (t->tm_year%100);
  482.         else
  483.           str << setw(4) << (t->tm_year+1900);
  484.         break;
  485.       case 'z' :
  486.         while (*++format == 'z')
  487.           ;
  488.         if (zone == 0)
  489.           str << "GMT";
  490.         else {
  491.           str << (zone < 0 ? '-' : '+');
  492.           zone = PABS(zone);
  493.           str << setw(2) << (zone/60) << setw(2) << (zone%60);
  494.         }
  495.         break;
  496.       case 'u' :
  497.         while (*++format == 'u')
  498.           repeatCount++;
  499.         switch (repeatCount) {
  500.           case 1 :
  501.             str << ((microseconds+50000)/100000);
  502.             break;
  503.           case 2 :
  504.             str << setw(2) << ((microseconds+5000)/10000);
  505.             break;
  506.           case 3 :
  507.             str << setw(3) << ((microseconds+500)/1000);
  508.             break;
  509.           default :
  510.             str << setw(6) << microseconds;
  511.             break;
  512.         }
  513.         break;
  514.       default :
  515.         str << *format++;
  516.     }
  517.   }
  518.   return str;
  519. }
  520. ///////////////////////////////////////////////////////////
  521. //
  522. //  Time parser
  523. //
  524. extern "C" {
  525. #ifndef STDAPICALLTYPE
  526. #define STDAPICALLTYPE
  527. #endif
  528. time_t STDAPICALLTYPE PTimeParse(void *, struct tm *, int);
  529. int STDAPICALLTYPE PTimeGetChar(void * stream)
  530. {
  531.   return ((istream *)stream)->get();
  532. }
  533. void STDAPICALLTYPE PTimeUngetChar(void * stream, int c)
  534. {
  535.   ((istream *)stream)->putback((char)c);
  536. }
  537. int STDAPICALLTYPE PTimeGetDateOrder()
  538. {
  539.   return PTime::GetDateOrder();
  540. }
  541. int STDAPICALLTYPE PTimeIsMonthName(const char * str, int month, int abbrev)
  542. {
  543.   return PTime::GetMonthName((PTime::Months)month,
  544.                              abbrev ? PTime::Abbreviated : PTime::FullName) *= str;
  545. }
  546. int STDAPICALLTYPE PTimeIsDayName(const char * str, int day, int abbrev)
  547. {
  548.   return PTime::GetDayName((PTime::Weekdays)day,
  549.                              abbrev ? PTime::Abbreviated : PTime::FullName) *= str;
  550. }
  551. };
  552. void PTime::ReadFrom(istream & strm)
  553. {
  554.   time_t now;
  555.   struct tm timeBuf;
  556.   time(&now);
  557.   microseconds = 0;
  558.   theTime = PTimeParse(&strm, os_localtime(&now, &timeBuf), GetTimeZone());
  559. }
  560. PTime PTime::operator+(const PTimeInterval & t) const
  561. {
  562.   PInt64 msecs = (PInt64)theTime*1000 + t.GetMilliSeconds();
  563.   return PTime((time_t)(msecs/1000), (long)(msecs%1000)*1000);
  564. }
  565. PTime & PTime::operator+=(const PTimeInterval & t)
  566. {
  567.   PInt64 msecs = (PInt64)theTime*1000 + t.GetMilliSeconds();
  568.   theTime = (time_t)(msecs/1000);
  569.   microseconds = (long)(msecs%1000)*1000;
  570.   return *this;
  571. }
  572. PTimeInterval PTime::operator-(const PTime & t) const
  573. {
  574.   time_t secs = theTime - t.theTime;
  575.   long usecs = microseconds - t.microseconds;
  576.   if (usecs < 0) {
  577.     usecs += 1000000;
  578.     secs--;
  579.   }
  580.   else if (usecs >= 1000000) {
  581.     usecs -= 1000000;
  582.     secs++;
  583.   }
  584.   return PTimeInterval(usecs/1000, secs);
  585. }
  586. PTime PTime::operator-(const PTimeInterval & t) const
  587. {
  588.   time_t secs = theTime - t.GetSeconds();
  589.   long msecs = (long)(microseconds/1000 - t.GetMilliSeconds()%1000);
  590.   if (msecs < 0) {
  591.     msecs += 1000;
  592.     secs--;
  593.   }
  594.   else if (msecs >= 1000) {
  595.     msecs -= 1000;
  596.     secs++;
  597.   }
  598.   return PTime(secs, msecs*1000);
  599. }
  600. PTime & PTime::operator-=(const PTimeInterval & t)
  601. {
  602.   theTime -= t.GetSeconds();
  603.   microseconds -= (long)(t.GetMilliSeconds()%1000)*1000;
  604.   if (microseconds < 0) {
  605.     microseconds += 1000000;
  606.     theTime--;
  607.   }
  608.   else if (microseconds >= 1000000) {
  609.     microseconds -= 1000000;
  610.     theTime++;
  611.   }
  612.   return *this;
  613. }
  614. // End Of File ///////////////////////////////////////////////////////////////