* Converts a PyObject * into a datetime, in any of the forms supported. * * If the units metadata isn't known ahead of time, set meta->base * to -1, and this function will populate meta with either default * values or values from the input object. * * The 'casting' parameter is used to control what kinds of inputs * are accepted, and what happens. For example, with 'unsafe' casting, * unre
| 2371 | * Returns -1 on error, 0 on success. |
| 2372 | */ |
| 2373 | NPY_NO_EXPORT int |
| 2374 | convert_pyobject_to_datetime(PyArray_DatetimeMetaData *meta, PyObject *obj, |
| 2375 | NPY_CASTING casting, npy_datetime *out) |
| 2376 | { |
| 2377 | if (PyBytes_Check(obj) || PyUnicode_Check(obj)) { |
| 2378 | PyObject *utf8 = NULL; |
| 2379 | |
| 2380 | /* Convert to an UTF8 string for the date parser */ |
| 2381 | if (PyBytes_Check(obj)) { |
| 2382 | utf8 = PyUnicode_FromEncodedObject(obj, NULL, NULL); |
| 2383 | if (utf8 == NULL) { |
| 2384 | return -1; |
| 2385 | } |
| 2386 | } |
| 2387 | else { |
| 2388 | utf8 = obj; |
| 2389 | Py_INCREF(utf8); |
| 2390 | } |
| 2391 | |
| 2392 | Py_ssize_t len = 0; |
| 2393 | char const *str = PyUnicode_AsUTF8AndSize(utf8, &len); |
| 2394 | if (str == NULL) { |
| 2395 | Py_DECREF(utf8); |
| 2396 | return -1; |
| 2397 | } |
| 2398 | |
| 2399 | /* Parse the ISO date */ |
| 2400 | npy_datetimestruct dts; |
| 2401 | NPY_DATETIMEUNIT bestunit = NPY_FR_ERROR; |
| 2402 | if (parse_iso_8601_datetime(str, len, meta->base, casting, |
| 2403 | &dts, &bestunit, NULL) < 0) { |
| 2404 | Py_DECREF(utf8); |
| 2405 | return -1; |
| 2406 | } |
| 2407 | |
| 2408 | /* Use the detected unit if none was specified */ |
| 2409 | if (meta->base == NPY_FR_ERROR) { |
| 2410 | meta->base = bestunit; |
| 2411 | meta->num = 1; |
| 2412 | } |
| 2413 | |
| 2414 | if (convert_datetimestruct_to_datetime(meta, &dts, out) < 0) { |
| 2415 | Py_DECREF(utf8); |
| 2416 | return -1; |
| 2417 | } |
| 2418 | |
| 2419 | Py_DECREF(utf8); |
| 2420 | return 0; |
| 2421 | } |
| 2422 | /* Do no conversion on raw integers */ |
| 2423 | else if (PyLong_Check(obj)) { |
| 2424 | /* Don't allow conversion from an integer without specifying a unit */ |
| 2425 | if (meta->base == NPY_FR_ERROR || meta->base == NPY_FR_GENERIC) { |
| 2426 | PyErr_SetString(PyExc_ValueError, "Converting an integer to a " |
| 2427 | "NumPy datetime requires a specified unit"); |
| 2428 | return -1; |
| 2429 | } |
| 2430 | *out = PyLong_AsLongLong(obj); |
no test coverage detected