* Parses (almost) standard ISO 8601 date strings. The differences are: * * + The date "20100312" is parsed as the year 20100312, not as * equivalent to "2010-03-12". The '-' in the dates are not optional. * + Only seconds may have a decimal point, with up to 18 digits after it * (maximum attoseconds precision). * + Either a 'T' as in ISO 8601 or a ' ' may be used to separate * the dat
| 219 | * Returns 0 on success, -1 on failure. |
| 220 | */ |
| 221 | NPY_NO_EXPORT int |
| 222 | parse_iso_8601_datetime(char const *str, Py_ssize_t len, |
| 223 | NPY_DATETIMEUNIT unit, |
| 224 | NPY_CASTING casting, |
| 225 | npy_datetimestruct *out, |
| 226 | NPY_DATETIMEUNIT *out_bestunit, |
| 227 | npy_bool *out_special) |
| 228 | { |
| 229 | int year_leap = 0; |
| 230 | int i, numdigits; |
| 231 | char const *substr; |
| 232 | Py_ssize_t sublen; |
| 233 | NPY_DATETIMEUNIT bestunit; |
| 234 | |
| 235 | /* Initialize the output to all zeros */ |
| 236 | memset(out, 0, sizeof(npy_datetimestruct)); |
| 237 | out->month = 1; |
| 238 | out->day = 1; |
| 239 | |
| 240 | /* |
| 241 | * Convert the empty string and case-variants of "NaT" to not-a-time. |
| 242 | * Tried to use PyOS_stricmp, but that function appears to be broken, |
| 243 | * not even matching the strcmp function signature as it should. |
| 244 | */ |
| 245 | if (len <= 0 || (len == 3 && |
| 246 | tolower(str[0]) == 'n' && |
| 247 | tolower(str[1]) == 'a' && |
| 248 | tolower(str[2]) == 't')) { |
| 249 | out->year = NPY_DATETIME_NAT; |
| 250 | |
| 251 | /* |
| 252 | * Indicate that this was a special value, and |
| 253 | * recommend generic units. |
| 254 | */ |
| 255 | if (out_bestunit != NULL) { |
| 256 | *out_bestunit = NPY_FR_GENERIC; |
| 257 | } |
| 258 | if (out_special != NULL) { |
| 259 | *out_special = 1; |
| 260 | } |
| 261 | |
| 262 | return 0; |
| 263 | } |
| 264 | |
| 265 | if (unit == NPY_FR_GENERIC) { |
| 266 | PyErr_SetString(PyExc_ValueError, |
| 267 | "Cannot create a NumPy datetime other than NaT " |
| 268 | "with generic units"); |
| 269 | return -1; |
| 270 | } |
| 271 | |
| 272 | /* |
| 273 | * The string "today" means take today's date in local time, and |
| 274 | * convert it to a date representation. This date representation, if |
| 275 | * forced into a time unit, will be at midnight UTC. |
| 276 | * This is perhaps a little weird, but done so that the |
| 277 | * 'datetime64[D]' type produces the date you expect, rather than |
| 278 | * switching to an adjacent day depending on the current time and your |
no test coverage detected