Xqt has submitted this change. ( 
https://gerrit.wikimedia.org/r/c/pywikibot/core/+/1348787?usp=email )

Change subject: time: add timespec to Timestamp.isoformat() method
......................................................................

time: add timespec to Timestamp.isoformat() method

* add the timespec parameter to Timestamp.isoformat(), which was
  introduced in Python 3.6
* return the timezone offset specified by the datetime/Timestamp instead
  of always returning UTC, while still using 'Z' for a zero offset
* remove the _ISO8601Format classmethod, which is no longer used
* update WbTime.fromTimestamp and use timetuple() directly
* update tests and documentation

Bug: T440120
Bug: T439983
Change-Id: I6e2d6900623157776d4b89efb3de319256200393
---
M docs/api_ref/date_time.rst
M pywikibot/_wbtypes.py
M pywikibot/data/api/_requests.py
M pywikibot/time.py
M tests/time_tests.py
5 files changed, 84 insertions(+), 28 deletions(-)

Approvals:
  Xqt: Verified; Looks good to me, approved
  Mahveotm: Looks good to me, but someone else must approve




diff --git a/docs/api_ref/date_time.rst b/docs/api_ref/date_time.rst
index f6c65d8..e601115 100644
--- a/docs/api_ref/date_time.rst
+++ b/docs/api_ref/date_time.rst
@@ -3,6 +3,7 @@
 ******************************************

 .. automodule:: pywikibot.time
+   :exclude-members: Timestamp

    .. admonition:: Imports in :mod:`pywikibot` module
       :class: note
@@ -11,3 +12,6 @@
       can also be used as :mod:`pywikibot` members:

       - :class:`pywikibot.Timestamp<pywikibot.time.Timestamp>`
+
+.. autoclass:: pywikibot.time.Timestamp
+   :special-members: __repr__, __str__
diff --git a/pywikibot/_wbtypes.py b/pywikibot/_wbtypes.py
index ec882a7..9efd083 100644
--- a/pywikibot/_wbtypes.py
+++ b/pywikibot/_wbtypes.py
@@ -737,9 +737,15 @@
         """
         if not timezone and timestamp.tzinfo and copy_timezone:
             timezone = int(timestamp.utcoffset().total_seconds() / 60)
-        return cls.fromTimestr(timestamp.isoformat(), precision=precision,
-                               before=before, after=after, timezone=timezone,
-                               calendarmodel=calendarmodel, site=site)
+        return cls(
+            *timestamp.timetuple()[:6],
+            precision=precision,
+            before=before,
+            after=after,
+            timezone=timezone,
+            calendarmodel=calendarmodel,
+            site=site,
+        )

     @staticmethod
     def _normalize_millennium(year: int) -> int:
diff --git a/pywikibot/data/api/_requests.py b/pywikibot/data/api/_requests.py
index 254e8c2..4b080c0 100644
--- a/pywikibot/data/api/_requests.py
+++ b/pywikibot/data/api/_requests.py
@@ -350,13 +350,13 @@
         Converts from Python datatypes to MediaWiki API parameter values.

         Supports:
-         * datetime.datetime (using strftime and ISO8601 format)
+         * datetime.datetime/Timestamp (using isoformat method)
          * pywikibot.page.BasePage (using title (+namespace; -section))

         All other datatypes are converted to string.
         """
         if isinstance(value, datetime.datetime):
-            return value.strftime(pywikibot.Timestamp.ISO8601Format)
+            return value.isoformat()
         if isinstance(value, pywikibot.page.BasePage):
             if value.site != self.site:
                 raise RuntimeError(f'value.site {value.site!r} is different '
diff --git a/pywikibot/time.py b/pywikibot/time.py
index 3f970f8..067d7e1 100644
--- a/pywikibot/time.py
+++ b/pywikibot/time.py
@@ -17,7 +17,7 @@
 from contextlib import suppress

 import pywikibot
-from pywikibot.tools import PYTHON_VERSION, classproperty
+from pywikibot.tools import PYTHON_VERSION, classproperty, deprecated


 __all__ = (
@@ -25,7 +25,8 @@
     'str2timedelta',
     'MW_KEYS',
     'Timestamp',
-    'TZoneFixedOffset'
+    'TZoneFixedOffset',
+    'UTC',
 )

 #: .. version-added:: 7.5
@@ -38,6 +39,13 @@
     # 'months' and 'minutes' were removed because confusion outweighs merit
 })

+UTC = datetime.timezone.utc
+"""Alias for the UTC time zone singleton :attr:`datetime.timezone.utc`.
+
+.. note:: :attr:`datetime.UTC` is an alias for it since Python 3.11.
+.. version-added:: 11.9
+"""
+

 class Timestamp(datetime.datetime):

@@ -217,20 +225,13 @@
         raise ValueError(f'time data {timestr!r} does not match any format.')

     @classproperty
+    @deprecated(since='11.9.0')
     def ISO8601Format(cls) -> str:  # noqa: N802
-        """ISO8601 format string class property for compatibility purpose."""
-        return cls._ISO8601Format()
+        """ISO8601 format string class property for compatibility purpose.

-    @classmethod
-    def _ISO8601Format(cls, sep: str = 'T') -> str:  # noqa: N802
-        """ISO8601 format string.
-
-        :param sep: One-character separator, placed between the date and
-            time
-        :return: ISO8601 format string
+        .. version-deprecated:: 11.9
         """
-        assert len(sep) == 1
-        return f'%Y-%m-%d{sep}%H:%M:%SZ'
+        return '%Y-%m-%dT%H:%M:%SZ'

     @classmethod
     def fromISOformat(cls,  # noqa: N802
@@ -301,14 +302,49 @@
             ts += '000000'
         return cls._from_mw(ts)

-    def isoformat(self, sep: str = 'T') -> str:  # type: ignore[override]
-        """Convert object to an ISO 8601 timestamp accepted by MediaWiki.
+    def isoformat(self, sep: str = 'T', timespec: str = 'seconds') -> str:
+        """Return a string representing the date and time in ISO 8601 format.

-        datetime.datetime.isoformat does not postfix the ISO formatted
-        date with a 'Z' unless a timezone is included, which causes
-        MediaWiki ~1.19 and earlier to fail.
+        Unlike :meth:`datetime.datetime.isoformat`, this method appends
+        a 'Z' to naive timestamps and uses 'Z' instead of '+00:00' for
+        timestamps with a zero UTC offset. For other timezone offsets,
+        the offset specified by the timestamp is preserved. The default
+        *timespec* is 'seconds' rather than 'auto'.
+
+        **Example:**
+
+        >>> from pywikibot.time import Timestamp, TZoneFixedOffset
+        >>> Timestamp(2026, 10, 4, 11, 22, 8, 132263).isoformat()
+        '2026-10-04T11:22:08Z'
+        >>> Timestamp(2026, 10, 4, 11, 22, 8, tzinfo=UTC).isoformat()
+        '2026-10-04T11:22:08Z'
+        >>> tzo = TZoneFixedOffset(-399, 'UTC')
+        >>> Timestamp(2026, 10, 4, tzinfo=tzo).isoformat(' ')
+        '2026-10-04 00:00:00-06:39'
+        >>> ts = Timestamp(2026, 10, 4, microsecond=100, tzinfo=tzo)
+        >>> ts.isoformat()
+        '2026-10-04T00:00:00-06:39'
+        >>> ts.isoformat(timespec='auto')
+        '2026-10-04T00:00:00.000100-06:39'
+
+        .. version-changed:: 3.0.20171212
+           *sep* parameter was added.
+        .. version-changed:: 11.9
+           *timespec* parameter was added. Timezone offsets are now
+           preserved.
+
+        :param sep: A one-character separator, placed between the date
+            and time portions of the result.
+        :param timespec: specifies the number of additional components
+            of the time to include. Refer :pylib:`datetime.isoformat
+            <datetime#datetime.datetime.isoformat>` for valid values.
         """
-        return self.strftime(self._ISO8601Format(sep))
+        ts = super().isoformat(sep, timespec)
+        if self.utcoffset() is None:
+            ts += 'Z'
+        elif self.utcoffset() == datetime.timedelta():
+            ts = ts.replace('+00:00', 'Z')
+        return ts

     def totimestampformat(self) -> str:
         """Convert object to a MediaWiki internal timestamp."""
@@ -339,7 +375,13 @@
         return f'{type(self).__name__}{s[s.find("("):]}'

     def __str__(self) -> str:
-        """Return a string format recognized by the API."""
+        """Return a string format recognized by the API.
+
+        For a :class:`Timestamp` instance ``t``, ``str(t)`` is
+        equivalent to :meth:`t.isoformat()<isoformat>`, which includes
+        the 'T' separator unlike the :meth:`datetime.datetime`
+        equivalent.
+        """
         return self.isoformat()

     @classmethod
diff --git a/tests/time_tests.py b/tests/time_tests.py
index 0a90bef..a1e3c53 100755
--- a/tests/time_tests.py
+++ b/tests/time_tests.py
@@ -14,6 +14,7 @@
 from datetime import datetime, timedelta, timezone

 from pywikibot.time import Timestamp, parse_duration, str2timedelta
+from pywikibot.tools import suppress_warnings
 from tests.aspects import TestCase


@@ -179,9 +180,12 @@

     def test_iso_format_property(self) -> None:
         """Test iso format properties."""
-        self.assertEqual(Timestamp.ISO8601Format, Timestamp._ISO8601Format())
-        self.assertEqual(re.sub(r'[\-:TZ]', '', Timestamp.ISO8601Format),
-                         Timestamp.mediawikiTSFormat)
+        with suppress_warnings(
+            r'.+Timestamp\.ISO8601Format is deprecated since release 11\.9\.0',
+            category=RuntimeWarning
+        ):
+            self.assertEqual(re.sub(r'[\-:TZ]', '', Timestamp.ISO8601Format),
+                             Timestamp.mediawikiTSFormat)

     def test_mediawiki_format(self) -> None:
         """Test conversion from and to Timestamp format."""

--
To view, visit 
https://gerrit.wikimedia.org/r/c/pywikibot/core/+/1348787?usp=email
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.wikimedia.org/r/settings?usp=email

Gerrit-MessageType: merged
Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Change-Id: I6e2d6900623157776d4b89efb3de319256200393
Gerrit-Change-Number: 1348787
Gerrit-PatchSet: 6
Gerrit-Owner: Xqt <[email protected]>
Gerrit-Reviewer: Mahveotm <[email protected]>
Gerrit-Reviewer: Xqt <[email protected]>
Gerrit-Reviewer: jenkins-bot
_______________________________________________
Pywikibot-commits mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to