00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00036 #include "OW_config.h"
00037 #include "OW_DateTime.hpp"
00038 #include "OW_String.hpp"
00039 #include "OW_BinarySerialization.hpp"
00040 #include "OW_Format.hpp"
00041 #include "OW_Mutex.hpp"
00042 #include "OW_MutexLock.hpp"
00043 #include "OW_ExceptionIds.hpp"
00044
00045 #if defined(OW_HAVE_ISTREAM) && defined(OW_HAVE_OSTREAM)
00046 #include <istream>
00047 #include <ostream>
00048 #else
00049 #include <iostream>
00050 #endif
00051
00052 #include <time.h>
00053 #ifdef OW_HAVE_SYS_TIME_H
00054 #include <sys/time.h>
00055 #endif
00056
00057 #include <cctype>
00058
00059
00060 #ifndef OW_HAVE_LOCALTIME_R
00061 namespace
00062 {
00063 OW_NAMESPACE::Mutex localtimeMutex;
00064 }
00065 struct tm *localtime_r(const time_t *timep, struct tm *result)
00066 {
00067 OW_NAMESPACE::MutexLock lock(localtimeMutex);
00068 struct tm *p = localtime(timep);
00069
00070 if (p)
00071 {
00072 *(result) = *p;
00073 }
00074
00075 return p;
00076 }
00077 #endif
00078
00079 #ifndef OW_HAVE_GMTIME_R
00080 namespace
00081 {
00082 OW_NAMESPACE::Mutex gmtimeMutex;
00083 }
00084 struct tm *gmtime_r(const time_t *timep, struct tm *result)
00085 {
00086 OW_NAMESPACE::MutexLock lock(gmtimeMutex);
00087 struct tm *p = gmtime(timep);
00088
00089 if (p)
00090 {
00091 *(result) = *p;
00092 }
00093
00094 return p;
00095 }
00096 #endif
00097
00098 #ifndef OW_HAVE_ASCTIME_R
00099 namespace
00100 {
00101 OW_NAMESPACE::Mutex asctimeMutex;
00102 }
00103 char *asctime_r(const struct tm *tm, char *result)
00104 {
00105 OW_NAMESPACE::MutexLock lock(asctimeMutex);
00106 char *p = asctime(tm);
00107
00108 if (p)
00109 {
00110
00111 ::strncpy(result,p,25);
00112 result[25] = 0;
00113 }
00114
00115 return result;
00116 }
00117 #endif
00118
00119 namespace OW_NAMESPACE
00120 {
00121
00122 using std::istream;
00123 using std::ostream;
00124
00126 OW_DEFINE_EXCEPTION_WITH_ID(DateTime);
00127
00129 DateTime::DateTime()
00130 : m_time(0)
00131 , m_microseconds(0)
00132
00133 {
00134 }
00136 namespace
00137 {
00138
00139 inline void badDateTime(const String& str)
00140 {
00141 OW_THROW(DateTimeException, Format("Invalid DateTime: %1", str).c_str());
00142 }
00143
00144 inline void validateRanges(Int32 year, Int32 month, Int32 day, Int32 hour,
00145 Int32 minute, Int32 second, Int32 microseconds, const String& str)
00146 {
00147 if (year < 0 || year > 9999 ||
00148 month < 1 || month > 12 ||
00149 day < 1 || day > 31 ||
00150 hour < 0 || hour > 23 ||
00151 minute < 0 || minute > 59 ||
00152 second < 0 || second > 60 ||
00153 microseconds < 0 || microseconds > 999999)
00154 {
00155 badDateTime(str);
00156 }
00157 }
00158
00159 inline bool isDOWValid(const char* str)
00160 {
00161
00162 bool good = true;
00163 if (str[0] == 'S')
00164 {
00165 if (str[1] == 'u')
00166 {
00167 if (str[2] != 'n')
00168 {
00169 good = false;
00170 }
00171 }
00172 else if (str[1] == 'a')
00173 {
00174 if (str[2] != 't')
00175 {
00176 good = false;
00177 }
00178 }
00179 else
00180 {
00181 good = false;
00182 }
00183 }
00184 else if (str[0] == 'M')
00185 {
00186 if (str[1] == 'o')
00187 {
00188 if (str[2] != 'n')
00189 {
00190 good = false;
00191 }
00192 }
00193 else
00194 {
00195 good = false;
00196 }
00197 }
00198 else if (str[0] == 'T')
00199 {
00200 if (str[1] == 'u')
00201 {
00202 if (str[2] != 'e')
00203 {
00204 good = false;
00205 }
00206 }
00207 else if (str[1] == 'h')
00208 {
00209 if (str[2] != 'u')
00210 {
00211 good = false;
00212 }
00213 }
00214 else
00215 {
00216 good = false;
00217 }
00218 }
00219 else if (str[0] == 'W')
00220 {
00221 if (str[1] == 'e')
00222 {
00223 if (str[2] != 'd')
00224 {
00225 good = false;
00226 }
00227 }
00228 else
00229 {
00230 good = false;
00231 }
00232 }
00233 else if (str[0] == 'F')
00234 {
00235 if (str[1] == 'r')
00236 {
00237 if (str[2] != 'i')
00238 {
00239 good = false;
00240 }
00241 }
00242 else
00243 {
00244 good = false;
00245 }
00246 }
00247 else
00248 {
00249 good = false;
00250 }
00251
00252 return good;
00253 }
00254
00255 inline bool isLongDOWValid(const String& s)
00256 {
00257 if ( (s == "Sunday") ||
00258 (s == "Monday") ||
00259 (s == "Tuesday") ||
00260 (s == "Wednesday") ||
00261 (s == "Thursday") ||
00262 (s == "Friday") ||
00263 (s == "Saturday") )
00264 {
00265 return true;
00266 }
00267 return false;
00268 }
00269
00270
00271 inline int decodeShortMonth(const char* str)
00272 {
00273
00274 if (str[0] == 'J')
00275 {
00276 if (str[1] == 'a')
00277 {
00278 if (str[2] == 'n')
00279 {
00280 return 1;
00281 }
00282 }
00283 else if (str[1] == 'u')
00284 {
00285 if (str[2] == 'n')
00286 {
00287 return 6;
00288 }
00289 else if (str[2] == 'l')
00290 {
00291 return 7;
00292 }
00293 }
00294 }
00295 else if (str[0] == 'F')
00296 {
00297 if (str[1] == 'e' && str[2] == 'b')
00298 {
00299 return 2;
00300 }
00301 }
00302 else if (str[0] == 'M')
00303 {
00304 if (str[1] == 'a')
00305 {
00306 if (str[2] == 'r')
00307 {
00308 return 3;
00309 }
00310 else if (str[2] == 'y')
00311 {
00312 return 5;
00313 }
00314 }
00315 }
00316 else if (str[0] == 'A')
00317 {
00318 if (str[1] == 'p')
00319 {
00320 if (str[2] == 'r')
00321 {
00322 return 4;
00323 }
00324 }
00325 else if (str[1] == 'u')
00326 {
00327 if (str[2] == 'g')
00328 {
00329 return 8;
00330 }
00331 }
00332 }
00333 else if (str[0] == 'S')
00334 {
00335 if (str[1] == 'e' && str[2] == 'p')
00336 {
00337 return 9;
00338 }
00339 }
00340 else if (str[0] == 'O')
00341 {
00342 if (str[1] == 'c' && str[2] == 't')
00343 {
00344 return 10;
00345 }
00346 }
00347 else if (str[0] == 'N')
00348 {
00349 if (str[1] == 'o' && str[2] == 'v')
00350 {
00351 return 11;
00352 }
00353 }
00354 else if (str[0] == 'D')
00355 {
00356 if (str[1] == 'e' && str[2] == 'c')
00357 {
00358 return 12;
00359 }
00360 }
00361
00362 return -1;
00363 }
00364
00365
00366 inline int decodeLongMonth(const String& str)
00367 {
00368 if ( str.equals("January") )
00369 {
00370 return 1;
00371 }
00372 else if ( str.equals("February") )
00373 {
00374 return 2;
00375 }
00376 else if ( str.equals("March") )
00377 {
00378 return 3;
00379 }
00380 else if ( str.equals("April") )
00381 {
00382 return 4;
00383 }
00384 else if ( str.equals("May") )
00385 {
00386 return 5;
00387 }
00388 else if ( str.equals("June") )
00389 {
00390 return 6;
00391 }
00392 else if ( str.equals("July") )
00393 {
00394 return 7;
00395 }
00396 else if ( str.equals("August") )
00397 {
00398 return 8;
00399 }
00400 else if ( str.equals("September") )
00401 {
00402 return 9;
00403 }
00404 else if ( str.equals("October") )
00405 {
00406 return 10;
00407 }
00408 else if ( str.equals("November") )
00409 {
00410 return 11;
00411 }
00412 else if ( str.equals("December") )
00413 {
00414 return 12;
00415 }
00416 return -1;
00417 }
00418
00419
00420
00421
00422 const int LOCAL_TIME_OFFSET = -24;
00423 bool getTimeZoneOffset(const String& timezone, int& offset)
00424 {
00425 int temp_offset = LOCAL_TIME_OFFSET -1;
00426 if ( timezone.length() == 1 )
00427 {
00428
00429
00430
00431 switch ( timezone[0] )
00432 {
00433 case 'Y':
00434 temp_offset = -12;
00435 break;
00436 case 'X':
00437 temp_offset = -11;
00438 break;
00439 case 'W':
00440 temp_offset = -10;
00441 break;
00442 case 'V':
00443 temp_offset = -9;
00444 break;
00445 case 'U':
00446 temp_offset = -8;
00447 break;
00448 case 'T':
00449 temp_offset = -7;
00450 break;
00451 case 'S':
00452 temp_offset = -6;
00453 break;
00454 case 'R':
00455 temp_offset = -5;
00456 break;
00457 case 'Q':
00458 temp_offset = -4;
00459 break;
00460 case 'P':
00461 temp_offset = -3;
00462 break;
00463 case 'O':
00464 temp_offset = -2;
00465 break;
00466 case 'N':
00467 temp_offset = -1;
00468 break;
00469 case 'Z':
00470 temp_offset = 0;
00471 break;
00472 case 'A':
00473 temp_offset = 1;
00474 break;
00475 case 'B':
00476 temp_offset = 2;
00477 break;
00478 case 'C':
00479 temp_offset = 3;
00480 break;
00481 case 'D':
00482 temp_offset = 4;
00483 break;
00484 case 'E':
00485 temp_offset = 5;
00486 break;
00487 case 'F':
00488 temp_offset = 6;
00489 break;
00490 case 'G':
00491 temp_offset = 7;
00492 break;
00493 case 'H':
00494 temp_offset = 8;
00495 break;
00496 case 'I':
00497 temp_offset = 9;
00498 break;
00499 case 'K':
00500 temp_offset = 10;
00501 break;
00502 case 'L':
00503 temp_offset = 11;
00504 break;
00505 case 'M':
00506 temp_offset = 12;
00507 break;
00508 case 'J':
00509 temp_offset = LOCAL_TIME_OFFSET;
00510 break;
00511 default:
00512 break;
00513 }
00514 }
00515 else if ( timezone == "UTC" )
00516 {
00517 temp_offset = 0;
00518 }
00519
00520 else if ( timezone == "GMT" )
00521 {
00522 temp_offset = 0;
00523 }
00524 else if ( timezone == "BST" )
00525 {
00526 temp_offset = 1;
00527 }
00528 else if ( timezone == "IST" )
00529 {
00530 temp_offset = 1;
00531 }
00532 else if ( timezone == "WET" )
00533 {
00534 temp_offset = 0;
00535 }
00536 else if ( timezone == "WEST" )
00537 {
00538 temp_offset = 1;
00539 }
00540 else if ( timezone == "CET" )
00541 {
00542 temp_offset = 1;
00543 }
00544 else if ( timezone == "CEST" )
00545 {
00546 temp_offset = 2;
00547 }
00548 else if ( timezone == "EET" )
00549 {
00550 temp_offset = 2;
00551 }
00552 else if ( timezone == "EEST" )
00553 {
00554 temp_offset = 3;
00555 }
00556 else if ( timezone == "MSK" )
00557 {
00558 temp_offset = 3;
00559 }
00560 else if ( timezone == "MSD" )
00561 {
00562 temp_offset = 4;
00563 }
00564
00565 else if ( timezone == "AST" )
00566 {
00567 temp_offset = -4;
00568 }
00569 else if ( timezone == "ADT" )
00570 {
00571 temp_offset = -3;
00572 }
00573 else if ( timezone == "EST" )
00574 {
00575
00576
00577 temp_offset = -5;
00578 }
00579 else if ( timezone == "EDT" )
00580 {
00581 temp_offset = -4;
00582 }
00583 else if ( timezone == "ET" )
00584
00585 {
00586
00587 temp_offset = -5;
00588 }
00589 else if ( timezone == "CST" )
00590 {
00591
00592 temp_offset = -6;
00593 }
00594 else if ( timezone == "CDT" )
00595 {
00596 temp_offset = -5;
00597 }
00598 else if ( timezone == "CT" )
00599
00600 {
00601
00602 temp_offset = -6;
00603 }
00604 else if ( timezone == "MST" )
00605 {
00606 temp_offset = -7;
00607 }
00608 else if ( timezone == "MDT" )
00609 {
00610 temp_offset = -6;
00611 }
00612 else if ( timezone == "MT" )
00613
00614 {
00615
00616 temp_offset = -7;
00617 }
00618 else if ( timezone == "PST" )
00619 {
00620 temp_offset = -8;
00621 }
00622 else if ( timezone == "PDT" )
00623 {
00624 temp_offset = -7;
00625 }
00626 else if ( timezone == "PT" )
00627
00628 {
00629
00630 temp_offset = -8;
00631 }
00632 else if ( timezone == "HST" )
00633 {
00634 temp_offset = -10;
00635 }
00636 else if ( timezone == "AKST" )
00637 {
00638 temp_offset = -9;
00639 }
00640 else if ( timezone == "AKDT" )
00641 {
00642 temp_offset = -8;
00643 }
00644
00645 else if ( timezone == "WST" )
00646 {
00647 temp_offset = 8;
00648 }
00649
00650
00651 if ( temp_offset >= LOCAL_TIME_OFFSET )
00652 {
00653 offset = temp_offset;
00654 return true;
00655 }
00656 return false;
00657 }
00658
00659 Int32 getDaysPerMonth(Int32 year, Int32 month)
00660 {
00661 const Int32 normal_days_per_month[12] =
00662 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
00663
00664 if ( (month >= 1) && (month <= 12) )
00665 {
00666 if ( month != 2 )
00667 {
00668 return normal_days_per_month[month - 1];
00669 }
00670
00671 int leap_year_adjust = 0;
00672
00673 if ( (year % 4) == 0 )
00674 {
00675
00676 if ( (year % 100) == 0 )
00677 {
00678 if ( (year % 400) == 0 )
00679 {
00680 leap_year_adjust = 1;
00681 }
00682 }
00683 else
00684 {
00685 leap_year_adjust = 1;
00686 }
00687 }
00688
00689 return normal_days_per_month[month - 1] + leap_year_adjust;
00690
00691 }
00692 return 0;
00693 }
00694
00695
00696
00697
00698
00699 void adjustTimeForTimeZone(Int32 timezone_offset, Int32& year, Int32& month,
00700 Int32& day, Int32& hour)
00701 {
00702 if ( timezone_offset < 0 )
00703 {
00704 hour -= timezone_offset;
00705
00706 if ( hour > 23 )
00707 {
00708 ++day;
00709 hour -= 24;
00710 }
00711
00712 if ( day > getDaysPerMonth(year, month) )
00713 {
00714 ++month;
00715 day = 1;
00716 }
00717 if ( month > 12 )
00718 {
00719 month -= 12;
00720 ++year;
00721 }
00722 }
00723 else if ( timezone_offset > 0 )
00724 {
00725 hour -= timezone_offset;
00726
00727 if ( hour < 0 )
00728 {
00729 --day;
00730 hour += 24;
00731 }
00732
00733 if ( day < 1 )
00734 {
00735 --month;
00736 day += getDaysPerMonth(year, month);
00737 }
00738 if ( month < 1 )
00739 {
00740 month += 12;
00741 --year;
00742 }
00743 }
00744 }
00745
00746
00747 }
00748
00750 DateTime::DateTime(const String& str)
00751 {
00752
00753 if ( str.length() == 25 )
00754 {
00755
00756 if ( !(str[14] != '.' || (str[21] != '+' && str[21] != '-')) )
00757 {
00758 try
00759 {
00760
00761
00762
00763 String strNoAsterisks(str);
00764 for (size_t i = 0; i < strNoAsterisks.length(); ++i)
00765 {
00766 if (strNoAsterisks[i] == '*')
00767 {
00768 strNoAsterisks[i] = '0';
00769 }
00770 }
00771 Int32 year = strNoAsterisks.substring(0, 4).toInt32();
00772 Int32 month = strNoAsterisks.substring(4, 2).toInt32();
00773 Int32 day = strNoAsterisks.substring(6, 2).toInt32();
00774 Int32 hour = strNoAsterisks.substring(8, 2).toInt32();
00775 Int32 minute = strNoAsterisks.substring(10, 2).toInt32();
00776 Int32 second = strNoAsterisks.substring(12, 2).toInt32();
00777 Int32 microseconds = strNoAsterisks.substring(15, 6).toInt32();
00778
00779 validateRanges(year, month, day, hour, minute, second, microseconds, str);
00780
00781 Int32 utc = strNoAsterisks.substring(22, 3).toInt32();
00782
00783
00784 if (str[21] == '+')
00785 {
00786 utc = 0 - utc;
00787 }
00788 minute += utc;
00789
00790 set(year, month, day, hour, minute, second,
00791 microseconds, E_UTC_TIME);
00792 return;
00793 }
00794 catch (StringConversionException&)
00795 {
00796
00797
00798 }
00799 }
00800 }
00801
00802
00803
00804 if ( !str.empty() )
00805 {
00806
00807
00808
00809 String weekday;
00810 String day;
00811 String time;
00812 int timezone_number = LOCAL_TIME_OFFSET - 1;
00813 Int32 month_number = -1;
00814 String year;
00815
00816 StringArray tokenized_date = str.tokenize();
00817
00818
00819 for ( StringArray::const_iterator date_token = tokenized_date.begin();
00820 date_token != tokenized_date.end();
00821 ++date_token )
00822 {
00823
00824 if ( isDOWValid( date_token->c_str() ) )
00825 {
00826 if ( weekday.empty() )
00827 {
00828 if ( date_token->length() > 3 )
00829 {
00830 if ( isLongDOWValid( *date_token ) )
00831 {
00832 weekday = *date_token;
00833 }
00834 else
00835 {
00836
00837 badDateTime(str);
00838 }
00839 }
00840 else
00841 {
00842 weekday = *date_token;
00843 }
00844 }
00845 else
00846 {
00847
00848 badDateTime(str);
00849 }
00850 }
00851
00852 else if ( (month_number == -1) &&
00853 (month_number = decodeShortMonth( date_token->c_str() ) ) != -1 )
00854 {
00855 if ( date_token->length() > 3 )
00856 {
00857 month_number = decodeLongMonth( date_token->c_str() );
00858
00859 if ( month_number == -1 )
00860 {
00861
00862 badDateTime(str);
00863 }
00864 }
00865 }
00866
00867 else if ( time.empty() && (date_token->indexOf(":") != String::npos) )
00868 {
00869
00870 time = *date_token;
00871 }
00872
00873 else if ( day.empty() && isdigit((*date_token)[0]) )
00874 {
00875 day = *date_token;
00876 }
00877
00878 else if ( year.empty() && isdigit((*date_token)[0]) )
00879 {
00880 year = *date_token;
00881 }
00882 else if ( (timezone_number <= LOCAL_TIME_OFFSET) &&
00883 (date_token->length() >= 1) &&
00884 (date_token->length() <= 4) &&
00885 getTimeZoneOffset(*date_token, timezone_number) )
00886 {
00887
00888 }
00889 else
00890 {
00891 badDateTime(str);
00892 }
00893
00894 }
00895
00896
00897
00898 if ( (month_number >= 1) && !day.empty() && !time.empty() && !year.empty() )
00899 {
00900
00901
00902
00903 StringArray time_fields = time.tokenize(":");
00904
00905
00906
00907 if ( (time_fields.size() < 2) || (time_fields.size() > 3) )
00908 {
00909 badDateTime(str);
00910 }
00911
00912 try
00913 {
00914
00915 Int32 hour;
00916 Int32 minute;
00917 Int32 second = 0;
00918 UInt32 microseconds = 0;
00919 Int32 year_number = year.toInt32();
00920 Int32 day_number = day.toInt32();
00921
00922 hour = time_fields[0].toInt32();
00923 minute = time_fields[1].toInt32();
00924
00925 if ( time_fields.size() == 3 )
00926 {
00927 second = time_fields[2].toInt32();
00928 }
00929
00930 validateRanges(year_number, month_number, day_number,
00931 hour, minute, second, microseconds, str);
00932
00933 if ( timezone_number <= LOCAL_TIME_OFFSET )
00934 {
00935 set(year_number, month_number, day_number, hour,
00936 minute, second, microseconds, E_LOCAL_TIME);
00937 }
00938 else
00939 {
00940
00941
00942
00943
00944 adjustTimeForTimeZone(timezone_number, year_number, month_number, day_number, hour);
00945
00946
00947 validateRanges(year_number, month_number, day_number, hour,
00948 minute, second, microseconds, str);
00949
00950 set(year_number, month_number, day_number, hour,
00951 minute, second, microseconds, E_UTC_TIME);
00952 }
00953 }
00954 catch (const StringConversionException&)
00955 {
00956 badDateTime(str);
00957 }
00958 }
00959 else
00960 {
00961
00962 badDateTime(str);
00963 }
00964 }
00965 else
00966 {
00967
00968 badDateTime(str);
00969 }
00970 }
00972 DateTime::DateTime(time_t t, UInt32 microseconds)
00973 : m_time(t)
00974 , m_microseconds(microseconds)
00975 {
00976 }
00978 DateTime::DateTime(int year, int month, int day, int hour, int minute,
00979 int second, UInt32 microseconds, ETimeOffset timeOffset)
00980 {
00981 set(year, month, day, hour, minute, second, microseconds, timeOffset);
00982 }
00984 DateTime::~DateTime()
00985 {
00986 }
00988 inline tm
00989 DateTime::getTm(ETimeOffset timeOffset) const
00990 {
00991 if (timeOffset == E_LOCAL_TIME)
00992 {
00993 tm theTime;
00994 localtime_r(&m_time, &theTime);
00995 return theTime;
00996 }
00997 else
00998 {
00999 tm theTime;
01000 gmtime_r(&m_time, &theTime);
01001 return theTime;
01002 }
01003 }
01004
01006 inline void
01007 DateTime::setTime(tm& tmarg, ETimeOffset timeOffset)
01008 {
01009 if (timeOffset == E_LOCAL_TIME)
01010 {
01011 m_time = ::mktime(&tmarg);
01012 }
01013 else
01014 {
01015 #ifdef OW_HAVE_TIMEGM
01016 m_time = ::timegm(&tmarg);
01017 #else
01018
01019
01020
01021 #ifdef OW_NETWARE
01022 m_time = ::mktime(&tmarg) - _timezone;
01023 #else
01024 m_time = ::mktime(&tmarg) - ::timezone;
01025 #endif
01026 #endif
01027 }
01028
01029 if (m_time < 0)
01030 {
01031 char buff[30];
01032 String extraError;
01033
01034 if( tmarg.tm_wday < 0 || tmarg.tm_wday > 6 )
01035 {
01036 extraError += Format("Invalid weekday: %1. ", tmarg.tm_wday);
01037 tmarg.tm_wday = 0;
01038 }
01039
01040 if( tmarg.tm_mon < 0 || tmarg.tm_mon > 11 )
01041 {
01042 extraError += Format("Invalid month: %1. ", tmarg.tm_mon);
01043 tmarg.tm_mon = 0;
01044 }
01045
01046 asctime_r(&tmarg, buff);
01047
01048 OW_THROW(DateTimeException, Format("Unable to represent time \"%1\" as a time_t. %2", buff, extraError).toString().rtrim().c_str());
01049 }
01050 }
01052 int
01053 DateTime::getHour(ETimeOffset timeOffset) const
01054 {
01055 return getTm(timeOffset).tm_hour;
01056 }
01058 int
01059 DateTime::getMinute(ETimeOffset timeOffset) const
01060 {
01061 return getTm(timeOffset).tm_min;
01062 }
01064 int
01065 DateTime::getSecond(ETimeOffset timeOffset) const
01066 {
01067 return getTm(timeOffset).tm_sec;
01068 }
01070 UInt32
01071 DateTime::getMicrosecond() const
01072 {
01073 return m_microseconds;
01074 }
01076 int
01077 DateTime::getDay(ETimeOffset timeOffset) const
01078 {
01079 return getTm(timeOffset).tm_mday;
01080 }
01082 int
01083 DateTime::getDow(ETimeOffset timeOffset) const
01084 {
01085 return getTm(timeOffset).tm_wday;
01086 }
01088 int
01089 DateTime::getMonth(ETimeOffset timeOffset) const
01090 {
01091 return getTm(timeOffset).tm_mon+1;
01092 }
01094 int
01095 DateTime::getYear(ETimeOffset timeOffset) const
01096 {
01097 return (getTm(timeOffset).tm_year + 1900);
01098 }
01100 time_t
01101 DateTime::get() const
01102 {
01103 return m_time;
01104 }
01106 void
01107 DateTime::setHour(int hour, ETimeOffset timeOffset)
01108 {
01109 tm theTime = getTm(timeOffset);
01110 theTime.tm_hour = hour;
01111 setTime(theTime, timeOffset);
01112 }
01114 void
01115 DateTime::setMinute(int minute, ETimeOffset timeOffset)
01116 {
01117 tm theTime = getTm(timeOffset);
01118 theTime.tm_min = minute;
01119 setTime(theTime, timeOffset);
01120 }
01122 void
01123 DateTime::setSecond(int second, ETimeOffset timeOffset)
01124 {
01125 tm theTime = getTm(timeOffset);
01126 theTime.tm_sec = second;
01127 setTime(theTime, timeOffset);
01128 }
01130 void
01131 DateTime::setMicrosecond(UInt32 microseconds)
01132 {
01133 if (microseconds > 999999)
01134 {
01135 OW_THROW(DateTimeException, Format("invalid microseconds: %1", microseconds).c_str());
01136 }
01137 m_microseconds = microseconds;
01138 }
01140 void
01141 DateTime::setTime(int hour, int minute, int second, ETimeOffset timeOffset)
01142 {
01143 tm theTime = getTm(timeOffset);
01144 theTime.tm_hour = hour;
01145 theTime.tm_min = minute;
01146 theTime.tm_sec = second;
01147 setTime(theTime, timeOffset);
01148 }
01150 void
01151 DateTime::setDay(int day, ETimeOffset timeOffset)
01152 {
01153 tm theTime = getTm(timeOffset);
01154 theTime.tm_mday = day;
01155 setTime(theTime, timeOffset);
01156 }
01158 void
01159 DateTime::setMonth(int month, ETimeOffset timeOffset)
01160 {
01161 if (month == 0)
01162 {
01163 OW_THROW(DateTimeException, "invalid month: 0");
01164 }
01165
01166 tm theTime = getTm(timeOffset);
01167 theTime.tm_mon = month-1;
01168 setTime(theTime, timeOffset);
01169 }
01171 void
01172 DateTime::setYear(int year, ETimeOffset timeOffset)
01173 {
01174 tm theTime = getTm(timeOffset);
01175 theTime.tm_year = year - 1900;
01176 setTime(theTime, timeOffset);
01177 }
01179 void
01180 DateTime::set(int year, int month, int day, int hour, int minute, int second,
01181 UInt32 microseconds, ETimeOffset timeOffset)
01182 {
01183 tm tmarg;
01184 memset(&tmarg, 0, sizeof(tmarg));
01185 tmarg.tm_year = (year >= 1900) ? year - 1900 : year;
01186 tmarg.tm_mon = month-1;
01187 tmarg.tm_mday = day;
01188 tmarg.tm_hour = hour;
01189 tmarg.tm_min = minute;
01190 tmarg.tm_sec = second;
01191 if (timeOffset == E_UTC_TIME)
01192 {
01193 tmarg.tm_isdst = 0;
01194 }
01195 else
01196 {
01197 tmarg.tm_isdst = -1;
01198 }
01199 setTime(tmarg, timeOffset);
01200 m_microseconds = microseconds;
01201 }
01203 void
01204 DateTime::setToCurrent()
01205 {
01206 #ifdef OW_HAVE_GETTIMEOFDAY
01207 timeval tv;
01208 gettimeofday(&tv, NULL);
01209 m_time = tv.tv_sec;
01210 m_microseconds = tv.tv_usec;
01211 #else
01212 m_time = time(NULL);
01213 m_microseconds = 0;
01214 #endif
01215 }
01217 void
01218 DateTime::addDays(int days)
01219 {
01220 tm theTime = getTm(E_UTC_TIME);
01221 theTime.tm_mday += days;
01222 setTime(theTime, E_UTC_TIME);
01223 }
01225 void
01226 DateTime::addYears(int years)
01227 {
01228 tm theTime = getTm(E_UTC_TIME);
01229 theTime.tm_year += years;
01230 setTime(theTime, E_UTC_TIME);
01231 }
01233 void
01234 DateTime::addMonths(int months)
01235 {
01236 tm theTime = getTm(E_UTC_TIME);
01237 theTime.tm_mon += months;
01238 setTime(theTime, E_UTC_TIME);
01239 }
01241 String
01242 DateTime::toString(ETimeOffset timeOffset) const
01243 {
01244 tm theTime = getTm(timeOffset);
01245 char buff[30];
01246 asctime_r(&theTime, buff);
01247 String s(buff);
01248 return s;
01249 }
01250
01252 String DateTime::toString(char const * format, ETimeOffset timeOffset) const
01253 {
01254 tm theTime = getTm(timeOffset);
01255 size_t const BUFSZ = 1024;
01256 char buf[BUFSZ];
01257 size_t n = strftime(buf, BUFSZ, format, &theTime);
01258 buf[n >= BUFSZ ? 0 : n] = '\0';
01259 return String(buf);
01260 }
01261
01263 char const DateTime::DEFAULT_FORMAT[] = "%c";
01264
01266 String
01267 DateTime::toStringGMT() const
01268 {
01269 return toString(E_UTC_TIME);
01270 }
01271
01273 Int16 DateTime::localTimeAndOffset(time_t t, struct tm & t_loc)
01274 {
01275 struct tm t_utc;
01276 struct tm * ptm_utc = ::gmtime_r(&t, &t_utc);
01277 struct tm * ptm_loc = ::localtime_r(&t, &t_loc);
01278 if (!ptm_utc || !ptm_loc)
01279 {
01280 OW_THROW(DateTimeException, Format("Invalid time_t: %1", t).c_str());
01281 }
01282 int min_diff =
01283 (t_loc.tm_min - t_utc.tm_min) + 60 * (t_loc.tm_hour - t_utc.tm_hour);
01284
01285
01286 int day_diff = t_loc.tm_mday - t_utc.tm_mday;
01287 int const one_day = 24 * 60;
01288 if (day_diff == 0)
01289 {
01290 return min_diff;
01291 }
01292 else if (day_diff == 1 || day_diff < -1)
01293 {
01294
01295
01296 return min_diff + one_day;
01297 }
01298 else
01299 {
01300
01301
01302 return min_diff - one_day;
01303 }
01304 }
01305
01307 void
01308 DateTime::set(time_t t, UInt32 microseconds)
01309 {
01310 if (t == static_cast<time_t>(-1) || microseconds > 999999)
01311 {
01312 OW_THROW(DateTimeException, "Either t == -1 or microseconds > 999999");
01313 }
01314
01315 m_time = t;
01316 m_microseconds = microseconds;
01317 }
01318
01320
01321 DateTime
01322 DateTime::getCurrent()
01323 {
01324 DateTime current;
01325 current.setToCurrent();
01326 return current;
01327 }
01328
01330 DateTime operator-(DateTime const & x, DateTime const & y)
01331 {
01332 time_t diff = x.get() - y.get();
01333 Int32 microdiff = (Int32)x.getMicrosecond() - (Int32)y.getMicrosecond();
01334 if (microdiff < 0)
01335 {
01336 --diff;
01337 microdiff += 1000000;
01338 }
01339 return DateTime(diff, (UInt32)microdiff);
01340 }
01341
01342 }
01343