summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Wiebe <mwiebe@enthought.com>2011-07-19 14:45:59 -0500
committerMark Wiebe <mwiebe@enthought.com>2011-07-19 14:46:14 -0500
commitecaf1e1765eb5697a27761b49a25081b1fffb90d (patch)
treeee10ea7d84cd135f6589a329d35a3a22de5e919e
parentc649139121015e3d6bb82377e3c9094a0f850065 (diff)
parent1d3add610afc367d59bdc0c40a16cacf766a48a9 (diff)
downloadnumpy-ecaf1e1765eb5697a27761b49a25081b1fffb90d.tar.gz
MRG: Merge branch 'steveha/datetime64_doc'
-rw-r--r--doc/source/reference/arrays.datetime.rst122
-rw-r--r--numpy/add_newdocs.py175
-rw-r--r--numpy/core/src/multiarray/datetime_busdaycal.c123
-rw-r--r--numpy/core/tests/test_datetime.py20
4 files changed, 274 insertions, 166 deletions
diff --git a/doc/source/reference/arrays.datetime.rst b/doc/source/reference/arrays.datetime.rst
index 2fd6dfcdd..541f97884 100644
--- a/doc/source/reference/arrays.datetime.rst
+++ b/doc/source/reference/arrays.datetime.rst
@@ -23,7 +23,7 @@ be either a :ref:`date unit <arrays.dtypes.dateunits>` or a
:ref:`time unit <arrays.dtypes.timeunits>`. The date units are years ('Y'),
months ('M'), weeks ('W'), and days ('D'), while the time units are
hours ('h'), minutes ('m'), seconds ('s'), milliseconds ('ms'), and
-more SI-prefix seconds-based units.
+some additional SI-prefix seconds-based units.
.. admonition:: Example
@@ -139,7 +139,7 @@ simple datetime calculations.
>>> np.timedelta64(1,'W') / np.timedelta64(1,'D')
7.0
-There are two Timedelta units, years and months, which are treated
+There are two Timedelta units ('Y', years and 'M', months) which are treated
specially, because how much time they represent changes depending
on when they are used. While a timedelta day unit is equivalent to
24 hours, there is no way to convert a month unit into days, because
@@ -167,7 +167,13 @@ other units based on input data.
Datetimes are always stored based on POSIX time (though having a TAI
mode which allows for accounting of leap-seconds is proposed), with
a epoch of 1970-01-01T00:00Z. This means the supported dates are
-always a symmetric interval around 1970.
+always a symmetric interval around the epoch, called "time span" in the
+table below.
+
+The length of the span is the range of a 64-bit integer times the length
+of the date or unit. For example, the time span for 'W' (week) is exactly
+7 times longer than the time span for 'D' (day), and the time span for
+'D' (day) is exactly 24 times longer than the time span for 'h' (hour).
Here are the date units:
@@ -176,10 +182,10 @@ Here are the date units:
======== ================ ======================= ==========================
Code Meaning Time span (relative) Time span (absolute)
======== ================ ======================= ==========================
- Y year +- 9.2e18 years [9.2e18 BC, 9.2e18 AD]
- M month +- 7.6e17 years [7.6e17 BC, 7.6e17 AD]
- W week +- 1.7e17 years [1.7e17 BC, 1.7e17 AD]
- D day +- 2.5e16 years [2.5e16 BC, 2.5e16 AD]
+ Y year +/- 9.2e18 years [9.2e18 BC, 9.2e18 AD]
+ M month +/- 7.6e17 years [7.6e17 BC, 7.6e17 AD]
+ W week +/- 1.7e17 years [1.7e17 BC, 1.7e17 AD]
+ D day +/- 2.5e16 years [2.5e16 BC, 2.5e16 AD]
======== ================ ======================= ==========================
And here are the time units:
@@ -189,28 +195,34 @@ And here are the time units:
======== ================ ======================= ==========================
Code Meaning Time span (relative) Time span (absolute)
======== ================ ======================= ==========================
- h hour +- 1.0e15 years [1.0e15 BC, 1.0e15 AD]
- m minute +- 1.7e13 years [1.7e13 BC, 1.7e13 AD]
- s second +- 2.9e12 years [ 2.9e9 BC, 2.9e9 AD]
- ms millisecond +- 2.9e9 years [ 2.9e6 BC, 2.9e6 AD]
- us microsecond +- 2.9e6 years [290301 BC, 294241 AD]
- ns nanosecond +- 292 years [ 1678 AD, 2262 AD]
- ps picosecond +- 106 days [ 1969 AD, 1970 AD]
- fs femtosecond +- 2.6 hours [ 1969 AD, 1970 AD]
- as attosecond +- 9.2 seconds [ 1969 AD, 1970 AD]
+ h hour +/- 1.0e15 years [1.0e15 BC, 1.0e15 AD]
+ m minute +/- 1.7e13 years [1.7e13 BC, 1.7e13 AD]
+ s second +/- 2.9e12 years [ 2.9e9 BC, 2.9e9 AD]
+ ms millisecond +/- 2.9e9 years [ 2.9e6 BC, 2.9e6 AD]
+ us microsecond +/- 2.9e6 years [290301 BC, 294241 AD]
+ ns nanosecond +/- 292 years [ 1678 AD, 2262 AD]
+ ps picosecond +/- 106 days [ 1969 AD, 1970 AD]
+ fs femtosecond +/- 2.6 hours [ 1969 AD, 1970 AD]
+ as attosecond +/- 9.2 seconds [ 1969 AD, 1970 AD]
======== ================ ======================= ==========================
Business Day Functionality
==========================
-To allow the datetime to be used in contexts where accounting for weekends
-and holidays is important, NumPy includes a set of functions for
-working with business days.
+To allow the datetime to be used in contexts where only certain days of
+the week are valid, NumPy includes a set of "busday" (business day)
+functions.
+
+The default for busday functions is that the only valid days are Monday
+through Friday (the usual business days). The implementation is based on
+a "weekmask" containing 7 Boolean flags to indicate valid days; custom
+weekmasks are possible that specify other sets of valid days.
+
+The "busday" functions can additionally check a list of "holiday" dates,
+specific dates that are not valid days.
The function :func:`busday_offset` allows you to apply offsets
-specified in business days to datetimes with a unit of 'day'. By default,
-a business date is defined to be any date which falls on Monday through
-Friday, but this can be customized with a weekmask and a list of holidays.
+specified in business days to datetimes with a unit of 'D' (day).
.. admonition:: Example
@@ -266,7 +278,7 @@ is necessary to get a desired answer.
The function is also useful for computing some kinds of days
like holidays. In Canada and the U.S., Mother's day is on
-the second Sunday in May, which can be computed with a special
+the second Sunday in May, which can be computed with a custom
weekmask.
.. admonition:: Example
@@ -274,11 +286,67 @@ weekmask.
>>> np.busday_offset('2012-05', 1, roll='forward', weekmask='Sun')
numpy.datetime64('2012-05-13','D')
-When performance is important for manipulating many business date
+When performance is important for manipulating many business dates
with one particular choice of weekmask and holidays, there is
an object :class:`busdaycalendar` which stores the data necessary
in an optimized form.
-The other two functions for business days are :func:`is_busday`
-and :func:`busday_count`, which are more straightforward and
-not explained here.
+np.is_busday():
+```````````````
+To test a datetime64 value to see if it is a valid day, use :func:`is_busday`.
+
+.. admonition:: Example
+
+ >>> np.is_busday(np.datetime64('2011-07-15')) # a Friday
+ True
+ >>> np.is_busday(np.datetime64('2011-07-16')) # a Saturday
+ False
+ >>> np.is_busday(np.datetime64('2011-07-16'), weekmask="Sat Sun")
+ True
+ >>> a = np.arange(np.datetime64('2011-07-11'), np.datetime64('2011-07-18'))
+ >>> np.is_busday(a)
+ array([ True, True, True, True, True, False, False], dtype='bool')
+
+np.busday_count():
+``````````````````
+To find how many valid days there are in a specified range of datetime64
+dates, use :func:`busday_count`:
+
+.. admonition:: Example
+
+ >>> np.busday_count(np.datetime64('2011-07-11'), np.datetime64('2011-07-18'))
+ 5
+ >>> np.busday_count(np.datetime64('2011-07-18'), np.datetime64('2011-07-11'))
+ 0
+ # note: In future this will likely return -5, not 0
+
+If you have an array of datetime64 day values, and you want a count of
+how many of them are valid dates, you can do this:
+
+.. admonition:: Example
+
+ >>> a = np.arange(np.datetime64('2011-07-11'), np.datetime64('2011-07-18'))
+ >>> np.count_nonzero(np.is_busday(a))
+ 5
+
+
+
+Custom Weekmasks
+----------------
+
+Here are several examples of custom weekmask values. These examples
+specify the "busday" default of Monday through Friday being valid days.
+
+Some examples::
+
+ # Positional sequences; positions are Monday through Sunday.
+ # Length of the sequence must be exactly 7.
+ weekmask = [1, 1, 1, 1, 1, 0, 0]
+ # list or other sequence; 0 == invalid day, 1 == valid day
+ weekmask = "1111100"
+ # string '0' == invalid day, '1' == valid day
+
+ # string abbreviations from this list: Mon Tue Wed Thu Fri Sat Sun
+ weekmask = "Mon Tue Wed Thu Fri"
+ # any amount of whitespace is allowed; abbreviations are case-sensitive.
+ weekmask = "MonTue Wed Thu\tFri"
diff --git a/numpy/add_newdocs.py b/numpy/add_newdocs.py
index 1e1d237a4..64f2f436a 100644
--- a/numpy/add_newdocs.py
+++ b/numpy/add_newdocs.py
@@ -5993,44 +5993,52 @@ add_newdoc('numpy.core.multiarray', 'busdaycalendar',
"""
busdaycalendar(weekmask='1111100', holidays=None)
- A business day calendar object that efficiently stores
- information defining business days for the business
- day-related functions.
+ A business day calendar object that efficiently stores information
+ defining valid days for the busday family of functions.
+
+ The default valid days are Monday through Friday ("business days").
+ A busdaycalendar object can be specified with any set of weekly
+ valid days, plus an optional "holiday" dates that always will be invalid.
+
+ Once a busdaycalendar object is created, the weekmask and holidays
+ cannot be modified.
.. versionadded:: 1.7.0
Parameters
----------
weekmask : str or array_like of bool, optional
- A seven-element array indicating which of Monday through Sunday may
- be valid business days. May be specified as a list or array, like
- [1,1,1,1,1,0,0], a length-seven string like '1111100', or a string
- of three-letter weekday names, like 'MonTueWedThuFri'. The latter
- string representation is most useful when only one day of the
- week is important, like 'Mon' if you want to calculate the date
- of Easter.
+ A seven-element array indicating which of Monday through Sunday are
+ valid days. May be specified as a length-seven list or array, like
+ [1,1,1,1,1,0,0]; a length-seven string, like '1111100'; or a string
+ like "Mon Tue Wed Thu Fri", made up of 3-character abbreviations for
+ weekdays, optionally separated by white space. Valid abbreviations
+ are: Mon Tue Wed Thu Fri Sat Sun
holidays : array_like of datetime64[D], optional
- An array of dates which should be blacked out from being considered
- as business days. They may be specified in any order, and NaT
- (not-a-time) dates are ignored. Internally, this list is normalized
- into a form suited for fast business day calculations.
+ An array of dates to consider as invalid dates, no matter which
+ weekday they fall upon. Holiday dates may be specified in any
+ order, and NaT (not-a-time) dates are ignored. This list is
+ saved in a normalized form that is suited for fast calculations
+ of valid days.
Returns
-------
out : busdaycalendar
A business day calendar object containing the specified
- weekmask and holidays.
+ weekmask and holidays values.
See Also
--------
- is_busday : Returns a boolean array indicating valid business days.
- busday_offset : Applies an offset counted in business days.
- busday_count : Counts how many business days are in a half-open date range.
+ is_busday : Returns a boolean array indicating valid days.
+ busday_offset : Applies an offset counted in valid days.
+ busday_count : Counts how many valid days are in a half-open date range.
Attributes
----------
- weekmask : seven-element array of bool
- holidays : sorted array of datetime64[D]
+ Note: once a busdaycalendar object is created, you cannot modify the
+ weekmask or holidays. The attributes return copies of internal data.
+ weekmask : (copy) seven-element array of bool
+ holidays : (copy) sorted array of datetime64[D]
Examples
--------
@@ -6046,17 +6054,16 @@ add_newdoc('numpy.core.multiarray', 'busdaycalendar',
""")
add_newdoc('numpy.core.multiarray', 'busdaycalendar', ('weekmask',
- """A copy of the seven-element boolean mask indicating valid business days."""))
+ """A copy of the seven-element boolean mask indicating valid days."""))
add_newdoc('numpy.core.multiarray', 'busdaycalendar', ('holidays',
- """A copy of the holiday array indicating blacked out business days."""))
+ """A copy of the holiday array indicating additional invalid days."""))
add_newdoc('numpy.core.multiarray', 'is_busday',
"""
is_busday(dates, weekmask='1111100', holidays=None, busdaycal=None, out=None)
- Calculates which of the given dates are valid business days, and
- which are not.
+ Calculates which of the given dates are valid days, and which are not.
.. versionadded:: 1.7.0
@@ -6065,20 +6072,19 @@ add_newdoc('numpy.core.multiarray', 'is_busday',
dates : array_like of datetime64[D]
The array of dates to process.
weekmask : str or array_like of bool, optional
- A seven-element array indicating which of Monday through Sunday may
- be valid business days. May be specified as a list or array, like
- [1,1,1,1,1,0,0], a length-seven string like '1111100', or a string
- of three-letter weekday names, like 'MonTueWedThuFri'. The latter
- string representation is most useful when only one day of the
- week is important, like 'Mon' if you want to calculate the date
- of Easter.
+ A seven-element array indicating which of Monday through Sunday are
+ valid days. May be specified as a length-seven list or array, like
+ [1,1,1,1,1,0,0]; a length-seven string, like '1111100'; or a string
+ like "Mon Tue Wed Thu Fri", made up of 3-character abbreviations for
+ weekdays, optionally separated by white space. Valid abbreviations
+ are: Mon Tue Wed Thu Fri Sat Sun
holidays : array_like of datetime64[D], optional
- An array of dates which should be blacked out from being considered
- as business days. They may be specified in any order, and NaT
- (not-a-time) dates are ignored. Internally, this list is normalized
- into a form suited for fast business day calculations.
+ An array of dates to consider as invalid dates. They may be
+ specified in any order, and NaT (not-a-time) dates are ignored.
+ This list is saved in a normalized form that is suited for
+ fast calculations of valid days.
busdaycal : busdaycalendar, optional
- A `busdaycalendar` object which specifies the business days. If this
+ A `busdaycalendar` object which specifies the valid days. If this
parameter is provided, neither weekmask nor holidays may be
provided.
out : array of bool, optional
@@ -6088,13 +6094,13 @@ add_newdoc('numpy.core.multiarray', 'is_busday',
-------
out : array of bool
An array with the same shape as ``dates``, containing True for
- each valid business day, and False for the others.
+ each valid day, and False for each invalid day.
See Also
--------
- busdaycalendar: An object for efficiently specifying which are business days.
- busday_offset : Applies an offset counted in business days.
- busday_count : Counts how many business days are in a half-open date range.
+ busdaycalendar: An object that specifies a custom set of valid days.
+ busday_offset : Applies an offset counted in valid days.
+ busday_count : Counts how many valid days are in a half-open date range.
Examples
--------
@@ -6108,9 +6114,9 @@ add_newdoc('numpy.core.multiarray', 'busday_offset',
"""
busday_offset(dates, offsets, roll='raise', weekmask='1111100', holidays=None, busdaycal=None, out=None)
- First adjusts the date to fall on a business day according to
+ First adjusts the date to fall on a valid day according to
the ``roll`` rule, then applies offsets to the given dates
- counted in business days.
+ counted in valid days.
.. versionadded:: 1.7.0
@@ -6121,36 +6127,35 @@ add_newdoc('numpy.core.multiarray', 'busday_offset',
offsets : array_like of int
The array of offsets, which is broadcast with ``dates``.
roll : {'raise', 'nat', 'forward', 'following', 'backward', 'preceding', 'modifiedfollowing', 'modifiedpreceding'}, optional
- How to treat dates that do not fall on a business day. The default
+ How to treat dates that do not fall on a valid day. The default
is 'raise'.
- * 'raise' means to raise an exception for invalid business days.
- * 'nat' means to return a NaT (not-a-time) for invalid business days.
- * 'forward' and 'following' mean to take the first business day
+ * 'raise' means to raise an exception for an invalid day.
+ * 'nat' means to return a NaT (not-a-time) for an invalid day.
+ * 'forward' and 'following' mean to take the first valid day
later in time.
- * 'backward' and 'preceding' mean to take the first business day
+ * 'backward' and 'preceding' mean to take the first valid day
earlier in time.
- * 'modifiedfollowing' means to take the first business day
+ * 'modifiedfollowing' means to take the first valid day
later in time unless it is across a Month boundary, in which
- case to take the first business day earlier in time.
- * 'modifiedpreceding' means to take the first business day
+ case to take the first valid day earlier in time.
+ * 'modifiedpreceding' means to take the first valid day
earlier in time unless it is across a Month boundary, in which
- case to take the first business day later in time.
+ case to take the first valid day later in time.
weekmask : str or array_like of bool, optional
- A seven-element array indicating which of Monday through Sunday may
- be valid business days. May be specified as a list or array, like
- [1,1,1,1,1,0,0], a length-seven string like '1111100', or a string
- of three-letter weekday names, like 'MonTueWedThuFri'. The latter
- string representation is most useful when only one day of the
- week is important, like 'Mon' if you want to calculate the date
- of Easter.
+ A seven-element array indicating which of Monday through Sunday are
+ valid days. May be specified as a length-seven list or array, like
+ [1,1,1,1,1,0,0]; a length-seven string, like '1111100'; or a string
+ like "Mon Tue Wed Thu Fri", made up of 3-character abbreviations for
+ weekdays, optionally separated by white space. Valid abbreviations
+ are: Mon Tue Wed Thu Fri Sat Sun
holidays : array_like of datetime64[D], optional
- An array of dates which should be blacked out from being considered
- as business days. They may be specified in any order, and NaT
- (not-a-time) dates are ignored. Internally, this list is normalized
- into a form suited for fast business day calculations.
+ An array of dates to consider as invalid dates. They may be
+ specified in any order, and NaT (not-a-time) dates are ignored.
+ This list is saved in a normalized form that is suited for
+ fast calculations of valid days.
busdaycal : busdaycalendar, optional
- A `busdaycalendar` object which specifies the business days. If this
+ A `busdaycalendar` object which specifies the valid days. If this
parameter is provided, neither weekmask nor holidays may be
provided.
out : array of datetime64[D], optional
@@ -6164,9 +6169,9 @@ add_newdoc('numpy.core.multiarray', 'busday_offset',
See Also
--------
- busdaycalendar: An object for efficiently specifying which are business days.
- is_busday : Returns a boolean array indicating valid business days.
- busday_count : Counts how many business days are in a half-open date range.
+ busdaycalendar: An object that specifies a custom set of valid days.
+ is_busday : Returns a boolean array indicating valid days.
+ busday_count : Counts how many valid days are in a half-open date range.
Examples
--------
@@ -6199,9 +6204,14 @@ add_newdoc('numpy.core.multiarray', 'busday_count',
"""
busday_count(begindates, enddates, weekmask='1111100', holidays=[], busdaycal=None, out=None)
- Counts the number of business days between `begindates` and
+ Counts the number of valid days between `begindates` and
`enddates`, not including the day of `enddates`.
+ If ``enddates`` specifies a date value that is earlier than the
+ corresponding ``begindates`` date value, the count will be 0.
+ However, in future this may change to a negative count of valid
+ days.
+
.. versionadded:: 1.7.0
Parameters
@@ -6212,20 +6222,19 @@ add_newdoc('numpy.core.multiarray', 'busday_count',
The array of the end dates for counting, which are excluded
from the count themselves.
weekmask : str or array_like of bool, optional
- A seven-element array indicating which of Monday through Sunday may
- be valid business days. May be specified as a list or array, like
- [1,1,1,1,1,0,0], a length-seven string like '1111100', or a string
- of three-letter weekday names, like 'MonTueWedThuFri'. The latter
- string representation is most useful when only one day of the
- week is important, like 'Mon' if you want to calculate the date
- of Easter.
+ A seven-element array indicating which of Monday through Sunday are
+ valid days. May be specified as a length-seven list or array, like
+ [1,1,1,1,1,0,0]; a length-seven string, like '1111100'; or a string
+ like "Mon Tue Wed Thu Fri", made up of 3-character abbreviations for
+ weekdays, optionally separated by white space. Valid abbreviations
+ are: Mon Tue Wed Thu Fri Sat Sun
holidays : array_like of datetime64[D], optional
- An array of dates which should be blacked out from being considered
- as business days. They may be specified in any order, and NaT
- (not-a-time) dates are ignored. Internally, this list is normalized
- into a form suited for fast business day calculations.
+ An array of dates to consider as invalid dates. They may be
+ specified in any order, and NaT (not-a-time) dates are ignored.
+ This list is saved in a normalized form that is suited for
+ fast calculations of valid days.
busdaycal : busdaycalendar, optional
- A `busdaycalendar` object which specifies the business days. If this
+ A `busdaycalendar` object which specifies the valid days. If this
parameter is provided, neither weekmask nor holidays may be
provided.
out : array of int, optional
@@ -6235,14 +6244,14 @@ add_newdoc('numpy.core.multiarray', 'busday_count',
-------
out : array of int
An array with a shape from broadcasting ``begindates`` and ``enddates``
- together, containing the number of business days between
+ together, containing the number of valid days between
the begin and end dates.
See Also
--------
- busdaycalendar: An object for efficiently specifying which are business days.
- is_busday : Returns a boolean array indicating valid business days.
- busday_offset : Applies an offset counted in business days.
+ busdaycalendar: An object that specifies a custom set of valid days.
+ is_busday : Returns a boolean array indicating valid days.
+ busday_offset : Applies an offset counted in valid days.
Examples
--------
diff --git a/numpy/core/src/multiarray/datetime_busdaycal.c b/numpy/core/src/multiarray/datetime_busdaycal.c
index ae35212ea..018912ee8 100644
--- a/numpy/core/src/multiarray/datetime_busdaycal.c
+++ b/numpy/core/src/multiarray/datetime_busdaycal.c
@@ -46,6 +46,7 @@ PyArray_WeekMaskConverter(PyObject *weekmask_in, npy_bool *weekmask)
if (PyBytes_Check(obj)) {
char *str;
Py_ssize_t len;
+ int i;
if (PyBytes_AsStringAndSize(obj, &str, &len) < 0) {
Py_DECREF(obj);
@@ -54,7 +55,6 @@ PyArray_WeekMaskConverter(PyObject *weekmask_in, npy_bool *weekmask)
/* Length 7 is a string like "1111100" */
if (len == 7) {
- int i;
for (i = 0; i < 7; ++i) {
switch(str[i]) {
case '0':
@@ -64,70 +64,81 @@ PyArray_WeekMaskConverter(PyObject *weekmask_in, npy_bool *weekmask)
weekmask[i] = 1;
break;
default:
- goto invalid_weekmask_string;
+ goto general_weekmask_string;
}
}
goto finish;
}
- /* Length divisible by 3 is a string like "Mon" or "MonWedFri" */
- else if (len % 3 == 0) {
- int i;
- memset(weekmask, 0, 7);
- for (i = 0; i < len; i += 3) {
- switch (str[i]) {
- case 'M':
- if (str[i+1] == 'o' && str[i+2] == 'n') {
- weekmask[0] = 1;
- }
- else {
- goto invalid_weekmask_string;
- }
- break;
- case 'T':
- if (str[i+1] == 'u' && str[i+2] == 'e') {
- weekmask[1] = 1;
- }
- else if (str[i+1] == 'h' && str[i+2] == 'u') {
- weekmask[3] = 1;
- }
- else {
- goto invalid_weekmask_string;
- }
- break;
- case 'W':
- if (str[i+1] == 'e' && str[i+2] == 'd') {
- weekmask[2] = 1;
- }
- else {
- goto invalid_weekmask_string;
- }
- break;
- case 'F':
- if (str[i+1] == 'r' && str[i+2] == 'i') {
- weekmask[4] = 1;
- }
- else {
- goto invalid_weekmask_string;
- }
- break;
- case 'S':
- if (str[i+1] == 'a' && str[i+2] == 't') {
- weekmask[5] = 1;
- }
- else if (str[i+1] == 'u' && str[i+2] == 'n') {
- weekmask[6] = 1;
- }
- else {
- goto invalid_weekmask_string;
- }
- break;
- }
+
+general_weekmask_string:
+ /* a string like "SatSun" or "Mon Tue Wed" */
+ memset(weekmask, 0, 7);
+ for (i = 0; i < len; i += 3) {
+ while (isspace(str[i]))
+ ++i;
+
+ if (i == len) {
+ goto finish;
+ }
+ else if (i + 2 >= len) {
+ goto invalid_weekmask_string;
}
- goto finish;
+ switch (str[i]) {
+ case 'M':
+ if (str[i+1] == 'o' && str[i+2] == 'n') {
+ weekmask[0] = 1;
+ }
+ else {
+ goto invalid_weekmask_string;
+ }
+ break;
+ case 'T':
+ if (str[i+1] == 'u' && str[i+2] == 'e') {
+ weekmask[1] = 1;
+ }
+ else if (str[i+1] == 'h' && str[i+2] == 'u') {
+ weekmask[3] = 1;
+ }
+ else {
+ goto invalid_weekmask_string;
+ }
+ break;
+ case 'W':
+ if (str[i+1] == 'e' && str[i+2] == 'd') {
+ weekmask[2] = 1;
+ }
+ else {
+ goto invalid_weekmask_string;
+ }
+ break;
+ case 'F':
+ if (str[i+1] == 'r' && str[i+2] == 'i') {
+ weekmask[4] = 1;
+ }
+ else {
+ goto invalid_weekmask_string;
+ }
+ break;
+ case 'S':
+ if (str[i+1] == 'a' && str[i+2] == 't') {
+ weekmask[5] = 1;
+ }
+ else if (str[i+1] == 'u' && str[i+2] == 'n') {
+ weekmask[6] = 1;
+ }
+ else {
+ goto invalid_weekmask_string;
+ }
+ break;
+ default:
+ goto invalid_weekmask_string;
+ }
}
+ goto finish;
+
invalid_weekmask_string:
PyErr_Format(PyExc_ValueError,
"Invalid business day weekmask string \"%s\"",
diff --git a/numpy/core/tests/test_datetime.py b/numpy/core/tests/test_datetime.py
index 2770364f0..563f9e87c 100644
--- a/numpy/core/tests/test_datetime.py
+++ b/numpy/core/tests/test_datetime.py
@@ -1440,8 +1440,28 @@ class TestDateTime(TestCase):
# Default M-F weekmask
assert_equal(bdd.weekmask, np.array([1,1,1,1,1,0,0], dtype='?'))
+ # Check string weekmask with varying whitespace.
+ bdd = np.busdaycalendar(weekmask="Sun TueWed Thu\tFri")
+ assert_equal(bdd.weekmask, np.array([0,1,1,1,1,0,1], dtype='?'))
+
+ # Check length 7 0/1 string
+ bdd = np.busdaycalendar(weekmask="0011001")
+ assert_equal(bdd.weekmask, np.array([0,0,1,1,0,0,1], dtype='?'))
+
+ # Check length 7 string weekmask.
+ bdd = np.busdaycalendar(weekmask="Mon Tue")
+ assert_equal(bdd.weekmask, np.array([1,1,0,0,0,0,0], dtype='?'))
+
# All-zeros weekmask should raise
assert_raises(ValueError, np.busdaycalendar, weekmask=[0,0,0,0,0,0,0])
+ # weekday names must be correct case
+ assert_raises(ValueError, np.busdaycalendar, weekmask="satsun")
+ # All-zeros weekmask should raise
+ assert_raises(ValueError, np.busdaycalendar, weekmask="")
+ # Invalid weekday name codes should raise
+ assert_raises(ValueError, np.busdaycalendar, weekmask="Mon Tue We")
+ assert_raises(ValueError, np.busdaycalendar, weekmask="Max")
+ assert_raises(ValueError, np.busdaycalendar, weekmask="Monday Tue")
def test_datetime_busday_holidays_offset(self):
# With exactly one holiday