-
-
Notifications
You must be signed in to change notification settings - Fork 33.5k
gh-80010: Expand fromisoformat to include most of ISO-8601 #92177
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
+778
−178
Merged
Changes from 1 commit
Commits
Show all changes
42 commits
Select commit
Hold shift + click to select a range
7635fe1
TEMP: Add isoformatter test
pganssle b9b7a03
Add support for YYYYMMDD
pganssle c746b96
Expand support for ISO 8601 times
pganssle 00978f9
Add support for ISO calendar-style strings
pganssle c36e306
Rework how string sanitization works
pganssle 0234cae
WIP
pganssle ee1a7e3
Move Isoformatter into test helper, add date/time tests
pganssle 7d2fd33
Final location for isoformatter and strategies
pganssle 72266c4
Working version of date.isoformat
pganssle 8067af1
Fix failure to set an error
pganssle 7b9bca5
First version with time parsing allowed
pganssle 328e781
Add support for leading T in time formatters
pganssle 4d0e3a9
Fix pure python separator detection in YYYYWwwd
pganssle 3e600f2
Version with all tests passing
pganssle e26f06f
Migrate fromisoformat tests to their own file
pganssle 1ea0cd1
Fix bug in time parsing logic
pganssle 1e3577f
s/ssize_t/size_t
pganssle 6422799
Add fromisoformat example tests
pganssle 3d24a15
Try to be consistent about use of double quotes in error messages
pganssle 661b1b0
Update documentation
pganssle 1defa1d
Remove isoformatter
pganssle 75de7a4
Update out-of-date comment
pganssle 07ee419
Only one space
pganssle 3d0fb7a
Explicitly handle 0-length tzstr
pganssle cc8c737
Raise exceptions from None
pganssle 31bf63e
Add test cases around week 53
pganssle 5bfb3fc
Add examples around week 53
pganssle 4879a47
Update docstrings
pganssle 3cd657f
Add news entry
pganssle 763d5bb
Add what's new entry
pganssle 3a06505
Be consistent about ISO 8601
pganssle e643f02
Change name of isoformat separator detection function
pganssle 5046809
Remove 'mode' logic and update comments
pganssle 90093bf
Fix segfault case
pganssle 6fc8157
Explicitly cast signed to unsigned
pganssle d9a766b
Document that ordinal dates are not supported
pganssle 04ed787
Remove dead code
pganssle 6da3e90
Various fixes
pganssle 92cc0be
Fix example
pganssle bec0bee
Add example for time.fromisoformat
pganssle aad6011
Fix trailing colon
pganssle a33d776
Remove fromisoformat property test
pganssle File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Expand support for ISO 8601 times
- Loading branch information
commit c746b96d804aabe0a0b5a9550b037c982507af78
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -680,6 +680,11 @@ set_date_fields(PyDateTime_Date *self, int y, int m, int d) | |
| * String parsing utilities and helper functions | ||
| */ | ||
|
|
||
| static const unsigned char * | ||
| is_digit(const char c) { | ||
| return ((unsigned int)(c - '0')) < 10; | ||
| } | ||
|
|
||
| static const char * | ||
| parse_digits(const char *ptr, int *var, size_t num_digits) | ||
| { | ||
|
|
@@ -740,7 +745,7 @@ parse_hh_mm_ss_ff(const char *tstr, const char *tstr_end, int *hour, | |
| const char *p = tstr; | ||
| const char *p_end = tstr_end; | ||
| int *vals[3] = {hour, minute, second}; | ||
| unsigned char has_separator = 2; | ||
| unsigned char has_separator = 1; | ||
pganssle marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| // Parse [HH[:?MM[:?SS]]] | ||
| for (size_t i = 0; i < 3; ++i) { | ||
|
|
@@ -750,36 +755,50 @@ parse_hh_mm_ss_ff(const char *tstr, const char *tstr_end, int *hour, | |
| } | ||
|
|
||
| char c = *(p++); | ||
| if (i == 0) { | ||
| has_separator = (c == ':'); | ||
| } | ||
|
|
||
| if (p >= p_end) { | ||
| return c != '\0'; | ||
pganssle marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
| else if (has_separator == 2 || (has_separator && c == ':')) { | ||
| if (has_separator == 2) { | ||
| has_separator = (c == ':'); | ||
| } | ||
| else if (has_separator && (c == ':')) { | ||
| continue; | ||
| } | ||
| else if (c == '.') { | ||
| else if (c == '.' || c == ',') { | ||
| break; | ||
| } | ||
| else { | ||
| } else if (!has_separator) { | ||
| --p; | ||
|
||
| } else { | ||
| return -4; // Malformed time separator | ||
| } | ||
| } | ||
|
|
||
| // Parse .fff[fff] | ||
| // Parse fractional components | ||
| size_t len_remains = p_end - p; | ||
| if (!(len_remains == 6 || len_remains == 3)) { | ||
| return -3; | ||
| size_t to_parse = len_remains; | ||
| if (len_remains >= 6) { | ||
| to_parse = 6; | ||
| } | ||
|
|
||
| p = parse_digits(p, microsecond, len_remains); | ||
| p = parse_digits(p, microsecond, to_parse); | ||
| if (NULL == p) { | ||
| return -3; | ||
| } | ||
|
|
||
| if (len_remains == 3) { | ||
| *microsecond *= 1000; | ||
| static int correction[5] = { | ||
pganssle marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| 100000, 10000, 1000, 100, 10 | ||
| }; | ||
|
|
||
| if (to_parse < 6) { | ||
| *microsecond *= correction[to_parse-1]; | ||
| } | ||
|
|
||
| for (size_t i = 0; i < len_remains - 6; ++i) { | ||
| if (!is_digit(*p)) { | ||
| break; | ||
| } | ||
| p++; | ||
pganssle marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| // Return 1 if it's not the end of the string | ||
|
|
@@ -805,7 +824,7 @@ parse_isoformat_time(const char *dtstr, size_t dtlen, int *hour, int *minute, | |
|
|
||
| const char *tzinfo_pos = p; | ||
| do { | ||
| if (*tzinfo_pos == '+' || *tzinfo_pos == '-') { | ||
| if (*tzinfo_pos == 'Z' || *tzinfo_pos == '+' || *tzinfo_pos == '-') { | ||
| break; | ||
| } | ||
| } while (++tzinfo_pos < p_end); | ||
|
|
@@ -827,14 +846,16 @@ parse_isoformat_time(const char *dtstr, size_t dtlen, int *hour, int *minute, | |
| } | ||
| } | ||
|
|
||
| // Parse time zone component | ||
| // Valid formats are: | ||
| // - +HH:MM (len 6) | ||
| // - +HH:MM:SS (len 9) | ||
| // - +HH:MM:SS.ffffff (len 16) | ||
| size_t tzlen = p_end - tzinfo_pos; | ||
| if (!(tzlen == 6 || tzlen == 9 || tzlen == 16)) { | ||
| return -5; | ||
| // Special case UTC / Zulu time. | ||
| if (*tzinfo_pos == 'Z') { | ||
| *tzoffset = 0; | ||
| *tzmicrosecond = 0; | ||
|
|
||
| if (*(tzinfo_pos + 1) != '\0') { | ||
| return -6; | ||
pganssle marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } else { | ||
| return 1; | ||
| } | ||
| } | ||
|
|
||
| int tzsign = (*tzinfo_pos == '-') ? -1 : 1; | ||
|
|
@@ -846,7 +867,7 @@ parse_isoformat_time(const char *dtstr, size_t dtlen, int *hour, int *minute, | |
| *tzoffset = tzsign * ((tzhour * 3600) + (tzminute * 60) + tzsecond); | ||
| *tzmicrosecond *= tzsign; | ||
|
|
||
| return rv ? -5 : 1; | ||
| return rv ? -7 : 1; | ||
pganssle marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| /* --------------------------------------------------------------------------- | ||
|
|
||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.