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