| 1 | /* |
| 2 | * Legal Notice |
| 3 | * |
| 4 | * This document and associated source code (the "Work") is a part of a |
| 5 | * benchmark specification maintained by the TPC. |
| 6 | * |
| 7 | * The TPC reserves all right, title, and interest to the Work as provided |
| 8 | * under U.S. and international laws, including without limitation all patent |
| 9 | * and trademark rights therein. |
| 10 | * |
| 11 | * No Warranty |
| 12 | * |
| 13 | * 1.1 TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THE INFORMATION |
| 14 | * CONTAINED HEREIN IS PROVIDED "AS IS" AND WITH ALL FAULTS, AND THE |
| 15 | * AUTHORS AND DEVELOPERS OF THE WORK HEREBY DISCLAIM ALL OTHER |
| 16 | * WARRANTIES AND CONDITIONS, EITHER EXPRESS, IMPLIED OR STATUTORY, |
| 17 | * INCLUDING, BUT NOT LIMITED TO, ANY (IF ANY) IMPLIED WARRANTIES, |
| 18 | * DUTIES OR CONDITIONS OF MERCHANTABILITY, OF FITNESS FOR A PARTICULAR |
| 19 | * PURPOSE, OF ACCURACY OR COMPLETENESS OF RESPONSES, OF RESULTS, OF |
| 20 | * WORKMANLIKE EFFORT, OF LACK OF VIRUSES, AND OF LACK OF NEGLIGENCE. |
| 21 | * ALSO, THERE IS NO WARRANTY OR CONDITION OF TITLE, QUIET ENJOYMENT, |
| 22 | * QUIET POSSESSION, CORRESPONDENCE TO DESCRIPTION OR NON-INFRINGEMENT |
| 23 | * WITH REGARD TO THE WORK. |
| 24 | * 1.2 IN NO EVENT WILL ANY AUTHOR OR DEVELOPER OF THE WORK BE LIABLE TO |
| 25 | * ANY OTHER PARTY FOR ANY DAMAGES, INCLUDING BUT NOT LIMITED TO THE |
| 26 | * COST OF PROCURING SUBSTITUTE GOODS OR SERVICES, LOST PROFITS, LOSS |
| 27 | * OF USE, LOSS OF DATA, OR ANY INCIDENTAL, CONSEQUENTIAL, DIRECT, |
| 28 | * INDIRECT, OR SPECIAL DAMAGES WHETHER UNDER CONTRACT, TORT, WARRANTY, |
| 29 | * OR OTHERWISE, ARISING IN ANY WAY OUT OF THIS OR ANY OTHER AGREEMENT |
| 30 | * RELATING TO THE WORK, WHETHER OR NOT SUCH AUTHOR OR DEVELOPER HAD |
| 31 | * ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. |
| 32 | * |
| 33 | * Contributors |
| 34 | * - Charles Levine |
| 35 | */ |
| 36 | |
| 37 | #include "utilities/DateTime.h" |
| 38 | |
| 39 | #include <stdio.h> |
| 40 | #include <stdexcept> |
| 41 | #include <chrono> |
| 42 | |
| 43 | // DJ: perhaps all unixes need this so maybe we want #ifndef WIN32 or something |
| 44 | // like that? |
| 45 | #if (__unix) || (_AIX) |
| 46 | #include <sys/time.h> // for gettimeofday |
| 47 | #endif |
| 48 | |
| 49 | using namespace TPCE; |
| 50 | |
| 51 | // Initialize static const member arrays. |
| 52 | const INT32 CDateTime::monthArray[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; |
| 53 | const INT32 CDateTime::monthArrayLY[12] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; |
| 54 | const INT32 CDateTime::cumulativeMonthArray[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; |
| 55 | |
| 56 | bool CDateTime::IsLeapYear(INT32 year) { |
| 57 | if ((year % 4) != 0) // only years which are multiples of 4 can be leap years |
| 58 | { |
| 59 | return false; |
| 60 | } |
| 61 | |
| 62 | if ((year % 400) == 0) // years divisible by 400 are leap years |
| 63 | { |
| 64 | return true; |
| 65 | } |
| 66 | |
| 67 | if ((year % 100) == 0) // years divisible by 100 but not 400 are not leap years |
| 68 | { |
| 69 | return false; |
| 70 | } |
| 71 | |
| 72 | // must be a leap year if you get here |
| 73 | return true; |
| 74 | } |
| 75 | |
| 76 | // Checks whether the date/time is valid. |
| 77 | bool CDateTime::IsValid(INT32 year, INT32 month, INT32 day, INT32 hour, INT32 minute, INT32 second, INT32 msec) { |
| 78 | // check all values that have static, absolute bounds |
| 79 | if (hour < minValidHour || maxValidHour < hour || minute < minValidMinute || maxValidMinute < minute || |
| 80 | second < minValidSecond || maxValidSecond < second || msec < minValidMilliSecond || |
| 81 | maxValidMilliSecond < msec || year < minValidYear || maxValidYear < year || month < minValidMonth || |
| 82 | maxValidMonth < month || day < minValidDay) { |
| 83 | return false; |
| 84 | } |
| 85 | |
| 86 | // check the day of the month |
| 87 | // optimize for common case. if check passes, we're done |
| 88 | if (day <= monthArray[month - 1]) { |
| 89 | return true; |
| 90 | } |
| 91 | |
| 92 | // Only one possibility left -- February 29th |
| 93 | // Feb 29th valid only if a leap year; invalid otherwise |
| 94 | if ((month == 2) && (day == 29)) { |
| 95 | return IsLeapYear(year); |
| 96 | } |
| 97 | |
| 98 | // exhausted all possibilities; can't be valid |
| 99 | return false; |
| 100 | } |
| 101 | |
| 102 | // Validate the specified date/time and throw an out_of_range exception if it |
| 103 | // isn't valid. |
| 104 | void CDateTime::Validate(INT32 year, INT32 month, INT32 day, INT32 hour, INT32 minute, INT32 second, INT32 msec) { |
| 105 | if (!IsValid(year, month, day, hour, minute, second, msec)) { |
| 106 | std::ostringstream msg; |
| 107 | msg << "The specified Date/Time is not valid." ; |
| 108 | throw std::out_of_range(msg.str()); |
| 109 | } |
| 110 | } |
| 111 | |
| 112 | // Validate the specified day number and throw an out_of_range exception if it |
| 113 | // isn't valid. |
| 114 | void CDateTime::Validate(INT32 dayNumber) { |
| 115 | if ((dayNumber < minValidDayNumber) || (CalculateDayNumber(maxValidYear, maxValidMonth, maxValidDay) < dayNumber)) { |
| 116 | std::ostringstream msg; |
| 117 | msg << "The specified day-number is not valid." ; |
| 118 | throw std::out_of_range(msg.str()); |
| 119 | } |
| 120 | } |
| 121 | |
| 122 | // Validate a day-number/msec pair. |
| 123 | void CDateTime::Validate(INT32 dayNumber, INT32 msecSoFarToday) { |
| 124 | if ((msecSoFarToday < minValidMilliSecond) || (maxValidMilliSecond < msecSoFarToday) || |
| 125 | (dayNumber < minValidDayNumber) || (CalculateDayNumber(maxValidYear, maxValidMonth, maxValidDay) < dayNumber)) { |
| 126 | std::ostringstream msg; |
| 127 | msg << "The specified (day-number, msec) pair is not valid." ; |
| 128 | throw std::out_of_range(msg.str()); |
| 129 | } |
| 130 | } |
| 131 | |
| 132 | // Computes the number of days since Jan 1, 0001. (Year 1 AD) |
| 133 | // 1-Jan-0001 = 0 |
| 134 | INT32 CDateTime::CalculateDayNumber(INT32 yr, INT32 mm, INT32 dd) { |
| 135 | // compute day of year |
| 136 | INT32 jd = cumulativeMonthArray[mm - 1] + dd - 1; |
| 137 | |
| 138 | // adjust day of year if this is a leap year and it is after February |
| 139 | if ((mm > 2) && IsLeapYear(yr)) { |
| 140 | jd++; |
| 141 | } |
| 142 | |
| 143 | // compute number of days from 1/1/0001 to beginning of present year |
| 144 | yr--; // start counting from year 1 AD (1-based instead of 0-based) |
| 145 | jd += yr / 400 * dy400; |
| 146 | yr %= 400; |
| 147 | jd += yr / 100 * dy100; |
| 148 | yr %= 100; |
| 149 | jd += yr / 4 * dy4; |
| 150 | yr %= 4; |
| 151 | jd += yr * dy1; |
| 152 | |
| 153 | return jd; |
| 154 | } |
| 155 | |
| 156 | INT32 CDateTime::YMDtoDayno(INT32 yr, INT32 mm, INT32 dd) { |
| 157 | // Validate year, month and day (use known safe values for hours - |
| 158 | // milliseconds). |
| 159 | Validate(yr, mm, dd, minValidHour, minValidMinute, minValidSecond, minValidMilliSecond); |
| 160 | |
| 161 | return CalculateDayNumber(yr, mm, dd); |
| 162 | } |
| 163 | |
| 164 | // returns text representation of DateTime |
| 165 | // the style argument is interpreted as a two digit field, where the first digit |
| 166 | // (in the tens place) is the date format and the second digit (in the ones |
| 167 | // place) is the time format. |
| 168 | // |
| 169 | // The following formats are provided: |
| 170 | // STYLE DATE TIME |
| 171 | // ----- ---- ---- |
| 172 | // 0 <omit> <omit> |
| 173 | // 1 YYYY-MM-DD HH:MM:SS (24hr) |
| 174 | // 2 MM/DD/YY HH:MM:SS.mmm (24hr) |
| 175 | // 3 MM/DD/YYYY HH:MM (24hr) |
| 176 | // 4 DD-MON-YYYY HH:MM:SS [AM|PM] |
| 177 | // 5 DD-MON-YY HH:MM:SS.mmm [AM|PM] |
| 178 | // 6 MM-DD-YY HH:MM [AM|PM] |
| 179 | // 7 MON DD YYYY |
| 180 | // 8 Month DD, YYYY |
| 181 | // |
| 182 | char *CDateTime::ToStr(INT32 style = 11) { |
| 183 | static const char *szMonthsShort[] = {"JAN" , "FEB" , "MAR" , "APR" , "MAY" , "JUN" , |
| 184 | "JUL" , "AUG" , "SEP" , "OCT" , "NOV" , "DEC" }; |
| 185 | static const char *szMonthsFull[] = {"January" , "February" , "March" , "April" , "May" , "June" , |
| 186 | "July" , "August" , "September" , "October" , "November" , "December" }; |
| 187 | static const char *szAmPm[] = {"AM" , "PM" }; |
| 188 | // the following array is used to map from 24-hour to 12-hour time |
| 189 | static const INT32 iHr12[] = {12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; |
| 190 | |
| 191 | INT32 year, month, day, hour, minute, second, msec; |
| 192 | INT32 p = 0; |
| 193 | static const INT32 iMaxStrLen = 40; |
| 194 | |
| 195 | if (m_szText == NULL) |
| 196 | m_szText = new char[iMaxStrLen]; |
| 197 | m_szText[0] = '\0'; |
| 198 | |
| 199 | GetYMDHMS(&year, &month, &day, &hour, &minute, &second, &msec); |
| 200 | |
| 201 | size_t lengthTotal = iMaxStrLen; |
| 202 | char *pszText = m_szText; |
| 203 | |
| 204 | // DATE portion |
| 205 | switch (style / 10) { |
| 206 | case 1: |
| 207 | // YYYY-MM-DD |
| 208 | p = snprintf(pszText, lengthTotal, "%04d-%02d-%02d " , year, month, day); |
| 209 | break; |
| 210 | case 2: |
| 211 | // MM/DD/YY |
| 212 | p = snprintf(pszText, lengthTotal, "%02d/%02d/%02d " , month, day, year % 100); |
| 213 | break; |
| 214 | case 3: |
| 215 | // MM/DD/YYYY |
| 216 | p = snprintf(pszText, lengthTotal, "%02d/%02d/%04d " , month, day, year); |
| 217 | break; |
| 218 | case 4: |
| 219 | // DD-MON-YYYY |
| 220 | p = snprintf(pszText, lengthTotal, "%02d-%s-%04d " , day, szMonthsShort[month - 1], year); |
| 221 | break; |
| 222 | case 5: |
| 223 | // DD-MON-YY |
| 224 | p = snprintf(pszText, lengthTotal, "%02d-%s-%02d " , day, szMonthsShort[month - 1], year % 100); |
| 225 | break; |
| 226 | case 6: |
| 227 | // MM-DD-YY |
| 228 | p = snprintf(pszText, lengthTotal, "%02d-%02d-%02d " , month, day, year % 100); |
| 229 | break; |
| 230 | case 7: |
| 231 | // MON DD YYYY |
| 232 | p = snprintf(pszText, lengthTotal, "%s %02d %04d " , szMonthsShort[month - 1], day, year); |
| 233 | break; |
| 234 | case 8: |
| 235 | // Month DD, YYYY |
| 236 | p = snprintf(pszText, lengthTotal, "%s %02d, %04d " , szMonthsFull[month - 1], day, year); |
| 237 | break; |
| 238 | } |
| 239 | |
| 240 | size_t lengthRemaining = lengthTotal - p; |
| 241 | pszText = m_szText + (char)p; |
| 242 | |
| 243 | // TIME portion |
| 244 | switch (style % 10) { |
| 245 | case 1: |
| 246 | // HH:MM:SS (24hr) |
| 247 | p += snprintf(pszText, lengthRemaining, "%02d:%02d:%02d" , hour, minute, second); |
| 248 | break; |
| 249 | case 2: |
| 250 | // HH:MM:SS.mmm (24hr) |
| 251 | p += snprintf(pszText, lengthRemaining, "%02d:%02d:%02d.%03d" , hour, minute, second, msec); |
| 252 | break; |
| 253 | case 3: |
| 254 | // HH:MM (24hr) |
| 255 | p += snprintf(pszText, lengthRemaining, "%02d:%02d" , hour, minute); |
| 256 | break; |
| 257 | case 4: |
| 258 | // HH:MM:SS [AM|PM] |
| 259 | p += snprintf(pszText, lengthRemaining, "%02d:%02d:%02d %s" , iHr12[hour], minute, second, szAmPm[hour / 12]); |
| 260 | break; |
| 261 | case 5: |
| 262 | // HHH:MM:SS.mmm [AM|PM] |
| 263 | p += snprintf(pszText, lengthRemaining, "%02d:%02d:%02d.%03d %s" , iHr12[hour], minute, second, msec, |
| 264 | szAmPm[hour / 12]); |
| 265 | break; |
| 266 | case 6: |
| 267 | // HH:MM [AM|PM] |
| 268 | p += snprintf(pszText, lengthRemaining, "%02d:%02d %s" , iHr12[hour], minute, szAmPm[hour / 12]); |
| 269 | break; |
| 270 | } |
| 271 | |
| 272 | // trim trailing blank, if there is one. |
| 273 | if (p > 0 && m_szText[p - 1] == ' ') |
| 274 | m_szText[p - 1] = '\0'; |
| 275 | |
| 276 | return m_szText; |
| 277 | } |
| 278 | |
| 279 | // set to current local time |
| 280 | CDateTime::CDateTime(void) { |
| 281 | m_szText = NULL; |
| 282 | Set(); |
| 283 | } |
| 284 | |
| 285 | CDateTime::CDateTime(INT32 dayno) { |
| 286 | Validate(dayno); |
| 287 | m_szText = NULL; |
| 288 | m_dayno = dayno; |
| 289 | m_msec = 0; |
| 290 | } |
| 291 | |
| 292 | CDateTime::CDateTime(INT32 year, INT32 month, INT32 day) { |
| 293 | Validate(year, month, day, minValidHour, minValidMinute, minValidSecond, minValidMilliSecond); |
| 294 | m_dayno = CalculateDayNumber(year, month, day); |
| 295 | m_szText = NULL; |
| 296 | m_msec = 0; |
| 297 | } |
| 298 | |
| 299 | // Copy constructor |
| 300 | CDateTime::CDateTime(const CDateTime &dt) { |
| 301 | // Assume source is valid. |
| 302 | // Validate( dt.m_dayno, dt.m_msec ); |
| 303 | m_dayno = dt.m_dayno; |
| 304 | m_msec = dt.m_msec; |
| 305 | m_szText = NULL; |
| 306 | } |
| 307 | |
| 308 | CDateTime::~CDateTime(void) { |
| 309 | if (m_szText) |
| 310 | delete[] m_szText; |
| 311 | } |
| 312 | |
| 313 | CDateTime::CDateTime(INT32 year, INT32 month, INT32 day, INT32 hour, INT32 minute, INT32 second, INT32 msec) { |
| 314 | // Validate specified date/time |
| 315 | Validate(year, month, day, hour, minute, second, msec); |
| 316 | |
| 317 | m_szText = NULL; |
| 318 | m_dayno = CalculateDayNumber(year, month, day); |
| 319 | m_msec = ((hour * MinutesPerHour + minute) * SecondsPerMinute + second) * MsPerSecond + msec; |
| 320 | } |
| 321 | |
| 322 | CDateTime::CDateTime(TPCE::TIMESTAMP_STRUCT *ts) { |
| 323 | Validate(ts->year, ts->month, ts->day, ts->hour, ts->minute, ts->second, ts->fraction / 1000000); |
| 324 | |
| 325 | m_szText = NULL; |
| 326 | m_dayno = CalculateDayNumber(ts->year, ts->month, ts->day); |
| 327 | m_msec = ((ts->hour * MinutesPerHour + ts->minute) * SecondsPerMinute + ts->second) * MsPerSecond + |
| 328 | ts->fraction / 1000000; |
| 329 | } |
| 330 | |
| 331 | // set to current local time |
| 332 | void CDateTime::Set(void) { |
| 333 | // assert(0); // why is this necessary? |
| 334 | // //UNIX-specific code to get the current time with 1ms resolution |
| 335 | // struct timeval tv; |
| 336 | // struct tm ltr; |
| 337 | // int secs; |
| 338 | // gettimeofday(&tv, NULL); |
| 339 | // struct tm* lt = localtime_r(&tv.tv_sec, <r); //expand into |
| 340 | // year/month/day/... |
| 341 | // // NOTE: 1 is added to tm_mon because it is 0 based, but |
| 342 | // CalculateDayNumber expects it to |
| 343 | // // be 1 based. |
| 344 | // m_dayno = CalculateDayNumber(lt->tm_year+1900, lt->tm_mon+1, |
| 345 | // lt->tm_mday); // tm_year is based on 1900, not 0. |
| 346 | |
| 347 | // secs = (lt->tm_hour * MinutesPerHour + lt->tm_min)*SecondsPerMinute + |
| 348 | // lt->tm_sec; |
| 349 | // m_msec = static_cast<INT32>((long)secs * MsPerSecond + tv.tv_usec / |
| 350 | // 1000); |
| 351 | } |
| 352 | |
| 353 | void CDateTime::Set(INT32 dayno) { |
| 354 | Validate(dayno); |
| 355 | m_dayno = dayno; |
| 356 | m_msec = 0; |
| 357 | } |
| 358 | |
| 359 | void CDateTime::Set(INT32 year, INT32 month, INT32 day) { |
| 360 | Validate(year, month, day, minValidHour, minValidMinute, minValidSecond, minValidMilliSecond); |
| 361 | |
| 362 | m_dayno = CalculateDayNumber(year, month, day); |
| 363 | m_msec = 0; |
| 364 | } |
| 365 | |
| 366 | void CDateTime::Set(INT32 hour, INT32 minute, INT32 second, INT32 msec) { |
| 367 | Validate(minValidYear, minValidMonth, minValidDay, hour, minute, second, msec); |
| 368 | |
| 369 | m_msec = ((hour * MinutesPerHour + minute) * SecondsPerMinute + second) * MsPerSecond + msec; |
| 370 | } |
| 371 | |
| 372 | void CDateTime::Set(INT32 year, INT32 month, INT32 day, INT32 hour, INT32 minute, INT32 second, INT32 msec) { |
| 373 | Validate(year, month, day, hour, minute, second, msec); |
| 374 | |
| 375 | m_dayno = CalculateDayNumber(year, month, day); |
| 376 | m_msec = ((hour * MinutesPerHour + minute) * SecondsPerMinute + second) * MsPerSecond + msec; |
| 377 | } |
| 378 | |
| 379 | // DaynoToYMD converts a day index to |
| 380 | // its corresponding calendar value (mm/dd/yr). The valid range for days |
| 381 | // is { 0 .. ~3.65M } for dates from 1-Jan-0001 to 31-Dec-9999. |
| 382 | void CDateTime::GetYMD(INT32 *year, INT32 *month, INT32 *day) { |
| 383 | INT32 dayno = m_dayno; |
| 384 | |
| 385 | // local variables |
| 386 | INT32 y, m; |
| 387 | |
| 388 | y = 1; // based on year 1 AD |
| 389 | y += (dayno / dy400) * 400; |
| 390 | dayno %= dy400; |
| 391 | if (dayno == dy400 - 1) // special case for last day of 400-year leap-year |
| 392 | { |
| 393 | y += 399; |
| 394 | dayno -= 3 * dy100 + 24 * dy4 + 3 * dy1; |
| 395 | } else { |
| 396 | y += (dayno / dy100) * 100; |
| 397 | dayno %= dy100; |
| 398 | y += (dayno / dy4) * 4; |
| 399 | dayno %= dy4; |
| 400 | if (dayno == dy4 - 1) // special case for last day of 4-year leap-year |
| 401 | { |
| 402 | y += 3; |
| 403 | dayno -= 3 * dy1; |
| 404 | } else { |
| 405 | y += dayno / dy1; |
| 406 | dayno %= dy1; |
| 407 | } |
| 408 | } |
| 409 | |
| 410 | m = 1; |
| 411 | dayno++; |
| 412 | if (IsLeapYear(y)) { |
| 413 | while (dayno > monthArrayLY[m - 1]) { |
| 414 | dayno -= monthArrayLY[m - 1]; |
| 415 | m++; |
| 416 | } |
| 417 | } else { |
| 418 | while (dayno > monthArray[m - 1]) { |
| 419 | dayno -= monthArray[m - 1]; |
| 420 | m++; |
| 421 | } |
| 422 | } |
| 423 | |
| 424 | *year = y; |
| 425 | *month = m; |
| 426 | *day = dayno; |
| 427 | } |
| 428 | |
| 429 | void CDateTime::GetYMDHMS(INT32 *year, INT32 *month, INT32 *day, INT32 *hour, INT32 *minute, INT32 *second, |
| 430 | INT32 *msec) { |
| 431 | GetYMD(year, month, day); |
| 432 | GetHMS(hour, minute, second, msec); |
| 433 | } |
| 434 | |
| 435 | void CDateTime::GetHMS(INT32 *hour, INT32 *minute, INT32 *second, INT32 *msec) { |
| 436 | INT32 ms = m_msec; |
| 437 | |
| 438 | *msec = ms % MsPerSecond; |
| 439 | ms /= MsPerSecond; |
| 440 | *second = ms % SecondsPerMinute; |
| 441 | ms /= SecondsPerMinute; |
| 442 | *minute = ms % MinutesPerHour; |
| 443 | *hour = ms / MinutesPerHour; |
| 444 | } |
| 445 | |
| 446 | void CDateTime::GetTimeStamp(TPCE::TIMESTAMP_STRUCT *ts) { |
| 447 | INT32 year, month, day, hour, minute, second, msec; |
| 448 | |
| 449 | GetYMDHMS(&year, &month, &day, &hour, &minute, &second, &msec); |
| 450 | ts->year = (INT16)year; |
| 451 | ts->month = (UINT16)month; |
| 452 | ts->day = (UINT16)day; |
| 453 | ts->hour = (UINT16)hour; |
| 454 | ts->minute = (UINT16)minute; |
| 455 | ts->second = (UINT16)second; |
| 456 | ts->fraction = (UINT32)msec * 1000000; // because "fraction" is 1/billion'th of a second |
| 457 | } |
| 458 | |
| 459 | #ifdef COMPILE_ODBC_LOAD |
| 460 | static const INT32 dayno_1Jan1900 = CDateTime::YMDtoDayno(1900, 1, 1); |
| 461 | |
| 462 | void CDateTime::GetDBDATETIME(DBDATETIME *dt) { |
| 463 | dt->dtdays = m_dayno - dayno_1Jan1900; |
| 464 | dt->dttime = m_msec * 3 / 10; |
| 465 | } |
| 466 | #endif // COMPILE_ODBC_LOAD |
| 467 | |
| 468 | void CDateTime::Add(INT32 days, INT32 msec, bool adjust_weekend /* =false */) { |
| 469 | if (adjust_weekend) { |
| 470 | days = ((days / DaysPerWorkWeek) * DaysPerWeek) + (days % DaysPerWorkWeek); |
| 471 | } |
| 472 | |
| 473 | m_dayno += days; |
| 474 | |
| 475 | m_msec += msec; |
| 476 | m_dayno += m_msec / MsPerDay; |
| 477 | m_msec %= MsPerDay; |
| 478 | if (m_msec < 0) { |
| 479 | m_dayno--; |
| 480 | m_msec += MsPerDay; |
| 481 | } |
| 482 | } |
| 483 | void CDateTime::AddMinutes(INT32 Minutes) { |
| 484 | Add(0, Minutes * SecondsPerMinute * MsPerSecond); |
| 485 | } |
| 486 | void CDateTime::AddWorkMs(INT64 WorkMs) { |
| 487 | INT32 WorkDays = (INT32)(WorkMs / (INT64)MsPerWorkDay); |
| 488 | Add(WorkDays, (INT32)(WorkMs % MsPerWorkDay), true); |
| 489 | } |
| 490 | bool CDateTime::operator<(const CDateTime &dt) { |
| 491 | return (m_dayno == dt.m_dayno) ? (m_msec < dt.m_msec) : (m_dayno < dt.m_dayno); |
| 492 | } |
| 493 | |
| 494 | bool CDateTime::operator<=(const CDateTime &dt) { |
| 495 | return (m_dayno == dt.m_dayno) ? (m_msec <= dt.m_msec) : (m_dayno <= dt.m_dayno); |
| 496 | } |
| 497 | |
| 498 | namespace TPCE { |
| 499 | |
| 500 | // Need const reference left argument for greater<CDateTime> comparison function |
| 501 | bool operator>(const CDateTime &l_dt, const CDateTime &r_dt) { |
| 502 | return (l_dt.m_dayno == r_dt.m_dayno) ? (l_dt.m_msec > r_dt.m_msec) : (l_dt.m_dayno > r_dt.m_dayno); |
| 503 | } |
| 504 | |
| 505 | } // namespace TPCE |
| 506 | |
| 507 | bool CDateTime::operator>=(const CDateTime &dt) { |
| 508 | return (m_dayno == dt.m_dayno) ? (m_msec >= dt.m_msec) : (m_dayno >= dt.m_dayno); |
| 509 | } |
| 510 | |
| 511 | bool CDateTime::operator==(const CDateTime &dt) { |
| 512 | return m_dayno == dt.m_dayno ? m_msec == dt.m_msec : false; |
| 513 | } |
| 514 | |
| 515 | // compute the difference between two DateTimes; |
| 516 | // result in seconds |
| 517 | double CDateTime::operator-(const CDateTime &dt) { |
| 518 | double dSecs; |
| 519 | dSecs = (double)((m_dayno - dt.m_dayno) * SecondsPerMinute * MinutesPerHour * HoursPerDay); |
| 520 | dSecs += (double)(m_msec - dt.m_msec) / MsPerSecondDivisor; |
| 521 | return dSecs; |
| 522 | } |
| 523 | |
| 524 | INT32 CDateTime::DiffInMilliSeconds(const CDateTime &BaseTime) { |
| 525 | INT32 mSecs; |
| 526 | mSecs = (m_dayno - BaseTime.m_dayno) * MsPerSecond * SecondsPerMinute * MinutesPerHour * HoursPerDay; |
| 527 | mSecs += (m_msec - BaseTime.m_msec); |
| 528 | return mSecs; |
| 529 | } |
| 530 | |
| 531 | INT32 CDateTime::DiffInMilliSeconds(CDateTime *pBaseTime) { |
| 532 | INT32 mSecs; |
| 533 | mSecs = (m_dayno - pBaseTime->m_dayno) * MsPerSecond * SecondsPerMinute * MinutesPerHour * HoursPerDay; |
| 534 | mSecs += (m_msec - pBaseTime->m_msec); |
| 535 | return mSecs; |
| 536 | } |
| 537 | |
| 538 | CDateTime &CDateTime::operator=(const CDateTime &dt) { |
| 539 | // Assume source is valid. |
| 540 | // Validate( dt.m_dayno, dt.m_msec ); |
| 541 | m_dayno = dt.m_dayno; |
| 542 | m_msec = dt.m_msec; |
| 543 | |
| 544 | return *this; |
| 545 | } |
| 546 | |
| 547 | CDateTime &CDateTime::operator+=(const CDateTime &dt) { |
| 548 | Add(dt.m_dayno, dt.m_msec); |
| 549 | |
| 550 | return *this; |
| 551 | } |
| 552 | |