Main Page | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | File Members | Related Pages

O3DBIDate.cpp

Go to the documentation of this file.
00001 
00011 #include "O3DBIDate.h"
00012 #include "O3DBIException.h"
00013 #include "O3DBIError.h"
00014 
00015 #define O3DBI_DATE_YEAR_MIN                     -4712
00016 #define O3DBI_DATE_YEAR_MAX                     9999
00017 #define O3DBI_DATE_MONTH_MIN                    1
00018 #define O3DBI_DATE_MONTH_MAX                    12
00019 #define O3DBI_DATE_DAY_MIN                      1
00020 #define O3DBI_DATE_DAY_MAX                      31
00021 #define O3DBI_DATE_HOUR_MIN                     0
00022 #define O3DBI_DATE_HOUR_MAX                     23
00023 #define O3DBI_DATE_MINUTE_MIN                   0
00024 #define O3DBI_DATE_MINUTE_MAX                   59
00025 #define O3DBI_DATE_SECOND_MIN                   0
00026 #define O3DBI_DATE_SECOND_MAX                   59
00027 
00028 #ifndef MAX_TIME_BUFFER_SIZE
00029 #define MAX_TIME_BUFFER_SIZE                    128
00030 #endif
00031 #define MAX_TIME_FORMAT_SIZE                    64
00032 
00033 // ----------------------------------------------------------------------------
00034 // O3DBIDate static member initialization
00035 
00036 int O3DBIDate::_arrDaysInMonth[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30,
00037     31, 30, 31 };
00038 
00039 // ----------------------------------------------------------------------------
00040 // O3DBIDate construction/destruction
00041 
00042 O3DBIDate::O3DBIDate()
00043 {
00044     _value._year = 1899;
00045     _value._month = 12;
00046     _value._day = 30;
00047     _value._hour = 0;
00048     _value._minute = 0;
00049     _value._second = 0;
00050 }
00051 
00052 O3DBIDate::O3DBIDate(int year,
00053                      int month,
00054                      int day,
00055                      int hour,
00056                      int minute,
00057                      int second)
00058 {
00059     _value._year = year;
00060     _value._month = month;
00061     _value._day = day;
00062     _value._hour = hour;
00063     _value._minute = minute;
00064     _value._second = second;
00065 
00066     if (! RangeCheck())
00067         throw new O3DBIException(O3DBI_INVALID_DATE,
00068         O3DBIErrorTxt::pchInvalidDate, _T("O3DBIDate::O3DBIDate"), this);
00069     if (JumpFromJulianToGregorian())
00070         _value._day = 15;   // Adjust date
00071 }
00072 
00073 O3DBIDate::O3DBIDate(const tm& t)
00074 {
00075     (*this) = t;
00076 }
00077 
00078 O3DBIDate::O3DBIDate(time_t time)
00079 {
00080     (*this) = time;
00081 }
00082 
00083 O3DBIDate::O3DBIDate(unsigned long ulJulianDay)
00084 {
00085     // The conversion algorithm developed by Henry F. Fliegel and
00086     // Thomas C. Van Flandern:
00087     unsigned long t1;
00088     unsigned long t2;
00089     unsigned long yr;
00090     unsigned long mo;
00091 
00092     t1 = ulJulianDay + 68569L;
00093     t2 = 4L * t1 / 146097L;
00094     t1 = t1 - (146097L * t2 + 3L) / 4L;
00095     yr = 4000L * (t1 + 1L) / 1461001L;
00096     t1 = t1 - 1461L * yr / 4L + 31L;
00097     mo = 80L * t1 / 2447L;
00098     _value._day = static_cast<int>(t1 - 2447L * mo / 80L);
00099     t1 = mo / 11L;
00100     _value._month = static_cast<int>(mo + 2L - 12L * t1);
00101     _value._year = static_cast<int>(100L * (t2 - 49L) + yr + t1);
00102 
00103     // Correction for BC years
00104     if (_value._year <= 0)
00105         _value._year -= 1;
00106 
00107     // Set all time members to zero
00108     _value._hour = 0;
00109     _value._minute = 0;
00110     _value._second = 0;
00111 
00112     if (! RangeCheck())
00113         throw new O3DBIException(O3DBI_INVALID_DATE,
00114         O3DBIErrorTxt::pchInvalidDate, _T("O3DBIDate::O3DBIDate"), this);
00115 
00116     if (JumpFromJulianToGregorian())
00117         _value._day = 15;   // Adjust date
00118 }
00119 
00120 O3DBIDate::O3DBIDate(const O3DBIDate& other)
00121 {
00122     (*this) = other;
00123 }
00124 
00125 O3DBIDate::~O3DBIDate()
00126 {
00127 
00128 }
00129 
00130 // ----------------------------------------------------------------------------
00131 // O3DBIDate assignment
00132 
00133 O3DBIDate& O3DBIDate::operator=(const O3DBIDate& other)
00134 {
00135     _value._year = other._value._year;
00136     _value._month = other._value._month;
00137     _value._day = other._value._day;
00138     _value._hour = other._value._hour;
00139     _value._minute = other._value._minute;
00140     _value._second = other._value._second;
00141     return (*this);
00142 }
00143 
00144 O3DBIDate& O3DBIDate::operator=(const tm& t)
00145 {
00146     _value._year = 1900 + t.tm_year;
00147     _value._month = t.tm_mon;
00148     _value._day = t.tm_mday;
00149     _value._hour = t.tm_hour;
00150     _value._minute = t.tm_min;
00151     _value._second = t.tm_sec;
00152     return (*this);
00153 }
00154 
00155 O3DBIDate& O3DBIDate::operator=(time_t time)
00156 {
00157     tm* t;
00158     t = ::gmtime(&time);
00159     (*this) = *t;
00160     return (*this);
00161 }
00162 
00163 // ----------------------------------------------------------------------------
00164 // O3DBIDate comparison
00165 
00166 bool O3DBIDate::operator==(const O3DBIDate& other) const
00167 {
00168     return (_value._year == other._value._year &&
00169         _value._month == other._value._month &&
00170         _value._day == other._value._day &&
00171         _value._hour == other._value._hour &&
00172         _value._minute == other._value._minute &&
00173         _value._second == other._value._second);
00174 }
00175 
00176 bool O3DBIDate::operator!=(const O3DBIDate& other) const
00177 {
00178     return (! ((*this) == other));
00179 }
00180 
00181 bool O3DBIDate::operator>=(const O3DBIDate& other) const
00182 {
00183     if (_value._year < other._value._year)
00184         return false;
00185     if (_value._month < other._value._month)
00186         return false;
00187     if (_value._day < other._value._day)
00188         return false;
00189     if (_value._hour < other._value._hour)
00190         return false;
00191     if (_value._minute < other._value._minute)
00192         return false;
00193     if (_value._second < other._value._second)
00194         return false;
00195     return true;
00196 }
00197 
00198 bool O3DBIDate::operator>(const O3DBIDate& other) const
00199 {
00200     if (_value._year > other._value._year)
00201         return true;
00202     if (_value._year < other._value._year)
00203         return false;
00204     if (_value._month > other._value._month)
00205         return true;
00206     if (_value._month < other._value._month)
00207         return false;
00208     if (_value._day > other._value._day)
00209         return true;
00210     if (_value._day < other._value._day)
00211         return false;
00212     if (_value._hour > other._value._hour)
00213         return true;
00214     if (_value._hour < other._value._hour)
00215         return false;
00216     if (_value._minute > other._value._minute)
00217         return true;
00218     if (_value._minute < other._value._minute)
00219         return false;
00220     if (_value._second > other._value._second)
00221         return true;
00222     return false;
00223 }
00224 
00225 bool O3DBIDate::operator<(const O3DBIDate& other) const
00226 {
00227     if (_value._year < other._value._year)
00228         return true;
00229     if (_value._year > other._value._year)
00230         return false;
00231     if (_value._month < other._value._month)
00232         return true;
00233     if (_value._month > other._value._month)
00234         return false;
00235     if (_value._day < other._value._day)
00236         return true;
00237     if (_value._day > other._value._day)
00238         return false;
00239     if (_value._hour < other._value._hour)
00240         return true;
00241     if (_value._hour > other._value._hour)
00242         return false;
00243     if (_value._minute < other._value._minute)
00244         return true;
00245     if (_value._minute > other._value._minute)
00246         return false;
00247     if (_value._second < other._value._second)
00248         return true;
00249     return false;
00250 }
00251 
00252 bool O3DBIDate::operator<=(const O3DBIDate& other) const
00253 {
00254     if (_value._year > other._value._year)
00255         return false;
00256     if (_value._month > other._value._month)
00257         return false;
00258     if (_value._day > other._value._day)
00259         return false;
00260     if (_value._hour > other._value._hour)
00261         return false;
00262     if (_value._minute > other._value._minute)
00263         return false;
00264     if (_value._second > other._value._second)
00265         return false;
00266     return true;
00267 }
00268 
00269 // ----------------------------------------------------------------------------
00270 // O3DBIDate public interface
00271 
00272 bool O3DBIDate::IsLeapYear() const
00273 {
00274     if (_value._year < 1600)
00275     {
00276         // Until 1600: a leap year is a year, which is divisible by 4
00277         return ((_value._year % 4) == 0);
00278     } else {
00279         // Since 1600: leap years are years divisible by 4, excluding years
00280         // divisible by 100, but including years divisible by 400
00281         if ((_value._year % 400) == 0)
00282             return true;
00283         else if ((_value._year % 100) == 0)
00284             return false;
00285         else if ((_value._year % 4) == 0)
00286             return true;
00287     }
00288     return false;
00289 }
00290 
00291 int O3DBIDate::GetYear() const
00292 {
00293     return _value._year;
00294 }
00295 
00296 void O3DBIDate::SetYear(int year)
00297 {
00298     if (year < O3DBI_DATE_YEAR_MIN || year > O3DBI_DATE_YEAR_MAX)
00299         throw new O3DBIException(O3DBI_VALUE_OUTOFRANGE,
00300         O3DBIErrorTxt::pchValueOutOfRange, _T("O3DBIDate::SetYear"), this);
00301     _value._year = year;
00302     if (JumpFromJulianToGregorian())
00303         _value._day = 15;   // Adjust date
00304 }
00305 
00306 int O3DBIDate::GetMonth() const
00307 {
00308     return _value._month;
00309 }
00310 
00311 void O3DBIDate::SetMonth(int month)
00312 {
00313     if (month < O3DBI_DATE_MONTH_MIN || month > O3DBI_DATE_MONTH_MAX)
00314         throw new O3DBIException(O3DBI_VALUE_OUTOFRANGE,
00315         O3DBIErrorTxt::pchValueOutOfRange, _T("O3DBIDate::SetMonth"), this);
00316     _value._month = month;
00317     if (JumpFromJulianToGregorian())
00318         _value._day = 15;   // Adjust date
00319 }
00320 
00321 int O3DBIDate::GetDay() const
00322 {
00323     return _value._day;
00324 }
00325 
00326 void O3DBIDate::SetDay(int day)
00327 {
00328     if (day < O3DBI_DATE_DAY_MIN || day > O3DBI_DATE_DAY_MAX)
00329         throw new O3DBIException(O3DBI_VALUE_OUTOFRANGE,
00330         O3DBIErrorTxt::pchValueOutOfRange, _T("O3DBIDate::SetDay"), this);
00331     _value._day = day;
00332     if (JumpFromJulianToGregorian())
00333         _value._day = 15;   // Adjust date
00334 }
00335 
00336 int O3DBIDate::GetHour() const
00337 {
00338     return _value._hour;
00339 }
00340 
00341 void O3DBIDate::SetHour(int hour)
00342 {
00343     if (hour < O3DBI_DATE_HOUR_MIN || hour > O3DBI_DATE_HOUR_MAX)
00344         throw new O3DBIException(O3DBI_VALUE_OUTOFRANGE,
00345         O3DBIErrorTxt::pchValueOutOfRange, _T("O3DBIDate::SetHour"), this);
00346     _value._hour = hour;
00347 }
00348 
00349 int O3DBIDate::GetMinute() const
00350 {
00351     return _value._minute;
00352 }
00353 
00354 void O3DBIDate::SetMinute(int minute)
00355 {
00356     if (minute < O3DBI_DATE_MINUTE_MIN || minute > O3DBI_DATE_MINUTE_MAX)
00357         throw new O3DBIException(O3DBI_VALUE_OUTOFRANGE,
00358         O3DBIErrorTxt::pchValueOutOfRange, _T("O3DBIDate::SetMinute"), this);
00359     _value._minute = minute;
00360 }
00361 
00362 int O3DBIDate::GetSecond() const
00363 {
00364     return _value._second;
00365 }
00366 
00367 void O3DBIDate::SetSecond(int second)
00368 {
00369     if (second < O3DBI_DATE_SECOND_MIN || second > O3DBI_DATE_SECOND_MAX)
00370         throw new O3DBIException(O3DBI_VALUE_OUTOFRANGE,
00371         O3DBIErrorTxt::pchValueOutOfRange, _T("O3DBIDate::SetSecond"), this);
00372     _value._second = second;
00373 }
00374 
00375 unsigned short O3DBIDate::GetDayOfWeek() const
00376 {
00377     return ((static_cast<int>(GetJulianDay() % 7L) + 1) % 7);
00378 }
00379 
00380 int O3DBIDate::GetDayOfYear() const
00381 {
00382     int iDay = _value._day;
00383     int iMonth = _value._month;
00384     
00385     while (iMonth > 1)
00386     {
00387         --iMonth;
00388         iDay += _arrDaysInMonth[iMonth];
00389         if (IsLeapYear() && iMonth == 2)
00390             ++iDay;
00391     }
00392     return iDay;
00393 }
00394 
00395 int O3DBIDate::GetCalendarWeek() const
00396 {
00397     const O3DBIDate date1stJanuary(_value._year, 1, 1, 0, 0, 0);
00398     int iWeekdayOf1stJanuary = date1stJanuary.GetDayOfWeek() - 1;
00399     int iDayOfYear = GetDayOfYear();
00400 
00401     if (iWeekdayOf1stJanuary >= 4) 
00402         iWeekdayOf1stJanuary -= 7;
00403     
00404     if ((iDayOfYear + iWeekdayOf1stJanuary) <= 0)
00405     {
00406         // Special case: The year starts with a CW of previous year
00407         O3DBIDate datePrevDay(_value._year - 1, 12, 31, 0, 0, 0);
00408         return datePrevDay.GetCalendarWeek();
00409     }
00410 
00411     short iCalendarWeek = ((iDayOfYear - 1 + iWeekdayOf1stJanuary) / 7) + 1;
00412     // Only years starting with a Thursday have 53 CWs
00413     if ((iCalendarWeek == 53) && (iWeekdayOf1stJanuary != 3))
00414         return 1;
00415     return iCalendarWeek;
00416 }
00417 
00418 long O3DBIDate::GetJulianDay() const
00419 {
00420     int year = _value._year;
00421     int month = _value._month;
00422     int day = _value._day;
00423 
00424     int a;
00425     int b = 0;
00426     float fYearCorrection;
00427 
00428     if (year < 0)
00429         ++year;
00430     fYearCorrection = (year > 0) ? 0.0 : 0.75;
00431     if (month <= 2)
00432     {
00433         --year;
00434         month += 12;
00435     }
00436 
00437     if ((year * 10000.0 + month * 100.0 + day) >= 15821015.0)
00438     {
00439         a = year / 100;
00440         b = 2 - a + a / 4;
00441     }
00442     return (static_cast<long>(365.25 * year - fYearCorrection) +
00443         static_cast<long>(30.6001 * (month + 1)) + day + 1720995L + b);
00444 }
00445 
00446 TO3DBIString O3DBIDate::GetAsString(PC_TCHAR pchFormat /* = NULL */) const
00447 {
00448     if (pchFormat != NULL && ::_tcslen(pchFormat) > MAX_TIME_FORMAT_SIZE)
00449         throw new O3DBIException(O3DBI_VALUE_FORMATSTRINGSIZE,
00450         O3DBIErrorTxt::pchValueFormatStringSize, _T("O3DBIDate::GetAsString"),
00451         this);
00452 
00453     _TCHAR buffer[MAX_TIME_BUFFER_SIZE];
00454     ::memset(&buffer, 0, MAX_TIME_BUFFER_SIZE * sizeof(_TCHAR));
00455     
00456     tm tmTemp;
00457     tmTemp.tm_year = _value._year - 1900;
00458     tmTemp.tm_mon = _value._month - 1;
00459     tmTemp.tm_mday = _value._day;
00460     tmTemp.tm_hour = _value._hour;
00461     tmTemp.tm_min = _value._minute;
00462     tmTemp.tm_sec = _value._second;
00463     tmTemp.tm_wday = GetDayOfWeek();
00464     tmTemp.tm_yday = GetDayOfYear();
00465     tmTemp.tm_isdst = 0;
00466 
00467     if (pchFormat != NULL)
00468     {
00469         int iResult =
00470             ::_tcsftime(buffer, MAX_TIME_BUFFER_SIZE, pchFormat, &tmTemp);
00471         if (iResult == 0)
00472             ::_tcsncpy(buffer, _T("### DATE ###"), 13);
00473         return TO3DBIString(buffer);
00474     } else {
00475         return TO3DBIString(::_tasctime(&tmTemp));
00476     }
00477 }
00478 
00479 TO3DBIString O3DBIDate::ToString() const
00480 {
00481     _TCHAR buffer[LARGESTRING_BUFFERSIZE];
00482     int p;
00483 
00484     p = ::_stprintf(buffer, _T("O3DBIDate at 0x%x\n"), this);
00485     ::_stprintf(buffer + p, _T("\tValue: %s"),
00486         GetAsString(_T("%Y-%m-%d %H:%M:%S (%A)")).c_str());
00487 
00488     return TO3DBIString(buffer);
00489 }
00490 
00491 // ----------------------------------------------------------------------------
00492 // O3DBIDate internal implementation
00493 
00494 // Checks whether the date is inside the valid range.
00495 bool O3DBIDate::RangeCheck() const
00496 {
00497     if (_value._year < O3DBI_DATE_YEAR_MIN ||
00498         _value._year > O3DBI_DATE_YEAR_MAX ||
00499         _value._month < O3DBI_DATE_MONTH_MIN ||
00500         _value._month > O3DBI_DATE_MONTH_MAX)
00501         return false;
00502 
00503     int iDay = (_arrDaysInMonth[_value._month] + (IsLeapYear() ? 1 : 0));
00504 
00505     if (_value._day < O3DBI_DATE_DAY_MIN ||
00506         _value._day >  iDay ||
00507         _value._hour < O3DBI_DATE_HOUR_MIN ||
00508         _value._hour > O3DBI_DATE_HOUR_MAX ||
00509         _value._minute < O3DBI_DATE_MINUTE_MIN ||
00510         _value._minute > O3DBI_DATE_MINUTE_MAX ||
00511         _value._second < O3DBI_DATE_SECOND_MIN ||
00512         _value._second > O3DBI_DATE_SECOND_MAX)
00513         return false;
00514     return true;
00515 }
00516 
00517 // Calendar reform: the papal bull of February 1582 decreed that 10 days should
00518 // be dropped from October 1582 so that 15 October should follow immediately
00519 // after 4 October, and from then on the reformed (Gregorian) calendar should
00520 // be used.
00521 bool O3DBIDate::JumpFromJulianToGregorian() const
00522 {
00523     if (_value._year == 1582 && _value._month == 10)
00524         return (_value._day > 4 && _value._day < 15);
00525     return false;
00526 }
00527 



SourceForge.net Logo Generated on Sun Jan 23 11:36:34 2005 for Oracle Object Oriented Database Interface (O3DBI) by  doxygen 1.3.9.1