datetime: strftime/strptime sub-second precision specifier (%Nf)
Dieses Issue hat noch niemand übernommen.
- Vorherrschende Sprache
- Python
- Sterne
- 77.2k
- Forks
- 35.9k
- PR-Merge-Kennzahlen
- PR-Kennzahlen ausstehend
Beschreibung
Feature or enhancement
Note: in this issue datetime refers to datetime.datetime, while time refers to datetime.time. This issue doesn't talk about the time module.
Background
Currently, in datetime.strftime/time.strftime, the only sub-second formatting code available is %f, which produces a fixed-width string of microsecond digits, padded from the left with zeros, like "004312".
Despite %f coding for an integer, its zero-padded nature makes it usable in producing the "fraction of the second" part of a datetime string. For example "%T.%f" results in a string like 22:11:55.012345.
Problem
There is still no way for datetime.strftime/time.strftime, alone to produce milliseconds, like 22:11:55.012, or any other fraction length between 1 and 5.
Non-solutions
If you control the code, you can call d.isoformat(timespec="milliseconds"). If all you have is configuration where you specify the datetime.strftime format string, you're in no luck.
Proposal
I'm proposing an expanded variant of the %f datetime.strftime format code in the form of %Nf where N∈{1,2,3,4,5,6}. It would produce datetime microseconds, zero-padded to 6 decimal positions and truncated to N most significant positions.
Examples:
- If
%f→"012345", then:
%6f→"012345"%5f→"01234"%4f→"0123"%3f→"012"%2f→"01"%1f→"0"
- An ISO 8601 format specifying millisecond precision:
%Y-%m-%dT%H:%M:%S.%3f%:z - A human-friendly format with 2 sub-second decimal places:
%Y-%m-%d %H:%M:%S.%2f %z
Issues and choices
Truncation or rounding
For microseconds equal to 012345, should %5f produce:
"01234"(truncation)"01235"(arithmetic rounding)- some other rounding mode?
My proposed change truncates.
Format code syntax
N in %Nf theoretically conflicts with "optional minimum field width" in POSIX libc. The post by @jb2170 highlights that the conflict is very theoretical because %f is a Python extension (and libc doesn't include sub-seconds in struct tm).
This theoretical conflict could still be avoided by following alternative codes:
%.Nfinstead of%Nf. This however was deemed confusing, since having a dot in the format code suggests that the code would also produce a dot in its output, and generally, round a float rather than truncating an integer.%:Nf(where:Nis analogous to the slicing operation) was floated, with no traction.
Overall, the 2 recently active discussion members are in favour of %Nf. I believe that either %Nf or %:Nf could be valid, which makes 3/3 recent posters in favour of %Nf.
Format code corner cases
In my initial implementation, if N falls outside of the supported [1, 6] range, a ValueError is raised. Since format code scanning operates on characters, such detection will only occur for 0, 7, 8 and 9. A code like "%10f" will not be intercepted and will hit the libc - handling always-incorrect multi-digit codes would complicate parsing in the C variant of wrap_strftime so I'm not considering that.
As an alternative to the ValueError, N=0 could produce nothing while values of 7, 8, 9 could act like N=6.
My preference: No change to initial code.
strptime leniency
In my initial implementation a %Nf code in datetime.strptime/time.strptime means that exactly N digits are expected. "%3f" will accept "111" but not "11" or "1111". This is OK since the existing %f code still accepts any number of digits in the [1, 6] range, as before.
Alternatively, a relaxation could be made instead: for a %Nf code, any number of digits from the range [1, N] could be accepted.
My preference: No relaxation.
Prior art
Rust's chrono lib permits %3f, %6f, and %9f (datetime cannot support %9f, since it doesn't go beyond microseconds).
Has this already been discussed elsewhere?
I have already discussed this feature proposal on Discourse
Links to previous discussion of this feature:
https://discuss.python.org/t/add-millisecond-formatting-support-to-datetime-strftime
Implementation
My initial implementation is in this PR:
Linked PRs
- gh-157291
- gh-157704
Beitragsleitfaden
Erste Schritte
- Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
- Forke das Repository und arbeite in einem Branch.
- Öffne einen Pull Request, der die Issue-Nummer nennt.
Rechercherichtung
Beginnen Sie mit den verlinkten PRs gh-157291 und gh-157704, lesen Sie anschließend die verlinkte Discourse-Diskussion und die ungelösten Entscheidungen in diesem Issue. Für den Abschluss sind eine abgestimmte format-code-Syntax und ein abgestimmtes Verhalten für Formatierung, ungültige Breiten, Kürzung und strptime-Parsing erforderlich, wobei die Implementierung in der verlinkten Arbeit widergespiegelt sein muss.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Bewertung
- Tech-Stack
- python
- Bereich
- backend
- Issue-Typ
- Feature
- Schwierigkeit
- 5/5
- Geschätzter Aufwand
- Über eine Woche
- Aktivitätsstatus
- Veraltet
- Klarheit
- Klar beschrieben
- Anfängerfreundlichkeit
- 25/100