summaryrefslogtreecommitdiff
path: root/numpy
diff options
context:
space:
mode:
authorMark Wiebe <mwiebe@enthought.com>2011-06-16 16:40:35 -0500
committerMark Wiebe <mwiebe@enthought.com>2011-06-16 16:40:35 -0500
commit382233c3d0fb03f20224dbfbc21e803fd7078407 (patch)
tree7ee056ed11962f5966e95b42f5c5f86dae5a812a /numpy
parent06ef6b786baa632b2fc408e558e1c84008c87e0e (diff)
downloadnumpy-382233c3d0fb03f20224dbfbc21e803fd7078407.tar.gz
ENH: datetime-parsing: Apply the datetime unit casting rules to string parsing
Diffstat (limited to 'numpy')
-rw-r--r--numpy/core/src/multiarray/_datetime.h4
-rw-r--r--numpy/core/src/multiarray/datetime.c120
-rw-r--r--numpy/core/src/multiarray/methods.c2
-rw-r--r--numpy/core/src/multiarray/methods.h3
4 files changed, 75 insertions, 54 deletions
diff --git a/numpy/core/src/multiarray/_datetime.h b/numpy/core/src/multiarray/_datetime.h
index fd1c3e22f..a94abc6c7 100644
--- a/numpy/core/src/multiarray/_datetime.h
+++ b/numpy/core/src/multiarray/_datetime.h
@@ -221,6 +221,8 @@ get_datetime_iso_8601_strlen(int local, NPY_DATETIMEUNIT base);
* 'str' must be a NULL-terminated string, and 'len' must be its length.
* 'unit' should contain -1 if the unit is unknown, or the unit
* which will be used if it is.
+ * 'casting' controls how the detected unit from the string is allowed
+ * to be cast to the 'unit' parameter.
*
* 'out' gets filled with the parsed date-time.
* 'out_local' gets set to 1 if the parsed time was in local time,
@@ -234,12 +236,12 @@ get_datetime_iso_8601_strlen(int local, NPY_DATETIMEUNIT base);
* 'D', for 'now', the unit recommended is 's', and for 'NaT'
* the unit recommended is 'Y'.
*
- *
* Returns 0 on success, -1 on failure.
*/
NPY_NO_EXPORT int
parse_iso_8601_date(char *str, int len,
NPY_DATETIMEUNIT unit,
+ NPY_CASTING casting,
npy_datetimestruct *out,
npy_bool *out_local,
NPY_DATETIMEUNIT *out_bestunit,
diff --git a/numpy/core/src/multiarray/datetime.c b/numpy/core/src/multiarray/datetime.c
index 27f4c11ed..e344edcbd 100644
--- a/numpy/core/src/multiarray/datetime.c
+++ b/numpy/core/src/multiarray/datetime.c
@@ -20,6 +20,7 @@
#include "numpy/npy_3kcompat.h"
#include "numpy/arrayscalars.h"
+#include "methods.h"
#include "_datetime.h"
/*
@@ -2457,6 +2458,8 @@ add_minutes_to_datetimestruct(npy_datetimestruct *dts, int minutes)
* 'str' must be a NULL-terminated string, and 'len' must be its length.
* 'unit' should contain -1 if the unit is unknown, or the unit
* which will be used if it is.
+ * 'casting' controls how the detected unit from the string is allowed
+ * to be cast to the 'unit' parameter.
*
* 'out' gets filled with the parsed date-time.
* 'out_local' gets set to 1 if the parsed time was in local time,
@@ -2470,12 +2473,12 @@ add_minutes_to_datetimestruct(npy_datetimestruct *dts, int minutes)
* 'D', for 'now', the unit recommended is 's', and for 'NaT'
* the unit recommended is 'Y'.
*
- *
* Returns 0 on success, -1 on failure.
*/
NPY_NO_EXPORT int
parse_iso_8601_date(char *str, int len,
NPY_DATETIMEUNIT unit,
+ NPY_CASTING casting,
npy_datetimestruct *out,
npy_bool *out_local,
NPY_DATETIMEUNIT *out_bestunit,
@@ -2484,6 +2487,7 @@ parse_iso_8601_date(char *str, int len,
int year_leap = 0;
int i, numdigits;
char *substr, sublen;
+ NPY_DATETIMEUNIT bestunit;
/* Initialize the output to all zeros */
memset(out, 0, sizeof(npy_datetimestruct));
@@ -2563,6 +2567,8 @@ parse_iso_8601_date(char *str, int len,
out->month = tm_.tm_mon + 1;
out->day = tm_.tm_mday;
+ bestunit = NPY_FR_D;
+
/*
* Indicate that this was a special value, and
* is a date (unit 'D').
@@ -2571,12 +2577,22 @@ parse_iso_8601_date(char *str, int len,
*out_local = 0;
}
if (out_bestunit != NULL) {
- *out_bestunit = NPY_FR_D;
+ *out_bestunit = bestunit;
}
if (out_special != NULL) {
*out_special = 1;
}
+ /* Check the casting rule */
+ if (unit != -1 && !can_cast_datetime64_units(bestunit, unit,
+ casting)) {
+ PyErr_Format(PyExc_ValueError, "Cannot parse \"%s\" as unit "
+ "'%s' using casting rule %s",
+ str, _datetime_strings[unit],
+ npy_casting_to_string(casting));
+ return -1;
+ }
+
return 0;
}
@@ -2587,14 +2603,6 @@ parse_iso_8601_date(char *str, int len,
time_t rawtime = 0;
PyArray_DatetimeMetaData meta;
- /* 'now' only works for units of hours or smaller */
- if (unit != -1 && unit < NPY_FR_h) {
- PyErr_SetString(PyExc_ValueError,
- "Special value 'now' can only be converted "
- "to a NumPy datetime with 'h' or smaller units");
- return -1;
- }
-
time(&rawtime);
/* Set up a dummy metadata for the conversion */
@@ -2602,6 +2610,8 @@ parse_iso_8601_date(char *str, int len,
meta.num = 1;
meta.events = 1;
+ bestunit = NPY_FR_s;
+
/*
* Indicate that this was a special value, and
* use 's' because the time() function has resolution
@@ -2611,12 +2621,22 @@ parse_iso_8601_date(char *str, int len,
*out_local = 0;
}
if (out_bestunit != NULL) {
- *out_bestunit = NPY_FR_s;
+ *out_bestunit = bestunit;
}
if (out_special != NULL) {
*out_special = 1;
}
+ /* Check the casting rule */
+ if (unit != -1 && !can_cast_datetime64_units(bestunit, unit,
+ casting)) {
+ PyErr_Format(PyExc_ValueError, "Cannot parse \"%s\" as unit "
+ "'%s' using casting rule %s",
+ str, _datetime_strings[unit],
+ npy_casting_to_string(casting));
+ return -1;
+ }
+
return convert_datetime_to_datetimestruct(&meta, rawtime, out);
}
@@ -2664,9 +2684,7 @@ parse_iso_8601_date(char *str, int len,
if (out_local != NULL) {
*out_local = 0;
}
- if (out_bestunit != NULL) {
- *out_bestunit = NPY_FR_Y;
- }
+ bestunit = NPY_FR_Y;
goto finish;
}
else if (*substr == '-') {
@@ -2703,9 +2721,7 @@ parse_iso_8601_date(char *str, int len,
if (out_local != NULL) {
*out_local = 0;
}
- if (out_bestunit != NULL) {
- *out_bestunit = NPY_FR_M;
- }
+ bestunit = NPY_FR_M;
goto finish;
}
else if (*substr == '-') {
@@ -2743,9 +2759,7 @@ parse_iso_8601_date(char *str, int len,
if (out_local != NULL) {
*out_local = 0;
}
- if (out_bestunit != NULL) {
- *out_bestunit = NPY_FR_D;
- }
+ bestunit = NPY_FR_D;
goto finish;
}
else if (*substr != 'T' && *substr != ' ') {
@@ -2778,9 +2792,7 @@ parse_iso_8601_date(char *str, int len,
--sublen;
}
else {
- if (out_bestunit != NULL) {
- *out_bestunit = NPY_FR_h;
- }
+ bestunit = NPY_FR_h;
goto parse_timezone;
}
@@ -2811,9 +2823,7 @@ parse_iso_8601_date(char *str, int len,
--sublen;
}
else {
- if (out_bestunit != NULL) {
- *out_bestunit = NPY_FR_m;
- }
+ bestunit = NPY_FR_m;
goto parse_timezone;
}
@@ -2844,9 +2854,7 @@ parse_iso_8601_date(char *str, int len,
--sublen;
}
else {
- if (out_bestunit != NULL) {
- *out_bestunit = NPY_FR_s;
- }
+ bestunit = NPY_FR_s;
goto parse_timezone;
}
@@ -2863,13 +2871,11 @@ parse_iso_8601_date(char *str, int len,
}
if (sublen == 0 || !isdigit(*substr)) {
- if (out_bestunit != NULL) {
- if (numdigits > 3) {
- *out_bestunit = NPY_FR_us;
- }
- else {
- *out_bestunit = NPY_FR_ms;
- }
+ if (numdigits > 3) {
+ bestunit = NPY_FR_us;
+ }
+ else {
+ bestunit = NPY_FR_ms;
}
goto parse_timezone;
}
@@ -2887,13 +2893,11 @@ parse_iso_8601_date(char *str, int len,
}
if (sublen == 0 || !isdigit(*substr)) {
- if (out_bestunit != NULL) {
- if (numdigits > 3) {
- *out_bestunit = NPY_FR_ps;
- }
- else {
- *out_bestunit = NPY_FR_ns;
- }
+ if (numdigits > 3) {
+ bestunit = NPY_FR_ps;
+ }
+ else {
+ bestunit = NPY_FR_ns;
}
goto parse_timezone;
}
@@ -2910,13 +2914,11 @@ parse_iso_8601_date(char *str, int len,
}
}
- if (out_bestunit != NULL) {
- if (numdigits > 3) {
- *out_bestunit = NPY_FR_as;
- }
- else {
- *out_bestunit = NPY_FR_fs;
- }
+ if (numdigits > 3) {
+ bestunit = NPY_FR_as;
+ }
+ else {
+ bestunit = NPY_FR_fs;
}
parse_timezone:
@@ -3072,6 +3074,20 @@ parse_timezone:
}
finish:
+ if (out_bestunit != NULL) {
+ *out_bestunit = bestunit;
+ }
+
+ /* Check the casting rule */
+ if (unit != -1 && !can_cast_datetime64_units(bestunit, unit,
+ casting)) {
+ PyErr_Format(PyExc_ValueError, "Cannot parse \"%s\" as unit "
+ "'%s' using casting rule %s",
+ str, _datetime_strings[unit],
+ npy_casting_to_string(casting));
+ return -1;
+ }
+
return 0;
parse_error:
@@ -3863,8 +3879,8 @@ convert_pyobject_to_datetime(PyArray_DatetimeMetaData *meta, PyObject *obj,
}
/* Parse the ISO date */
- if (parse_iso_8601_date(str, len, meta->base, &dts,
- NULL, &bestunit, NULL) < 0) {
+ if (parse_iso_8601_date(str, len, meta->base, NPY_SAFE_CASTING,
+ &dts, NULL, &bestunit, NULL) < 0) {
Py_DECREF(bytes);
return -1;
}
diff --git a/numpy/core/src/multiarray/methods.c b/numpy/core/src/multiarray/methods.c
index 9502bc9f0..b9954e7f0 100644
--- a/numpy/core/src/multiarray/methods.c
+++ b/numpy/core/src/multiarray/methods.c
@@ -766,7 +766,7 @@ array_setasflat(PyArrayObject *self, PyObject *args)
Py_RETURN_NONE;
}
-static const char *
+NPY_NO_EXPORT const char *
npy_casting_to_string(NPY_CASTING casting)
{
switch (casting) {
diff --git a/numpy/core/src/multiarray/methods.h b/numpy/core/src/multiarray/methods.h
index 642265ccd..fc3b987fa 100644
--- a/numpy/core/src/multiarray/methods.h
+++ b/numpy/core/src/multiarray/methods.h
@@ -5,4 +5,7 @@
extern NPY_NO_EXPORT PyMethodDef array_methods[];
#endif
+NPY_NO_EXPORT const char *
+npy_casting_to_string(NPY_CASTING casting);
+
#endif