| 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 | * Gradient Systems |
| 35 | */ |
| 36 | |
| 37 | /*** includes ***/ |
| 38 | #include "config.h" |
| 39 | #include "porting.h" |
| 40 | #include <stdlib.h> |
| 41 | #ifndef USE_STDLIB_H |
| 42 | #include <malloc.h> |
| 43 | #endif |
| 44 | #include <stdio.h> |
| 45 | #include <math.h> |
| 46 | #include "date.h" |
| 47 | #include "mathops.h" |
| 48 | #include "dist.h" |
| 49 | |
| 50 | #define D_CHARS "ymdYMD24" /* valid characters in a DBGDATE setting */ |
| 51 | #define MIN_DATE_INT 18000101 |
| 52 | |
| 53 | static int m_days[2][13] = {{0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}, |
| 54 | {0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335}}; |
| 55 | static char *qtr_start[5] = {NULL, "01-01" , "04-01" , "07-01" , "10-01" }; |
| 56 | char *weekday_names[8] = {NULL, "Sunday" , "Monday" , "Tuesday" , "Wednesday" , "Thursday" , "Friday" , "Saturday" }; |
| 57 | /* |
| 58 | * Routine: mk_date(void) |
| 59 | * Purpose: initialize a date_t |
| 60 | * Algorithm: |
| 61 | * Data Structures: |
| 62 | * Params: |
| 63 | * Returns: date_t * |
| 64 | * Called By: |
| 65 | * Calls: |
| 66 | * Assumptions: |
| 67 | * Side Effects: |
| 68 | * TODO: None |
| 69 | */ |
| 70 | date_t *mk_date(void) { |
| 71 | date_t *res; |
| 72 | |
| 73 | res = (date_t *)malloc(sizeof(struct DATE_T)); |
| 74 | MALLOC_CHECK(res); |
| 75 | |
| 76 | res->flags = 0; |
| 77 | res->year = 0; |
| 78 | res->month = 0; |
| 79 | res->day = 0; |
| 80 | res->julian = 0; |
| 81 | |
| 82 | return (res); |
| 83 | } |
| 84 | /* |
| 85 | * Routine: strtotime(char *str) |
| 86 | * Purpose: convert a string from the time to the number of seconds since |
| 87 | * midnight Algorithm: Data Structures: Params: Returns: int Called By: Calls: |
| 88 | * Assumptions: |
| 89 | * Side Effects: |
| 90 | * TODO: None |
| 91 | */ |
| 92 | int strtotime(char *str) { |
| 93 | int hour, min, sec, res; |
| 94 | |
| 95 | if (sscanf(str, "%d:%d:%d" , &hour, &min, &sec) != 3) { |
| 96 | if (sscanf(str, "%d:%d" , &hour, &min) != 2) { |
| 97 | INTERNAL("Invalid time format" ); |
| 98 | } |
| 99 | sec = 0; |
| 100 | } |
| 101 | |
| 102 | if (hour > 23 || hour < 0) |
| 103 | INTERNAL("Invalid time format" ); |
| 104 | if (min > 59 || min < 0) |
| 105 | INTERNAL("Invalid time format" ); |
| 106 | if (sec > 59 || sec < 0) |
| 107 | INTERNAL("Invalid time format" ); |
| 108 | |
| 109 | res = hour * 3600 + min * 60 + sec; |
| 110 | |
| 111 | return (res); |
| 112 | } |
| 113 | |
| 114 | /* |
| 115 | * Routine: jtodt(int src, date_t *dest) |
| 116 | * Purpose: convert a number of julian days to a date_t |
| 117 | * Algorithm: Fleigel and Van Flandern (CACM, vol 11, #10, Oct. 1968, p. 657) |
| 118 | * Data Structures: |
| 119 | * |
| 120 | * Params: source integer: days since big bang |
| 121 | * Returns: date_t *; NULL on failure |
| 122 | * Called By: |
| 123 | * Calls: |
| 124 | * Assumptions: |
| 125 | * Side Effects: |
| 126 | * TODO: |
| 127 | */ |
| 128 | int jtodt(date_t *dest, int src) { |
| 129 | long i, j, l, n; |
| 130 | |
| 131 | if (src < 0) |
| 132 | return (-1); |
| 133 | |
| 134 | dest->julian = src; |
| 135 | l = src + 68569; |
| 136 | n = (int)floor((4 * l) / 146097); |
| 137 | l = l - (int)floor((146097 * n + 3) / 4); |
| 138 | i = (int)floor((4000 * (l + 1) / 1461001)); |
| 139 | l = l - (int)floor((1461 * i) / 4) + 31; |
| 140 | j = (int)floor((80 * l) / 2447); |
| 141 | dest->day = l - (int)floor((2447 * j) / 80); |
| 142 | l = (int)floor(j / 11); |
| 143 | dest->month = j + 2 - 12 * l; |
| 144 | dest->year = 100 * (n - 49) + i + l; |
| 145 | |
| 146 | return (0); |
| 147 | } |
| 148 | |
| 149 | /* |
| 150 | * Routine: dttoj(date_t *) |
| 151 | * Purpose: convert a date_t to a number of julian days |
| 152 | * Algorithm: http://quasar.as.utexas.edu/BillInfo/JulianDatesG.html |
| 153 | * Data Structures: |
| 154 | * |
| 155 | * Params: |
| 156 | * Returns: |
| 157 | * Called By: |
| 158 | * Calls: |
| 159 | * Assumptions: |
| 160 | * Side Effects: |
| 161 | * TODO: None |
| 162 | */ |
| 163 | int dttoj(date_t *dt) { |
| 164 | int y, m, res; |
| 165 | |
| 166 | y = dt->year; |
| 167 | m = dt->month; |
| 168 | if (m <= 2) { |
| 169 | m += 12; |
| 170 | y -= 1; |
| 171 | } |
| 172 | |
| 173 | /* |
| 174 | * added 1 to get dttoj and jtodt to match |
| 175 | */ |
| 176 | res = dt->day + (153 * m - 457) / 5 + 365 * y + (int)floor(y / 4) - (int)floor(y / 100) + (int)floor(y / 400) + |
| 177 | 1721118 + 1; |
| 178 | |
| 179 | return (res); |
| 180 | } |
| 181 | |
| 182 | /* |
| 183 | * Routine: strtodt() |
| 184 | * Purpose: Convert an ascii string to a date_t structure |
| 185 | * Algorithm: |
| 186 | * Data Structures: |
| 187 | * |
| 188 | * Params: char *s, date_t *dest |
| 189 | * Returns: int; 0 on success |
| 190 | * Called By: |
| 191 | * Calls: |
| 192 | * Assumptions: |
| 193 | * Side Effects: |
| 194 | * TODO: Need to allow for date formats other than Y4MD- |
| 195 | */ |
| 196 | int strtodt(date_t *dest, char *s) { |
| 197 | int nRetCode = 0; |
| 198 | |
| 199 | if (s == NULL) { |
| 200 | dest = NULL; |
| 201 | return (-1); |
| 202 | } |
| 203 | |
| 204 | if (sscanf(s, "%4d-%d-%d" , &dest->year, &dest->month, &dest->day) != 3) { |
| 205 | fprintf(stderr, "ERROR: Invalid string to date conversion in strtodt\n" ); |
| 206 | nRetCode = -1; |
| 207 | } |
| 208 | |
| 209 | dest->julian = dttoj(dest); |
| 210 | |
| 211 | return (nRetCode); |
| 212 | } |
| 213 | |
| 214 | /* |
| 215 | * Routine: dttostr(date_t *d) |
| 216 | * Purpose: convert a date_t structure to a string |
| 217 | * Algorithm: |
| 218 | * Data Structures: |
| 219 | * |
| 220 | * Params: |
| 221 | * Returns: char *; NULL on failure |
| 222 | * Called By: |
| 223 | * Calls: |
| 224 | * Assumptions: |
| 225 | * Side Effects: |
| 226 | * TODO: 20000110 Need to handle more than Y4MD- |
| 227 | */ |
| 228 | char *dttostr(date_t *d) { |
| 229 | static char *res; |
| 230 | static int init = 0; |
| 231 | |
| 232 | if (!init) { |
| 233 | res = (char *)malloc(sizeof(char) * 11); |
| 234 | MALLOC_CHECK(res); |
| 235 | init = 1; |
| 236 | } |
| 237 | |
| 238 | if (d == NULL) |
| 239 | return (NULL); |
| 240 | |
| 241 | sprintf(res, "%4d-%02d-%02d" , d->year, d->month, d->day); |
| 242 | |
| 243 | return (res); |
| 244 | } |
| 245 | |
| 246 | /* |
| 247 | * Routine: date_init |
| 248 | * Purpose: set the date handling parameters |
| 249 | * Algorithm: |
| 250 | * Data Structures: |
| 251 | * |
| 252 | * Params: None |
| 253 | * Returns: int; 0 on success |
| 254 | * Called By: |
| 255 | * Calls: |
| 256 | * Assumptions: |
| 257 | * Side Effects: |
| 258 | * TODO: None |
| 259 | */ |
| 260 | int date_init(void) { |
| 261 | printf("date_init is not yet complete\n" ); |
| 262 | exit(1); |
| 263 | return (0); |
| 264 | } |
| 265 | |
| 266 | /* |
| 267 | * Routine: date_t_op(int op, date_t *operand1, date_t *operand2) |
| 268 | * Purpose: execute arbitrary binary operations on date_t's |
| 269 | * Algorithm: |
| 270 | * Data Structures: |
| 271 | * |
| 272 | * Params: |
| 273 | * Returns: |
| 274 | * Called By: |
| 275 | * Calls: |
| 276 | * Assumptions: |
| 277 | * Side Effects: |
| 278 | * TODO: |
| 279 | * 20010806 jms Return code is meaningless |
| 280 | */ |
| 281 | int date_t_op(date_t *dest, int op, date_t *d1, date_t *d2) { |
| 282 | int tJulian; |
| 283 | char tString[11]; |
| 284 | date_t tDate; |
| 285 | |
| 286 | switch (op) { |
| 287 | case OP_FIRST_DOM: /* set to first day of month */ |
| 288 | tJulian = d1->julian - d1->day + 1; |
| 289 | jtodt(dest, tJulian); |
| 290 | break; |
| 291 | case OP_LAST_DOM: /* set to last day of month */ |
| 292 | tJulian = d1->julian - d1->day + m_days[is_leap(d1->year)][d1->month]; |
| 293 | jtodt(dest, tJulian); |
| 294 | break; |
| 295 | case OP_SAME_LY: |
| 296 | if (is_leap(d1->year) && (d1->month == 2) && (d1->day == 29)) |
| 297 | sprintf(tString, "%d-02-28" , d1->year - 1); |
| 298 | else |
| 299 | sprintf(tString, "%4d-%02d-%02d" , d1->year - 1, d1->month, d1->day); |
| 300 | strtodt(dest, tString); |
| 301 | break; |
| 302 | case OP_SAME_LQ: |
| 303 | switch (d1->month) { |
| 304 | case 1: |
| 305 | case 2: |
| 306 | case 3: |
| 307 | sprintf(tString, "%4d-%s" , d1->year, qtr_start[1]); |
| 308 | strtodt(&tDate, tString); |
| 309 | tJulian = d1->julian - tDate.julian; |
| 310 | sprintf(tString, "%4d-%s" , d1->year - 1, qtr_start[4]); |
| 311 | strtodt(&tDate, tString); |
| 312 | tJulian += tDate.julian; |
| 313 | jtodt(dest, tJulian); |
| 314 | break; |
| 315 | case 4: |
| 316 | case 5: |
| 317 | case 6: |
| 318 | sprintf(tString, "%4d-%s" , d1->year, qtr_start[2]); |
| 319 | strtodt(&tDate, tString); |
| 320 | tJulian = d1->julian - tDate.julian; |
| 321 | sprintf(tString, "%4d-%s" , d1->year, qtr_start[1]); |
| 322 | strtodt(&tDate, tString); |
| 323 | tJulian += tDate.julian; |
| 324 | jtodt(dest, tJulian); |
| 325 | break; |
| 326 | case 7: |
| 327 | case 8: |
| 328 | case 9: |
| 329 | sprintf(tString, "%4d-%s" , d1->year, qtr_start[3]); |
| 330 | strtodt(&tDate, tString); |
| 331 | tJulian = d1->julian - tDate.julian; |
| 332 | sprintf(tString, "%4d-%s" , d1->year, qtr_start[2]); |
| 333 | strtodt(&tDate, tString); |
| 334 | tJulian += tDate.julian; |
| 335 | jtodt(dest, tJulian); |
| 336 | break; |
| 337 | case 10: |
| 338 | case 11: |
| 339 | case 12: |
| 340 | sprintf(tString, "%4d-%s" , d1->year, qtr_start[4]); |
| 341 | strtodt(&tDate, tString); |
| 342 | tJulian = d1->julian - tDate.julian; |
| 343 | sprintf(tString, "%4d-%s" , d1->year, qtr_start[3]); |
| 344 | strtodt(&tDate, tString); |
| 345 | tJulian += tDate.julian; |
| 346 | jtodt(dest, tJulian); |
| 347 | break; |
| 348 | } |
| 349 | break; |
| 350 | } |
| 351 | |
| 352 | return (0); |
| 353 | } |
| 354 | |
| 355 | /* |
| 356 | * Routine: itodt(date_t *d, int src) |
| 357 | * Purpose: convert a number of days to a date_t |
| 358 | * Algorithm: NOTE: sets only julian field |
| 359 | * Data Structures: |
| 360 | * |
| 361 | * Params: |
| 362 | * Returns: |
| 363 | * Called By: |
| 364 | * Calls: |
| 365 | * Assumptions: |
| 366 | * Side Effects: |
| 367 | * TODO: None |
| 368 | */ |
| 369 | int itodt(date_t *dest, int src) { |
| 370 | |
| 371 | dest->julian = src; |
| 372 | |
| 373 | return (0); |
| 374 | } |
| 375 | |
| 376 | /* |
| 377 | * Routine: set_dow(date *d) |
| 378 | * Purpose: perpetual calendar stuff |
| 379 | * Algorithm: |
| 380 | * Data Structures: |
| 381 | * |
| 382 | * Params: |
| 383 | * Returns: |
| 384 | * Called By: |
| 385 | * Calls: |
| 386 | * Assumptions: |
| 387 | * Side Effects: |
| 388 | * TODO: |
| 389 | */ |
| 390 | static int doomsday[4] = {3, 2, 0, 5}; |
| 391 | static int known[13] = {0, 3, 0, 0, 4, 9, 6, 11, 8, 5, 10, 7, 12}; |
| 392 | int set_dow(date_t *d) { |
| 393 | |
| 394 | static int last_year = -1, dday; |
| 395 | int res, q, r, s; |
| 396 | |
| 397 | if (d->year != last_year) { |
| 398 | if (is_leap(d->year)) { |
| 399 | /* adjust the known dates for january and february */ |
| 400 | known[1] = 4; |
| 401 | known[2] = 1; |
| 402 | } else { |
| 403 | known[1] = 3; |
| 404 | known[2] = 0; |
| 405 | } |
| 406 | |
| 407 | /* calculate the doomsday for the century */ |
| 408 | dday = d->year / 100; |
| 409 | dday -= 15; |
| 410 | dday %= 4; |
| 411 | dday = doomsday[dday]; |
| 412 | |
| 413 | /* and then calculate the doomsday for the year */ |
| 414 | q = d->year % 100; |
| 415 | r = q % 12; |
| 416 | q /= 12; |
| 417 | s = r / 4; |
| 418 | dday += q + r + s; |
| 419 | dday %= 7; |
| 420 | last_year = d->year; |
| 421 | } |
| 422 | |
| 423 | res = d->day; |
| 424 | res -= known[d->month]; |
| 425 | while (res < 0) |
| 426 | res += 7; |
| 427 | while (res > 6) |
| 428 | res -= 7; |
| 429 | |
| 430 | res += dday; |
| 431 | res %= 7; |
| 432 | |
| 433 | return (res); |
| 434 | } |
| 435 | |
| 436 | /* |
| 437 | * Routine: is_leap(year) |
| 438 | * Purpose: |
| 439 | * Algorithm: |
| 440 | * Data Structures: |
| 441 | * |
| 442 | * Params: |
| 443 | * Returns: |
| 444 | * Called By: |
| 445 | * Calls: |
| 446 | * Assumptions: |
| 447 | * Side Effects: |
| 448 | * TODO: None |
| 449 | */ |
| 450 | int is_leap(int year) { |
| 451 | |
| 452 | return (((year % 100) == 0) ? ((((year % 400) % 2) == 0) ? 1 : 0) : ((year % 4) == 0) ? 1 : 0); |
| 453 | } |
| 454 | |
| 455 | /* |
| 456 | * Routine: day_number(date_t *) |
| 457 | * Purpose: |
| 458 | * Algorithm: NOTE: this is NOT the ordinal day in the year, but the ordinal |
| 459 | *reference into the calendar distribution for the day; in particular, this |
| 460 | *needs to skip over the leap day Data Structures: |
| 461 | * |
| 462 | * Params: |
| 463 | * Returns: |
| 464 | * Called By: |
| 465 | * Calls: |
| 466 | * Assumptions: |
| 467 | * Side Effects: |
| 468 | * TODO: None |
| 469 | */ |
| 470 | int day_number(date_t *d) { |
| 471 | return (m_days[is_leap(d->year)][d->month] + d->day); |
| 472 | } |
| 473 | |
| 474 | /* |
| 475 | * Routine: getDateWeightFromJulian(jDay, nDistribution) |
| 476 | * Purpose: return the weight associated with a particular julian date and |
| 477 | * distribution Algorithm: Data Structures: |
| 478 | * |
| 479 | * Params: |
| 480 | * Returns: |
| 481 | * Called By: |
| 482 | * Calls: |
| 483 | * Assumptions: |
| 484 | * Side Effects: |
| 485 | * TODO: None |
| 486 | */ |
| 487 | int getDateWeightFromJulian(jDay, nDistribution) { |
| 488 | date_t dTemp; |
| 489 | int nDay; |
| 490 | |
| 491 | jtodt(&dTemp, jDay); |
| 492 | nDay = day_number(&dTemp); |
| 493 | |
| 494 | return (dist_weight(NULL, "calendar" , nDay, nDistribution + is_leap(dTemp.year))); |
| 495 | } |
| 496 | |
| 497 | /* |
| 498 | * Routine: date_part(date_t *, int part) |
| 499 | * Purpose: |
| 500 | * Algorithm: |
| 501 | * Data Structures: |
| 502 | * |
| 503 | * Params: |
| 504 | * Returns: |
| 505 | * Called By: |
| 506 | * Calls: |
| 507 | * Assumptions: |
| 508 | * Side Effects: |
| 509 | * TODO: None |
| 510 | */ |
| 511 | int date_part(date_t *d, int part) { |
| 512 | switch (part) { |
| 513 | case 1: |
| 514 | return (d->year); |
| 515 | case 2: |
| 516 | return (d->month); |
| 517 | case 3: |
| 518 | return (d->day); |
| 519 | default: |
| 520 | INTERNAL("Invalid call to date_part()" ); |
| 521 | return (-1); |
| 522 | } |
| 523 | } |
| 524 | |
| 525 | #ifdef TEST |
| 526 | main() { |
| 527 | date_t *d; |
| 528 | int ret; |
| 529 | |
| 530 | d = mk_date(); |
| 531 | strtodt(d, "1776-07-04" ); |
| 532 | ret = set_dow(d); |
| 533 | printf("set_dow(\"1776-07-04\"): wanted 4 got %d\n" , ret); |
| 534 | if (ret != 4) { |
| 535 | exit(1); |
| 536 | } |
| 537 | strtodt(d, "2000-01-01" ); |
| 538 | ret = set_dow(d); |
| 539 | printf("set_dow(\"2000-01-01\"): wanted 6 got %d\n" , ret); |
| 540 | if (ret != 6) { |
| 541 | exit(1); |
| 542 | } |
| 543 | |
| 544 | strtodt(d, "1970-01-01" ); |
| 545 | if ((ret = dttoj(d)) != 2440588) { |
| 546 | printf("dttoj returned %d\n" , ret); |
| 547 | exit(1); |
| 548 | } |
| 549 | |
| 550 | d->year = 1; |
| 551 | d->month = 11; |
| 552 | d->date = 11; |
| 553 | jtodt(d, 2440588); |
| 554 | if ((d->year != 1970) || (d->month != 1) || (d->date != 1)) { |
| 555 | printf("jtodt failed got: " ); |
| 556 | printf("%4d-%02d-%02d" , d->year, d->month, d->date); |
| 557 | exit(1); |
| 558 | } |
| 559 | return (0); |
| 560 | } |
| 561 | #endif /* TEST */ |
| 562 | |