Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 33 additions & 6 deletions Doc/library/datetime.rst
Original file line number Diff line number Diff line change
Expand Up @@ -791,13 +791,25 @@ Instance methods:
.. versionchanged:: 3.9
Result changed from a tuple to a :term:`named tuple`.

.. method:: date.isoformat()

Return a string representing the date in ISO 8601 format, ``YYYY-MM-DD``::
.. method:: date.isoformat(basic=False)

Return a string representing the date in:

- ISO 8601 extended format ``YYYY-MM-DD`` (the default), or
- ISO 8601 basic format ``YYYYMMDD`` via the *basic* argument.

Examples:

>>> from datetime import date
>>> date(2002, 12, 4).isoformat()
'2002-12-04'
>>> date(2002, 12, 4).isoformat(basic=True)
'20021204'

.. versionchanged:: next
Added the *basic* parameter.


.. method:: date.__str__()

Expand Down Expand Up @@ -1566,9 +1578,9 @@ Instance methods:
and ``weekday``. The same as ``self.date().isocalendar()``.


.. method:: datetime.isoformat(sep='T', timespec='auto')
.. method:: datetime.isoformat(sep='T', timespec='auto', basic=False)

Return a string representing the date and time in ISO 8601 format:
Return a string representing the date and time in ISO 8601 extended format:

- ``YYYY-MM-DDTHH:MM:SS.ffffff``, if :attr:`microsecond` is not 0
- ``YYYY-MM-DDTHH:MM:SS``, if :attr:`microsecond` is 0
Expand All @@ -1580,13 +1592,20 @@ Instance methods:
is not 0
- ``YYYY-MM-DDTHH:MM:SS+HH:MM[:SS[.ffffff]]``, if :attr:`microsecond` is 0

If *basic* is true, this uses the ISO 8601 basic format for the date,
time and offset components.

Examples::

>>> from datetime import datetime, timezone
>>> datetime(2019, 5, 18, 15, 17, 8, 132263).isoformat()
'2019-05-18T15:17:08.132263'
>>> datetime(2019, 5, 18, 15, 17, 8, 132263).isoformat(basic=True)
'20190518T151708.132263'
>>> datetime(2019, 5, 18, 15, 17, tzinfo=timezone.utc).isoformat()
'2019-05-18T15:17:00+00:00'
>>> datetime(2019, 5, 18, 15, 17, tzinfo=timezone.utc).isoformat(basic=True)
'20190518T151700+0000'

The optional argument *sep* (default ``'T'``) is a one-character separator,
placed between the date and time portions of the result. For example::
Expand Down Expand Up @@ -1633,6 +1652,9 @@ Instance methods:
.. versionchanged:: 3.6
Added the *timespec* parameter.

.. versionadded:: next
Added the *basic* parameter.


.. method:: datetime.__str__()

Expand Down Expand Up @@ -1984,15 +2006,17 @@ Instance methods:
Added the *fold* parameter.


.. method:: time.isoformat(timespec='auto')
.. method:: time.isoformat(timespec='auto', basic=False)

Return a string representing the time in ISO 8601 format, one of:
Return a string representing the time in ISO 8601 (extended) format, one of:

- ``HH:MM:SS.ffffff``, if :attr:`microsecond` is not 0
- ``HH:MM:SS``, if :attr:`microsecond` is 0
- ``HH:MM:SS.ffffff+HH:MM[:SS[.ffffff]]``, if :meth:`utcoffset` does not return ``None``
- ``HH:MM:SS+HH:MM[:SS[.ffffff]]``, if :attr:`microsecond` is 0 and :meth:`utcoffset` does not return ``None``

If *basic* is true, this uses the ISO 8601 basic format which omits the colons.

The optional argument *timespec* specifies the number of additional
components of the time to include (the default is ``'auto'``).
It can be one of the following:
Expand Down Expand Up @@ -2027,6 +2051,9 @@ Instance methods:
.. versionchanged:: 3.6
Added the *timespec* parameter.

.. versionchanged:: next
Added the *basic* parameter.


.. method:: time.__str__()

Expand Down
8 changes: 8 additions & 0 deletions Doc/whatsnew/3.15.rst
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,14 @@ dataclasses
type names.


datetime
--------

* Add the :meth:`~datetime.date.strptime` method to the
:class:`datetime.date` and :class:`datetime.time` classes.
(Contributed by Wannes Boeykens in :gh:`41431`.)


dbm
---

Expand Down
1 change: 1 addition & 0 deletions Include/internal/pycore_global_objects_fini_generated.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Include/internal/pycore_global_strings.h
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,7 @@ struct _Py_global_strings {
STRUCT_FOR_ID(autocommit)
STRUCT_FOR_ID(backtick)
STRUCT_FOR_ID(base)
STRUCT_FOR_ID(basic)
STRUCT_FOR_ID(before)
STRUCT_FOR_ID(big)
STRUCT_FOR_ID(binary_form)
Expand Down
1 change: 1 addition & 0 deletions Include/internal/pycore_runtime_init_generated.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions Include/internal/pycore_unicodeobject_generated.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

72 changes: 49 additions & 23 deletions Lib/_pydatetime.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,14 +163,23 @@ def _build_struct_time(y, m, d, hh, mm, ss, dstflag):
dnum = _days_before_month(y, m) + d
return _time.struct_time((y, m, d, hh, mm, ss, wday, dnum, dstflag))

def _format_time(hh, mm, ss, us, timespec='auto'):
specs = {
'hours': '{:02d}',
'minutes': '{:02d}:{:02d}',
'seconds': '{:02d}:{:02d}:{:02d}',
'milliseconds': '{:02d}:{:02d}:{:02d}.{:03d}',
'microseconds': '{:02d}:{:02d}:{:02d}.{:06d}'
}
def _format_time(hh, mm, ss, us, timespec='auto', basic=False):
if basic:
specs = {
'hours': '{:02d}',
'minutes': '{:02d}{:02d}',
'seconds': '{:02d}{:02d}{:02d}',
'milliseconds': '{:02d}{:02d}{:02d}.{:03d}',
'microseconds': '{:02d}{:02d}{:02d}.{:06d}'
}
else:
specs = {
'hours': '{:02d}',
'minutes': '{:02d}:{:02d}',
'seconds': '{:02d}:{:02d}:{:02d}',
'milliseconds': '{:02d}:{:02d}:{:02d}.{:03d}',
'microseconds': '{:02d}:{:02d}:{:02d}.{:06d}'
}

if timespec == 'auto':
# Skip trailing microseconds when us==0.
Expand Down Expand Up @@ -1125,16 +1134,18 @@ def __format__(self, fmt):
return self.strftime(fmt)
return str(self)

def isoformat(self):
"""Return the date formatted according to ISO.
def isoformat(self, basic=False):
"""Return the date formatted according to ISO 8601.

This is 'YYYY-MM-DD'.
This is 'YYYY-MM-DD' or 'YYYYMMDD' if *basic* is true.

References:
- https://www.w3.org/TR/NOTE-datetime
- https://www.cl.cam.ac.uk/~mgk25/iso-time.html
"""
return "%04d-%02d-%02d" % (self._year, self._month, self._day)
if basic:
return f"{self._year:04d}{self._month:02d}{self._day:02d}"
return f"{self._year:04d}-{self._month:02d}-{self._day:02d}"

__str__ = isoformat

Expand Down Expand Up @@ -1587,10 +1598,13 @@ def __hash__(self):

# Conversion to string

def _tzstr(self):
"""Return formatted timezone offset (+xx:xx) or an empty string."""
def _tzstr(self, basic):
"""Return formatted timezone offset (+xx:xx) or an empty string.
The colon separator is omitted if *basic* is true.
"""
off = self.utcoffset()
return _format_offset(off)
sep = '' if basic else ':'
return _format_offset(off, sep)

def __repr__(self):
"""Convert to formal string, for repr()."""
Expand All @@ -1611,19 +1625,21 @@ def __repr__(self):
s = s[:-1] + ", fold=1)"
return s

def isoformat(self, timespec='auto'):
def isoformat(self, timespec='auto', basic=False):
"""Return the time formatted according to ISO.

The full format is 'HH:MM:SS.mmmmmm+zz:zz'. By default, the fractional
part is omitted if self.microsecond == 0.

If *basic* is true, separators ':' are omitted.

The optional argument timespec specifies the number of additional
terms of the time to include. Valid options are 'auto', 'hours',
'minutes', 'seconds', 'milliseconds' and 'microseconds'.
"""
s = _format_time(self._hour, self._minute, self._second,
self._microsecond, timespec)
tz = self._tzstr()
self._microsecond, timespec, basic)
tz = self._tzstr(basic)
if tz:
s += tz
return s
Expand Down Expand Up @@ -2150,6 +2166,14 @@ def astimezone(self, tz=None):

# Ways to produce a string.

def _tzstr(self, basic):
"""Return formatted timezone offset (+xx:xx) or an empty string.
The colon separator is omitted if *basic* is true.
"""
off = self.utcoffset()
sep = '' if basic else ':'
return _format_offset(off, sep)

def ctime(self):
"Return ctime() style string."
weekday = self.toordinal() % 7 or 7
Expand All @@ -2160,12 +2184,14 @@ def ctime(self):
self._hour, self._minute, self._second,
self._year)

def isoformat(self, sep='T', timespec='auto'):
def isoformat(self, sep='T', timespec='auto', basic=False):
"""Return the time formatted according to ISO.

The full format looks like 'YYYY-MM-DD HH:MM:SS.mmmmmm'.
By default, the fractional part is omitted if self.microsecond == 0.

If *basic* is true, separators ':' and '-' are omitted.

If self.tzinfo is not None, the UTC offset is also attached, giving
a full format of 'YYYY-MM-DD HH:MM:SS.mmmmmm+HH:MM'.

Expand All @@ -2176,12 +2202,12 @@ def isoformat(self, sep='T', timespec='auto'):
terms of the time to include. Valid options are 'auto', 'hours',
'minutes', 'seconds', 'milliseconds' and 'microseconds'.
"""
s = ("%04d-%02d-%02d%c" % (self._year, self._month, self._day, sep) +
fmt = "%04d%02d%02d%c" if basic else "%04d-%02d-%02d%c"
s = (fmt % (self._year, self._month, self._day, sep) +
_format_time(self._hour, self._minute, self._second,
self._microsecond, timespec))
self._microsecond, timespec, basic))

off = self.utcoffset()
tz = _format_offset(off)
tz = self._tzstr(basic)
if tz:
s += tz

Expand Down
Loading
Loading