Skip to content

Commit f3285f3

Browse files
Initial
1 parent a9a399f commit f3285f3

File tree

6 files changed

+61
-0
lines changed

6 files changed

+61
-0
lines changed

Doc/library/datetime.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1155,6 +1155,9 @@ Other constructors, all class methods:
11551155
>>> when.strftime("%B %d") # doctest: +SKIP
11561156
'February 29'
11571157

1158+
.. versionchanged::
1159+
Added the ``%F`` directive.
1160+
11581161

11591162
Class attributes:
11601163

@@ -2593,6 +2596,9 @@ convenience. These parameters all correspond to ISO 8601 date values.
25932596
| | (empty string if the object is | +06:34:15, | |
25942597
| | naive). | -03:07:12.345216 | |
25952598
+-----------+--------------------------------+------------------------+-------+
2599+
| ``%F`` | Optional microseconds as a | (empty), .000003, | \(11) |
2600+
| | decimal number. | .123456, .3 | |
2601+
+-----------+--------------------------------+------------------------+-------+
25962602

25972603
These may not be available on all platforms when used with the :meth:`~.datetime.strftime`
25982604
method. The ISO 8601 year and ISO 8601 week directives are not interchangeable
@@ -2765,6 +2771,10 @@ Notes:
27652771
:exc:`DeprecationWarning`. In 3.15 or later we may change this into
27662772
an error or change the default year to a leap year. See :gh:`70647`.
27672773

2774+
(11)
2775+
The ``%F`` directive can only be used with :meth:`~.datetime.strptime`
2776+
and :meth:`~.time.strptime`.
2777+
27682778
.. rubric:: Footnotes
27692779

27702780
.. [#] If, that is, we ignore the effects of Relativity

Doc/library/time.rst

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -614,12 +614,27 @@ Functions
614614
except for recognizing UTC and GMT which are always known (and are considered to
615615
be non-daylight savings timezones).
616616

617+
The ``%F`` directive is exclusive to :func:`!time.strptime` and allows for
618+
optional microseconds as a decimal.::
619+
620+
>>> import time
621+
>>> time.strptime("09:10:13", "%H:%M:%S%F")
622+
time.struct_time(tm_year=1900, tm_mon=1, tm_mday=1, tm_hour=9, tm_min=10,
623+
tm_sec=13, tm_wday=0, tm_yday=1, tm_isdst=-1)
624+
>>> time.strptime("09:10:13.22", "%H:%M:%S%F")
625+
time.struct_time(tm_year=1900, tm_mon=1, tm_mday=1, tm_hour=9, tm_min=10,
626+
tm_sec=13, tm_wday=0, tm_yday=1, tm_isdst=-1)
627+
628+
617629
Only the directives specified in the documentation are supported. Because
618630
``strftime()`` is implemented per platform it can sometimes offer more
619631
directives than those listed. But ``strptime()`` is independent of any platform
620632
and thus does not necessarily support all directives available that are not
621633
documented as supported.
622634

635+
.. versionchanged::
636+
Added the ``%F`` directive.
637+
623638

624639
.. class:: struct_time
625640

Lib/_strptime.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,7 @@ def __init__(self, locale_time=None):
288288
# The " [1-9]" part of the regex is to make %c from ANSI C work
289289
'd': r"(?P<d>3[0-1]|[1-2]\d|0[1-9]|[1-9]| [1-9])",
290290
'f': r"(?P<f>[0-9]{1,6})",
291+
'F': r"(?:\.(?P<F>[0-9]{1,6}))?",
291292
'H': r"(?P<H>2[0-3]|[0-1]\d|\d)",
292293
'I': r"(?P<I>1[0-2]|0[1-9]|[1-9]| [1-9])",
293294
'G': r"(?P<G>\d\d\d\d)",
@@ -522,6 +523,10 @@ def _strptime(data_string, format="%a %b %d %H:%M:%S %Y"):
522523
# Pad to always return microseconds.
523524
s += "0" * (6 - len(s))
524525
fraction = int(s)
526+
elif group_key == "F":
527+
s = found_dict["F"] or "0"
528+
s += "0" * (6 - len(s))
529+
fraction = int(s)
525530
elif group_key == 'A':
526531
weekday = locale_time.f_weekday.index(found_dict['A'].lower())
527532
elif group_key == 'a':

Lib/test/datetimetester.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2890,6 +2890,16 @@ def test_strptime(self):
28902890
strptime("-00:02:01.000003", "%z").utcoffset(),
28912891
-timedelta(minutes=2, seconds=1, microseconds=3)
28922892
)
2893+
2894+
# Test %F
2895+
inputs = [
2896+
(self.theclass(2025, 3, 23, 13, 2, 47, 197000), "2025-03-23 13:02:47.197", "%Y-%m-%d %H:%M:%S%F"),
2897+
(self.theclass(2025, 3, 23, 13, 2, 47), "2025-03-23 13:02:47", "%Y-%m-%d %H:%M:%S%F"),
2898+
]
2899+
for expected, string, format in inputs:
2900+
with self.subTest(expected=expected, string=string, format=format):
2901+
self.assertEqual(expected, self.theclass.strptime(string, format))
2902+
28932903
# Only local timezone and UTC are supported
28942904
for tzseconds, tzname in ((0, 'UTC'), (0, 'GMT'),
28952905
(-_time.timezone, _time.tzname[0])):
@@ -3858,6 +3868,15 @@ def test_strftime(self):
38583868
# A naive object replaces %z, %:z and %Z with empty strings.
38593869
self.assertEqual(t.strftime("'%z' '%:z' '%Z'"), "'' '' ''")
38603870

3871+
# Test %F
3872+
inputs = [
3873+
(self.theclass(13, 2, 47, 197000), "13:02:47.197", "%H:%M:%S%F"),
3874+
(self.theclass(13, 2, 47), "13:02:47", "%H:%M:%S%F"),
3875+
]
3876+
for expected, string, format in inputs:
3877+
with self.subTest(expected=expected, string=string, format=format):
3878+
self.assertEqual(expected, self.theclass.strptime(string, format))
3879+
38613880
# bpo-34482: Check that surrogates don't cause a crash.
38623881
try:
38633882
t.strftime('%H\ud800%M')

Lib/test/test_strptime.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,16 @@ def test_fraction(self):
364364
tup, frac, _ = _strptime._strptime(str(d), format="%Y-%m-%d %H:%M:%S.%f")
365365
self.assertEqual(frac, d.microsecond)
366366

367+
def test_optional_fraction(self):
368+
# Test optional microseconds
369+
import datetime
370+
d = datetime.datetime(2012, 12, 20, 12, 34, 56, 78987)
371+
tup, frac, _ = _strptime._strptime(str(d), format="%Y-%m-%d %H:%M:%S%F")
372+
self.assertEqual(frac, d.microsecond)
373+
dn = datetime.datetime(2012, 12, 20, 12, 34, 56)
374+
tup, frac, _ = _strptime._strptime(str(dn), format="%Y-%m-%d %H:%M:%S%F")
375+
self.assertEqual(frac, dn.microsecond)
376+
367377
def test_weekday(self):
368378
# Test weekday directives
369379
self.roundtrip('%w', 6)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Add ``%F`` format code to :func:`time.strptime` and :func:`datetime.datetime.strptime`
2+
which allows for optional microseconds.

0 commit comments

Comments
 (0)