python / python/cpython

datetime: strftime/strptime sub-second precision specifier (%Nf)

未關閉
#157,290 4 則留言 0 個 reaction 已指派 0 人 在 GitHub 檢視

還沒有人認領這個 Issue。

extension-modules type-feature
主要語言
Python
星號
77.2k
分支
35.9k
PR 合併指標
PR 指標待擷取

描述

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:

  1. If %f"012345", then:
  • %6f"012345"
  • %5f"01234"
  • %4f"0123"
  • %3f"012"
  • %2f"01"
  • %1f"0"
  1. An ISO 8601 format specifying millisecond precision: %Y-%m-%dT%H:%M:%S.%3f%:z
  2. 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:

  • %.Nf instead 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 :N is 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

貢獻指南

開啟貢獻指南

從這裡開始

  1. 先讀完整個 Issue,再讀專案的貢獻指南。
  2. 在 Issue 下留言說明你要接手 —— 這能避免兩個人做同樣的事。
  3. Fork 儲存庫,在一個分支上完成修改。
  4. 送出 Pull Request,並在描述裡引用這個 Issue 編號。

研究方向

先從連結的 PR gh-157291 和 gh-157704 開始,然後閱讀連結的 Discourse 討論,以及此 issue 中尚未解決的選擇。完成工作需要就 format-code 語法,以及格式化、無效寬度、截斷和 strptime 剖析的行為達成共識,並在連結的工作中反映該實作。

由索引模型根據 Issue 內容生成。

評估

技術堆疊
python
領域
backend
Issue 類型
功能
難度
5/5
預估耗時
一週以上
活躍度
停滯
描述清晰度
描述清楚
新手友好度
25/100

把新 issue 寄到你的電子郵件信箱

精選適合新手參與的 GitHub issue 摘要。