numpy 2.0.0
src/multiarray/datetime_busday.c File Reference
#include <Python.h>
#include <numpy/arrayobject.h>
#include "npy_config.h"
#include "numpy/npy_3kcompat.h"
#include "numpy/arrayscalars.h"
#include "lowlevel_strided_loops.h"
#include "_datetime.h"
#include "datetime_busday.h"
#include "datetime_busdaycal.h"

Defines

#define PY_SSIZE_T_CLEAN
#define NPY_NO_DEPRECATED_API
#define _MULTIARRAYMODULE

Functions

static int get_day_of_week (npy_datetime date)
static int is_holiday (npy_datetime date, npy_datetime *holidays_begin, npy_datetime *holidays_end)
static npy_datetimefind_earliest_holiday_on_or_after (npy_datetime date, npy_datetime *holidays_begin, npy_datetime *holidays_end)
static npy_datetimefind_earliest_holiday_after (npy_datetime date, npy_datetime *holidays_begin, npy_datetime *holidays_end)
static int apply_business_day_roll (npy_datetime date, npy_datetime *out, int *out_day_of_week, NPY_BUSDAY_ROLL roll, npy_bool *weekmask, npy_datetime *holidays_begin, npy_datetime *holidays_end)
static int apply_business_day_offset (npy_datetime date, npy_int64 offset, npy_datetime *out, NPY_BUSDAY_ROLL roll, npy_bool *weekmask, int busdays_in_weekmask, npy_datetime *holidays_begin, npy_datetime *holidays_end)
static int apply_business_day_count (npy_datetime date_begin, npy_datetime date_end, npy_int64 *out, npy_bool *weekmask, int busdays_in_weekmask, npy_datetime *holidays_begin, npy_datetime *holidays_end)
NPY_NO_EXPORT PyArrayObjectbusiness_day_offset (PyArrayObject *dates, PyArrayObject *offsets, PyArrayObject *out, NPY_BUSDAY_ROLL roll, npy_bool *weekmask, int busdays_in_weekmask, npy_datetime *holidays_begin, npy_datetime *holidays_end)
NPY_NO_EXPORT PyArrayObjectbusiness_day_count (PyArrayObject *dates_begin, PyArrayObject *dates_end, PyArrayObject *out, npy_bool *weekmask, int busdays_in_weekmask, npy_datetime *holidays_begin, npy_datetime *holidays_end)
NPY_NO_EXPORT PyArrayObjectis_business_day (PyArrayObject *dates, PyArrayObject *out, npy_bool *weekmask, int busdays_in_weekmask, npy_datetime *holidays_begin, npy_datetime *holidays_end)
static int PyArray_BusDayRollConverter (PyObject *roll_in, NPY_BUSDAY_ROLL *roll)
NPY_NO_EXPORT PyObject * array_busday_offset (PyObject *NPY_UNUSED(self), PyObject *args, PyObject *kwds)
NPY_NO_EXPORT PyObject * array_busday_count (PyObject *NPY_UNUSED(self), PyObject *args, PyObject *kwds)
NPY_NO_EXPORT PyObject * array_is_busday (PyObject *NPY_UNUSED(self), PyObject *args, PyObject *kwds)

Define Documentation

#define _MULTIARRAYMODULE
#define NPY_NO_DEPRECATED_API
#define PY_SSIZE_T_CLEAN

Function Documentation

static int apply_business_day_count ( npy_datetime  date_begin,
npy_datetime  date_end,
npy_int64 *  out,
npy_bool weekmask,
int  busdays_in_weekmask,
npy_datetime holidays_begin,
npy_datetime holidays_end 
) [static]
Applies a single business day count operation. See the function business_day_count for the meaning of all the parameters.
Returns 0 on success, -1 on failure.

If we get a NaT, raise an error
Trivial empty date range
Remove any earlier holidays
Remove any later holidays
Start the count as negative the number of holidays in the range
Add the whole weeks between date_begin and date_end
Get the day of the week for 'date_begin'
Count the remaining days one by one

References apply_business_day_offset(), PyArray_DatetimeMetaData::base, create_datetime_dtype(), NPY_DATETIME, NPY_FR_D, NPY_ITER_ALIGNED, NPY_ITER_ALLOCATE, NPY_ITER_BUFFERED, NPY_ITER_EXTERNAL_LOOP, NPY_ITER_READONLY, NPY_ITER_WRITEONLY, NPY_ITER_ZEROSIZE_OK, NPY_KEEPORDER, NPY_SAFE_CASTING, NPY_SUCCEED, NpyIter_Deallocate(), NpyIter_GetDataPtrArray(), NpyIter_GetInnerLoopSizePtr(), NpyIter_GetInnerStrideArray(), NpyIter_GetIterNext(), NpyIter_GetIterSize(), NpyIter_GetOperandArray(), NpyIter_MultiNew(), PyArray_DatetimeMetaData::num, and PyArray_DescrFromType().

Referenced by business_day_offset().

static int apply_business_day_offset ( npy_datetime  date,
npy_int64  offset,
npy_datetime out,
NPY_BUSDAY_ROLL  roll,
npy_bool weekmask,
int  busdays_in_weekmask,
npy_datetime holidays_begin,
npy_datetime holidays_end 
) [static]
Applies a single business day offset. See the function business_day_offset for the meaning of all the parameters.
Returns 0 on success, -1 on failure.

Roll the date to a business day
If we get a NaT, just return it
Now we're on a valid business day
Remove any earlier holidays
Jump by as many weeks as we can
Adjust based on the number of holidays we crossed
Step until we use up the rest of the offset
Remove any later holidays
Jump by as many weeks as we can
Adjust based on the number of holidays we crossed
Step until we use up the rest of the offset

References is_holiday().

Referenced by apply_business_day_count().

static int apply_business_day_roll ( npy_datetime  date,
npy_datetime out,
int *  out_day_of_week,
NPY_BUSDAY_ROLL  roll,
npy_bool weekmask,
npy_datetime holidays_begin,
npy_datetime holidays_end 
) [static]
Applies the 'roll' strategy to 'date', placing the result in 'out' and setting 'out_day_of_week' to the day of the week that results.
Returns 0 on success, -1 on failure.

Deal with NaT input
Get the day of the week for 'date'
Apply the 'roll' if it's not a business day
If we crossed a month boundary, do preceding instead
If we crossed a month boundary, do following instead

NPY_NO_EXPORT PyObject* array_busday_count ( PyObject *  NPY_UNUSEDself,
PyObject *  args,
PyObject *  kwds 
)
This is the 'busday_count' function exposed for calling from Python.

Make sure only one of the weekmask/holidays and busdaycal is supplied
Indicate that the holidays weren't allocated by us
Copy the private normalized weekmask/holidays data
Fix up the weekmask from the uninitialized signal value to a proper default.
Count the number of business days in a week
The holidays list must be normalized before using it
Make 'dates_begin' into an array
Use the datetime dtype with generic units so it fills it in
This steals the datetime_dtype reference
Make 'dates_end' into an array
Use the datetime dtype with generic units so it fills it in
This steals the datetime_dtype reference
Make sure 'out' is an array if it's provided

Referenced by _vec_string().

NPY_NO_EXPORT PyObject* array_busday_offset ( PyObject *  NPY_UNUSEDself,
PyObject *  args,
PyObject *  kwds 
)
This is the 'busday_offset' function exposed for calling from Python.

Make sure only one of the weekmask/holidays and busdaycal is supplied
Indicate that the holidays weren't allocated by us
Copy the private normalized weekmask/holidays data
Fix up the weekmask from the uninitialized signal value to a proper default.
Count the number of business days in a week
The holidays list must be normalized before using it
Make 'dates' into an array
Use the datetime dtype with generic units so it fills it in
This steals the datetime_dtype reference
Make 'offsets' into an array
Make sure 'out' is an array if it's provided

Referenced by _vec_string().

NPY_NO_EXPORT PyObject* array_is_busday ( PyObject *  NPY_UNUSEDself,
PyObject *  args,
PyObject *  kwds 
)
This is the 'is_busday' function exposed for calling from Python.

Make sure only one of the weekmask/holidays and busdaycal is supplied
Indicate that the holidays weren't allocated by us
Copy the private normalized weekmask/holidays data
Fix up the weekmask from the uninitialized signal value to a proper default.
Count the number of business days in a week
The holidays list must be normalized before using it
Make 'dates' into an array
Use the datetime dtype with generic units so it fills it in
This steals the datetime_dtype reference
Make sure 'out' is an array if it's provided

Referenced by _vec_string().

NPY_NO_EXPORT PyArrayObject* business_day_count ( PyArrayObject dates_begin,
PyArrayObject dates_end,
PyArrayObject out,
npy_bool weekmask,
int  busdays_in_weekmask,
npy_datetime holidays_begin,
npy_datetime holidays_end 
)
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.
dates_begin: An array of dates with 'datetime64[D]' data type. dates_end: An array of dates with 'datetime64[D]' data type. out: Either NULL, or an array with 'int64' data type

System Message: ERROR/3 (<string>, line 8) Unexpected indentation.

<blockquote> in which to place the resulting dates.</blockquote>

System Message: WARNING/2 (<string>, line 9) Block quote ends without a blank line; unexpected unindent.
weekmask: A 7-element boolean mask, 1 for possible business days and 0
for non-business days.
System Message: WARNING/2 (<string>, line 11) Definition list ends without a blank line; unexpected unindent.
busdays_in_weekmask: A count of how many 1's there are in weekmask. holidays_begin/holidays_end: A sorted list of dates matching '[D]'

System Message: ERROR/3 (<string>, line 13) Unexpected indentation.

<blockquote> unit metadata, with any dates falling on a day of the week without weekmask[i] == 1 already filtered out.</blockquote>

First create the data types for the dates and the int64 output
Set up the iterator parameters
Allocate the iterator
Loop over all elements
Get the return object from the iterator

NPY_NO_EXPORT PyArrayObject* business_day_offset ( PyArrayObject dates,
PyArrayObject offsets,
PyArrayObject out,
NPY_BUSDAY_ROLL  roll,
npy_bool weekmask,
int  busdays_in_weekmask,
npy_datetime holidays_begin,
npy_datetime holidays_end 
)
Applies the given offsets in business days to the dates provided. This is the low-level function which requires already cleaned input data.
dates: An array of dates with 'datetime64[D]' data type. offsets: An array safely convertible into type int64. out: Either NULL, or an array with 'datetime64[D]' data type

System Message: ERROR/3 (<string>, line 8) Unexpected indentation.

<blockquote> in which to place the resulting dates.</blockquote>

System Message: WARNING/2 (<string>, line 9) Block quote ends without a blank line; unexpected unindent.
roll: A rule for how to treat non-business day dates. weekmask: A 7-element boolean mask, 1 for possible business days and 0

System Message: ERROR/3 (<string>, line 11) Unexpected indentation.

<blockquote> for non-business days.</blockquote>

System Message: WARNING/2 (<string>, line 12) Block quote ends without a blank line; unexpected unindent.
busdays_in_weekmask: A count of how many 1's there are in weekmask. holidays_begin/holidays_end: A sorted list of dates matching '[D]'

System Message: ERROR/3 (<string>, line 14) Unexpected indentation.

<blockquote> unit metadata, with any dates falling on a day of the week without weekmask[i] == 1 already filtered out.</blockquote>

For each (date, offset) in the broadcasted pair of (dates, offsets), does the following:

System Message: ERROR/3 (<string>, line 19) Unexpected indentation.

<blockquote>

  • Applies the 'roll' rule to the date to either produce NaT, raise an exception, or land on a valid business day.
  • Adds 'offset' business days to the valid business day found.
  • Sets the value in 'out' if provided, or the allocated output array otherwise.

</blockquote>

First create the data types for dates and offsets
Set up the iterator parameters
Allocate the iterator
Loop over all elements
Get the return object from the iterator

References apply_business_day_count(), PyArray_DatetimeMetaData::base, create_datetime_dtype(), NPY_DATETIME, NPY_FR_D, NPY_ITER_ALIGNED, NPY_ITER_ALLOCATE, NPY_ITER_BUFFERED, NPY_ITER_EXTERNAL_LOOP, NPY_ITER_READONLY, NPY_ITER_WRITEONLY, NPY_ITER_ZEROSIZE_OK, NPY_KEEPORDER, NPY_SAFE_CASTING, NPY_SUCCEED, NpyIter_Deallocate(), NpyIter_GetDataPtrArray(), NpyIter_GetInnerLoopSizePtr(), NpyIter_GetInnerStrideArray(), NpyIter_GetIterNext(), NpyIter_GetIterSize(), NpyIter_GetOperandArray(), NpyIter_MultiNew(), PyArray_DatetimeMetaData::num, and PyArray_DescrFromType().

static npy_datetime* find_earliest_holiday_after ( npy_datetime  date,
npy_datetime holidays_begin,
npy_datetime holidays_end 
) [static]
Finds the earliest holiday which is after 'date'. If 'date' does not appear within the holiday range, returns 'holidays_begin' if 'date' is before all holidays, or 'holidays_end' if 'date' is after all holidays.
To remove all the holidays after 'date' from a holiday range, do: <blockquote>

holidays_end = find_holiday_earliest_after(date,
holidays_begin, holidays_end);

</blockquote>

The holidays list should be normalized, which means any NaT (not-a-time) values, duplicates, and dates already excluded by the weekmask should be removed, and the list should be sorted.

Simple binary search

static npy_datetime* find_earliest_holiday_on_or_after ( npy_datetime  date,
npy_datetime holidays_begin,
npy_datetime holidays_end 
) [static]
Finds the earliest holiday which is on or after 'date'. If 'date' does not appear within the holiday range, returns 'holidays_begin' if 'date' is before all holidays, or 'holidays_end' if 'date' is after all holidays.
To remove all the holidays before 'date' from a holiday range, do: <blockquote>

holidays_begin = find_holiday_earliest_on_or_after(date,
holidays_begin, holidays_end);

</blockquote>

The holidays list should be normalized, which means any NaT (not-a-time) values, duplicates, and dates already excluded by the weekmask should be removed, and the list should be sorted.

Simple binary search

static int get_day_of_week ( npy_datetime  date) [static]
Gets the day of the week for a datetime64[D] value

Get the day of the week for 'date' (1970-01-05 is Monday)

NPY_NO_EXPORT PyArrayObject* is_business_day ( PyArrayObject dates,
PyArrayObject out,
npy_bool weekmask,
int  busdays_in_weekmask,
npy_datetime holidays_begin,
npy_datetime holidays_end 
)
Returns a boolean array with True for input dates which are valid business days, and False for dates which are not. This is the low-level function which requires already cleaned input data.
dates: An array of dates with 'datetime64[D]' data type. out: Either NULL, or an array with 'bool' data type

System Message: ERROR/3 (<string>, line 7) Unexpected indentation.

<blockquote> in which to place the resulting dates.</blockquote>

System Message: WARNING/2 (<string>, line 8) Block quote ends without a blank line; unexpected unindent.
weekmask: A 7-element boolean mask, 1 for possible business days and 0
for non-business days.
System Message: WARNING/2 (<string>, line 10) Definition list ends without a blank line; unexpected unindent.
busdays_in_weekmask: A count of how many 1's there are in weekmask. holidays_begin/holidays_end: A sorted list of dates matching '[D]'

System Message: ERROR/3 (<string>, line 12) Unexpected indentation.

<blockquote> unit metadata, with any dates falling on a day of the week without weekmask[i] == 1 already filtered out.</blockquote>

First create the data types for the dates and the bool output
Set up the iterator parameters
Allocate the iterator
Loop over all elements
Check if it's a business day
Get the return object from the iterator

References NPY_BUSDAY_PRECEDING.

static int is_holiday ( npy_datetime  date,
npy_datetime holidays_begin,
npy_datetime holidays_end 
) [static]
Returns 1 if the date is a holiday (contained in the sorted list of dates), 0 otherwise.
The holidays list should be normalized, which means any NaT (not-a-time) values, duplicates, and dates already excluded by the weekmask should be removed, and the list should be sorted.

Simple binary search
Not found

Referenced by apply_business_day_offset().

static int PyArray_BusDayRollConverter ( PyObject *  roll_in,
NPY_BUSDAY_ROLL roll 
) [static]

Make obj into an ASCII string
accept unicode input
Use switch statements to quickly isolate the right enum value