diff options
author | Mark Wiebe <mwiebe@enthought.com> | 2011-06-16 16:40:35 -0500 |
---|---|---|
committer | Mark Wiebe <mwiebe@enthought.com> | 2011-06-16 16:40:35 -0500 |
commit | 382233c3d0fb03f20224dbfbc21e803fd7078407 (patch) | |
tree | 7ee056ed11962f5966e95b42f5c5f86dae5a812a /numpy | |
parent | 06ef6b786baa632b2fc408e558e1c84008c87e0e (diff) | |
download | numpy-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.h | 4 | ||||
-rw-r--r-- | numpy/core/src/multiarray/datetime.c | 120 | ||||
-rw-r--r-- | numpy/core/src/multiarray/methods.c | 2 | ||||
-rw-r--r-- | numpy/core/src/multiarray/methods.h | 3 |
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 |