@@ -66,10 +66,29 @@ This file implements string parsing and creation for NumPy datetime.
66
66
*
67
67
* Returns 0 on success, -1 on failure.
68
68
*/
69
+
70
+ #define FORMAT_STARTSWITH (ch ) \
71
+ if (exact) { \
72
+ if (!format_len || *format != ch) { \
73
+ goto parse_error; \
74
+ } \
75
+ ++format; \
76
+ --format_len; \
77
+ } else { \
78
+ if (format_len > 0) { \
79
+ if (*format != ch) { \
80
+ goto parse_error; \
81
+ } \
82
+ ++format; \
83
+ --format_len; \
84
+ } \
85
+ } \
86
+
69
87
int parse_iso_8601_datetime (const char * str , int len , int want_exc ,
70
88
npy_datetimestruct * out ,
71
89
NPY_DATETIMEUNIT * out_bestunit ,
72
- int * out_local , int * out_tzoffset ) {
90
+ int * out_local , int * out_tzoffset ,
91
+ const char * format , int format_len , int exact ) {
73
92
int year_leap = 0 ;
74
93
int i , numdigits ;
75
94
const char * substr ;
@@ -104,14 +123,19 @@ int parse_iso_8601_datetime(const char *str, int len, int want_exc,
104
123
while (sublen > 0 && isspace (* substr )) {
105
124
++ substr ;
106
125
-- sublen ;
126
+ FORMAT_STARTSWITH (' ' );
107
127
}
108
128
109
129
/* Leading '-' sign for negative year */
110
130
if (* substr == '-' ) {
111
131
++ substr ;
112
132
-- sublen ;
133
+ FORMAT_STARTSWITH ('-' );
113
134
}
114
135
136
+ FORMAT_STARTSWITH ('%' );
137
+ FORMAT_STARTSWITH ('Y' );
138
+
115
139
if (sublen == 0 ) {
116
140
goto parse_error ;
117
141
}
@@ -139,6 +163,9 @@ int parse_iso_8601_datetime(const char *str, int len, int want_exc,
139
163
if (out_local != NULL ) {
140
164
* out_local = 0 ;
141
165
}
166
+ if (format_len ) {
167
+ goto parse_error ;
168
+ }
142
169
bestunit = NPY_FR_Y ;
143
170
goto finish ;
144
171
}
@@ -156,6 +183,7 @@ int parse_iso_8601_datetime(const char *str, int len, int want_exc,
156
183
ymd_sep = valid_ymd_sep [i ];
157
184
++ substr ;
158
185
-- sublen ;
186
+ FORMAT_STARTSWITH (ymd_sep );
159
187
/* Cannot have trailing separator */
160
188
if (sublen == 0 || !isdigit (* substr )) {
161
189
goto parse_error ;
@@ -167,6 +195,8 @@ int parse_iso_8601_datetime(const char *str, int len, int want_exc,
167
195
out -> month = (* substr - '0' );
168
196
++ substr ;
169
197
-- sublen ;
198
+ FORMAT_STARTSWITH ('%' );
199
+ FORMAT_STARTSWITH ('m' );
170
200
/* Second digit optional if there was a separator */
171
201
if (isdigit (* substr )) {
172
202
out -> month = 10 * out -> month + (* substr - '0' );
@@ -190,6 +220,9 @@ int parse_iso_8601_datetime(const char *str, int len, int want_exc,
190
220
if (!has_ymd_sep ) {
191
221
goto parse_error ;
192
222
}
223
+ if (format_len ) {
224
+ goto parse_error ;
225
+ }
193
226
if (out_local != NULL ) {
194
227
* out_local = 0 ;
195
228
}
@@ -203,6 +236,7 @@ int parse_iso_8601_datetime(const char *str, int len, int want_exc,
203
236
}
204
237
++ substr ;
205
238
-- sublen ;
239
+ FORMAT_STARTSWITH (ymd_sep );
206
240
}
207
241
208
242
/* PARSE THE DAY */
@@ -213,6 +247,8 @@ int parse_iso_8601_datetime(const char *str, int len, int want_exc,
213
247
out -> day = (* substr - '0' );
214
248
++ substr ;
215
249
-- sublen ;
250
+ FORMAT_STARTSWITH ('%' );
251
+ FORMAT_STARTSWITH ('d' );
216
252
/* Second digit optional if there was a separator */
217
253
if (isdigit (* substr )) {
218
254
out -> day = 10 * out -> day + (* substr - '0' );
@@ -235,13 +271,17 @@ int parse_iso_8601_datetime(const char *str, int len, int want_exc,
235
271
if (out_local != NULL ) {
236
272
* out_local = 0 ;
237
273
}
274
+ if (format_len ) {
275
+ goto parse_error ;
276
+ }
238
277
bestunit = NPY_FR_D ;
239
278
goto finish ;
240
279
}
241
280
242
281
if ((* substr != 'T' && * substr != ' ' ) || sublen == 1 ) {
243
282
goto parse_error ;
244
283
}
284
+ FORMAT_STARTSWITH (* substr );
245
285
++ substr ;
246
286
-- sublen ;
247
287
@@ -250,6 +290,8 @@ int parse_iso_8601_datetime(const char *str, int len, int want_exc,
250
290
if (!isdigit (* substr )) {
251
291
goto parse_error ;
252
292
}
293
+ FORMAT_STARTSWITH ('%' );
294
+ FORMAT_STARTSWITH ('H' );
253
295
out -> hour = (* substr - '0' );
254
296
++ substr ;
255
297
-- sublen ;
@@ -274,6 +316,9 @@ int parse_iso_8601_datetime(const char *str, int len, int want_exc,
274
316
if (!hour_was_2_digits ) {
275
317
goto parse_error ;
276
318
}
319
+ if (format_len ) {
320
+ goto parse_error ;
321
+ }
277
322
bestunit = NPY_FR_h ;
278
323
goto finish ;
279
324
}
@@ -286,6 +331,7 @@ int parse_iso_8601_datetime(const char *str, int len, int want_exc,
286
331
if (sublen == 0 || !isdigit (* substr )) {
287
332
goto parse_error ;
288
333
}
334
+ FORMAT_STARTSWITH (':' );
289
335
} else if (!isdigit (* substr )) {
290
336
if (!hour_was_2_digits ) {
291
337
goto parse_error ;
@@ -298,6 +344,8 @@ int parse_iso_8601_datetime(const char *str, int len, int want_exc,
298
344
out -> min = (* substr - '0' );
299
345
++ substr ;
300
346
-- sublen ;
347
+ FORMAT_STARTSWITH ('%' );
348
+ FORMAT_STARTSWITH ('M' );
301
349
/* Second digit optional if there was a separator */
302
350
if (isdigit (* substr )) {
303
351
out -> min = 10 * out -> min + (* substr - '0' );
@@ -317,12 +365,16 @@ int parse_iso_8601_datetime(const char *str, int len, int want_exc,
317
365
318
366
if (sublen == 0 ) {
319
367
bestunit = NPY_FR_m ;
368
+ if (format_len ) {
369
+ goto parse_error ;
370
+ }
320
371
goto finish ;
321
372
}
322
373
323
374
/* If we make it through this condition block, then the next
324
375
* character is a digit. */
325
376
if (has_hms_sep && * substr == ':' ) {
377
+ FORMAT_STARTSWITH (':' );
326
378
++ substr ;
327
379
-- sublen ;
328
380
/* Cannot have a trailing ':' */
@@ -339,6 +391,8 @@ int parse_iso_8601_datetime(const char *str, int len, int want_exc,
339
391
out -> sec = (* substr - '0' );
340
392
++ substr ;
341
393
-- sublen ;
394
+ FORMAT_STARTSWITH ('%' );
395
+ FORMAT_STARTSWITH ('S' );
342
396
/* Second digit optional if there was a separator */
343
397
if (isdigit (* substr )) {
344
398
out -> sec = 10 * out -> sec + (* substr - '0' );
@@ -360,12 +414,15 @@ int parse_iso_8601_datetime(const char *str, int len, int want_exc,
360
414
if (sublen > 0 && * substr == '.' ) {
361
415
++ substr ;
362
416
-- sublen ;
417
+ FORMAT_STARTSWITH ('.' );
363
418
} else {
364
419
bestunit = NPY_FR_s ;
365
420
goto parse_timezone ;
366
421
}
367
422
368
423
/* PARSE THE MICROSECONDS (0 to 6 digits) */
424
+ FORMAT_STARTSWITH ('%' );
425
+ FORMAT_STARTSWITH ('f' );
369
426
numdigits = 0 ;
370
427
for (i = 0 ; i < 6 ; ++ i ) {
371
428
out -> us *= 10 ;
@@ -430,15 +487,22 @@ int parse_iso_8601_datetime(const char *str, int len, int want_exc,
430
487
while (sublen > 0 && isspace (* substr )) {
431
488
++ substr ;
432
489
-- sublen ;
490
+ FORMAT_STARTSWITH (' ' );
433
491
}
434
492
435
493
if (sublen == 0 ) {
436
494
// Unlike NumPy, treating no time zone as naive
495
+ if (format_len > 0 ) {
496
+ goto parse_error ;
497
+ }
437
498
goto finish ;
438
499
}
439
500
440
501
/* UTC specifier */
441
502
if (* substr == 'Z' ) {
503
+ FORMAT_STARTSWITH ('%' );
504
+ FORMAT_STARTSWITH ('Z' );
505
+
442
506
/* "Z" should be equivalent to tz offset "+00:00" */
443
507
if (out_local != NULL ) {
444
508
* out_local = 1 ;
@@ -449,12 +513,17 @@ int parse_iso_8601_datetime(const char *str, int len, int want_exc,
449
513
}
450
514
451
515
if (sublen == 1 ) {
516
+ if (format_len > 0 ) {
517
+ goto parse_error ;
518
+ }
452
519
goto finish ;
453
520
} else {
454
521
++ substr ;
455
522
-- sublen ;
456
523
}
457
524
} else if (* substr == '-' || * substr == '+' ) {
525
+ FORMAT_STARTSWITH ('%' );
526
+ FORMAT_STARTSWITH ('z' );
458
527
/* Time zone offset */
459
528
int offset_neg = 0 , offset_hour = 0 , offset_minute = 0 ;
460
529
@@ -538,9 +607,10 @@ int parse_iso_8601_datetime(const char *str, int len, int want_exc,
538
607
while (sublen > 0 && isspace (* substr )) {
539
608
++ substr ;
540
609
-- sublen ;
610
+ FORMAT_STARTSWITH (' ' );
541
611
}
542
612
543
- if (sublen != 0 ) {
613
+ if (( sublen != 0 ) || ( format_len != 0 ) ) {
544
614
goto parse_error ;
545
615
}
546
616
0 commit comments