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