* Counts the number of business days between two dates, not including * the end date. This is the low-level function which requires already * cleaned input data. * * If dates_begin is before dates_end, the result is positive. If * dates_begin is after dates_end, it is negative. * * dates_begin: An array of dates with 'datetime64[D]' data type. * dates_end: An array of dates with 'date
| 595 | * week without weekmask[i] == 1 already filtered out. |
| 596 | */ |
| 597 | NPY_NO_EXPORT PyArrayObject * |
| 598 | business_day_count(PyArrayObject *dates_begin, PyArrayObject *dates_end, |
| 599 | PyArrayObject *out, |
| 600 | npy_bool *weekmask, int busdays_in_weekmask, |
| 601 | npy_datetime *holidays_begin, npy_datetime *holidays_end) |
| 602 | { |
| 603 | PyArray_DatetimeMetaData temp_meta; |
| 604 | PyArray_Descr *dtypes[3] = {NULL, NULL, NULL}; |
| 605 | |
| 606 | NpyIter *iter = NULL; |
| 607 | PyArrayObject *op[3] = {NULL, NULL, NULL}; |
| 608 | npy_uint32 op_flags[3], flags; |
| 609 | |
| 610 | PyArrayObject *ret = NULL; |
| 611 | |
| 612 | if (busdays_in_weekmask == 0) { |
| 613 | PyErr_SetString(PyExc_ValueError, |
| 614 | "the business day weekmask must have at least one " |
| 615 | "valid business day"); |
| 616 | return NULL; |
| 617 | } |
| 618 | |
| 619 | /* First create the data types for the dates and the int64 output */ |
| 620 | temp_meta.base = NPY_FR_D; |
| 621 | temp_meta.num = 1; |
| 622 | dtypes[0] = create_datetime_dtype(NPY_DATETIME, &temp_meta); |
| 623 | if (dtypes[0] == NULL) { |
| 624 | goto fail; |
| 625 | } |
| 626 | dtypes[1] = dtypes[0]; |
| 627 | Py_INCREF(dtypes[1]); |
| 628 | dtypes[2] = PyArray_DescrFromType(NPY_INT64); |
| 629 | if (dtypes[2] == NULL) { |
| 630 | goto fail; |
| 631 | } |
| 632 | |
| 633 | /* Set up the iterator parameters */ |
| 634 | flags = NPY_ITER_EXTERNAL_LOOP| |
| 635 | NPY_ITER_BUFFERED| |
| 636 | NPY_ITER_ZEROSIZE_OK; |
| 637 | op[0] = dates_begin; |
| 638 | op_flags[0] = NPY_ITER_READONLY | NPY_ITER_ALIGNED; |
| 639 | op[1] = dates_end; |
| 640 | op_flags[1] = NPY_ITER_READONLY | NPY_ITER_ALIGNED; |
| 641 | op[2] = out; |
| 642 | op_flags[2] = NPY_ITER_WRITEONLY | NPY_ITER_ALLOCATE | NPY_ITER_ALIGNED; |
| 643 | |
| 644 | /* Allocate the iterator */ |
| 645 | iter = NpyIter_MultiNew(3, op, flags, NPY_KEEPORDER, NPY_SAFE_CASTING, |
| 646 | op_flags, dtypes); |
| 647 | if (iter == NULL) { |
| 648 | goto fail; |
| 649 | } |
| 650 | |
| 651 | /* Loop over all elements */ |
| 652 | if (NpyIter_GetIterSize(iter) > 0) { |
| 653 | NpyIter_IterNextFunc *iternext; |
| 654 | char **dataptr; |
no test coverage detected