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