@@ -77,7 +77,11 @@ parse_iso_8601_datetime(char *str, int len,
77
77
out -> month = 1 ;
78
78
out -> day = 1 ;
79
79
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
+ */
81
85
if (len <= 0 || (len == 3 &&
82
86
tolower (str [0 ]) == 'n' &&
83
87
tolower (str [1 ]) == 'a' &&
@@ -109,9 +113,11 @@ parse_iso_8601_datetime(char *str, int len,
109
113
}
110
114
111
115
/*
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
115
121
* switching to an adjacent day depending on the current time and your
116
122
* timezone.
117
123
*/
@@ -126,15 +132,15 @@ parse_iso_8601_datetime(char *str, int len,
126
132
time (& rawtime );
127
133
#if defined(_WIN32 )
128
134
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 " );
131
137
return -1 ;
132
138
}
133
139
#else
134
140
/* Other platforms may require something else */
135
141
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 " );
138
144
return -1 ;
139
145
}
140
146
#endif
@@ -784,6 +790,9 @@ lossless_unit_from_datetimestruct(npy_datetimestruct *dts)
784
790
* NULL-terminated string. If the string fits in the space exactly,
9E81
785
791
* it leaves out the NULL terminator and returns success.
786
792
*
793
+ * The differences from ISO 8601 are the 'NaT' string, and
794
+ * the number of year digits is >= 4 instead of strictly 4.
795
+ *
787
796
* If 'local' is non-zero, it produces a string in local time with
788
797
* a +-#### timezone offset, otherwise it uses timezone Z (UTC).
789
798
*
@@ -829,7 +838,7 @@ make_iso_8601_datetime(npy_datetimestruct *dts, char *outstr, int outlen,
829
838
}
830
839
831
840
/* 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 ) {
833
842
local = 0 ;
834
843
}
835
844
@@ -923,7 +932,7 @@ make_iso_8601_datetime(npy_datetimestruct *dts, char *outstr, int outlen,
923
932
/*
924
933
* Now the datetimestruct data is in the final form for
925
934
* 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.
927
936
*/
928
937
if (casting != NPY_UNSAFE_CASTING ) {
929
938
/* 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,
952
961
}
953
962
954
963
/* 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
+ */
955
969
#ifdef _WIN32
956
970
tmplen = _snprintf (substr , sublen , "%04" NPY_INT64_FMT , dts -> year );
957
971
#else
0 commit comments