8000 ENH: datetime: Applying changes for Chuck and Derek's feedback · numpy/numpy@7c1c7a8 · GitHub
[go: up one dir, main page]

Skip to content

Commit 7c1c7a8

Browse files
author
Mark Wiebe
committed
ENH: datetime: Applying changes for Chuck and Derek's feedback
1 parent 46c91af commit 7c1c7a8

File tree

2 files changed

+45
-22
lines changed

2 files changed

+45
-22
lines changed

numpy/core/src/multiarray/convert_datatype.c

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,11 @@ PyArray_AdaptFlexibleDType(PyObject *data_obj, PyArray_Descr *data_dtype,
142142
int flex_type_num;
143143

144144
if (*flex_dtype == NULL) {
145+
if (!PyErr_Occurred()) {
146+
PyErr_SetString(PyExc_RuntimeError,
147+
"NumPy AdaptFlexibleDType was called with NULL flex_dtype "
148+
"but no error set");
149+
}
145150
return;
146151
}
147152

@@ -162,40 +167,44 @@ PyArray_AdaptFlexibleDType(PyObject *data_obj, PyArray_Descr *data_dtype,
162167
else {
163168
npy_intp size = 8;
164169

165-
/* Get a string-size estimate of the input */
170+
/*
171+
* Get a string-size estimate of the input. These
172+
* are generallly the size needed, rounded up to
173+
* a multiple of eight.
174+
*/
166175
switch (data_dtype->type_num) {
167176
case NPY_BOOL:
168-
size = 5;
177+
size = 8;
169178
break;
170179
case NPY_UBYTE:
171-
size = 3;
180+
size = 8;
172181
break;
173182
case NPY_BYTE:
174-
size = 4;
183+
size = 8;
175184
break;
176185
case NPY_USHORT:
177- size = 5;
186+
size = 8;
178187
break;
179188
case NPY_SHORT:
180-
size = 6;
189+
size = 8;
181190
break;
182191
case NPY_UINT:
183-
size = 10;
192+
size = 16;
184193
break;
185194
case NPY_INT:
186-
size = 6;
195+
size = 16;
187196
break;
188197
case NPY_ULONG:
189-
size = 20;
198+
size = 24;
190199
break;
191200
case NPY_LONG:
192-
size = 21;
201+
size = 24;
193202
break;
194203
case NPY_ULONGLONG:
195-
size = 20;
204+
size = 24;
196205
break;
197206
case NPY_LONGLONG:
198-
size = 21;
207+
size = 24;
199208
break;
200209
case NPY_HALF:
201210
case NPY_FLOAT:

numpy/core/src/multiarray/datetime_strings.c

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,11 @@ parse_iso_8601_datetime(char *str, int len,
7777
out->month = 1;
7878
out->day = 1;
7979

80-
/* The empty string and case-variants of "NaT" parse to not-a-time */
80+
/*
81+
* Convert the empty string and case-variants of "NaT" to not-a-time.
82+
* Tried to use PyOS_stricmp, but that function appears to be broken,
83+
* not even matching the strcmp function 8000 signature as it should.
84+
*/
8185
if (len <= 0 || (len == 3 &&
8286
tolower(str[0]) == 'n' &&
8387
tolower(str[1]) == 'a' &&
@@ -109,9 +113,11 @@ parse_iso_8601_datetime(char *str, int len,
109113
}
110114

111115
/*
112-
* The string "today" resolves to midnight of today's local date in UTC.
113-
* This is perhaps a little weird, but done so that further truncation
114-
* to a 'datetime64[D]' type produces the date you expect, rather than
116+
* The string "today" means take today's date in local time, and
117+
* convert it to a date representation. This date representation, if
118+
* forced into a time unit, will be at midnight UTC.
119+
* This is perhaps a little weird, but done so that the
120+
* 'datetime64[D]' type produces the date you expect, rather than
115121
* switching to an adjacent day depending on the current time and your
116122
* timezone.
117123
*/
@@ -126,15 +132,15 @@ parse_iso_8601_datetime(char *str, int len,
126132
time(&rawtime);
127133
#if defined(_WIN32)
128134
if (localtime_s(&tm_, &rawtime) != 0) {
129-
PyErr_SetString(PyExc_OSError, "Failed to use localtime_s to "
130-
"get local time");
135+
PyErr_SetString(PyExc_OSError, "Failed to obtain local time "
136+
"from localtime_s");
131137
return -1;
132138
}
133139
#else
134140
/* Other platforms may require something else */
135141
if (localtime_r(&rawtime, &tm_) == NULL) {
136-
PyErr_SetString(PyExc_OSError, "Failed to use localtime_r to "
137-
"get local time");
142+
PyErr_SetString(PyExc_OSError, "Failed obtain local time "
143+
"from localtime_r");
138144
return -1;
139145
}
140146
#endif
@@ -784,6 +790,9 @@ lossless_unit_from_datetimestruct(npy_datetimestruct *dts)
784790
* NULL-terminated string. If the string fits in the space exactly, 9E81
785791
* it leaves out the NULL terminator and returns success.
786792
*
793+
* The differences from ISO 8601 are the 'NaT' string, and
794+
* the number of year digits is >= 4 instead of strictly 4.
795+
*
787796
* If 'local' is non-zero, it produces a string in local time with
788797
* a +-#### timezone offset, otherwise it uses timezone Z (UTC).
789798
*
@@ -829,7 +838,7 @@ make_iso_8601_datetime(npy_datetimestruct *dts, char *outstr, int outlen,
829838
}
830839

831840
/* Only do local time within a reasonable year range */
832-
if ((dts->year <= 1900 || dts->year >= 10000) && tzoffset == -1) {
841+
if ((dts->year <= 1800 || dts->year >= 10000) && tzoffset == -1) {
833842
local = 0;
834843
}
835844

@@ -923,7 +932,7 @@ make_iso_8601_datetime(npy_datetimestruct *dts, char *outstr, int outlen,
923932
/*
924933
* Now the datetimestruct data is in the final form for
925934
* the string representation, so ensure that the data
926-
* isn't being cast according to the casting rule.
935+
* is being cast according to the casting rule.
927936
*/
928937
if (casting != NPY_UNSAFE_CASTING) {
929938
/* Producing a date as a local time is always 'unsafe' */
@@ -952,6 +961,11 @@ make_iso_8601_datetime(npy_datetimestruct *dts, char *outstr, int outlen,
952961
}
953962

954963
/* YEAR */
964+
/*
965+
* Can't use PyOS_snprintf, because it always produces a '\0'
966+
* character at the end, and NumPy string types are permitted
967+
* to have data all the way to the end of the buffer.
968+
*/
955969
#ifdef _WIN32
956970
tmplen = _snprintf(substr, sublen, "%04" NPY_INT64_FMT, dts->year);
957971
#else

0 commit comments

Comments
 (0)
0