diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 4d55243b59beded46411a01c53000126b6215e5c..922c569d38f00c108da42f2cd9e7744fd684656e 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -4,7 +4,7 @@ ci:
 
 repos:
   - repo: https://github.com/astral-sh/ruff-pre-commit
-    rev: v0.9.10
+    rev: v0.11.7
     hooks:
       - id: ruff
         args: [--fix, --exit-non-zero-on-fix]
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 23f15a672cea3c0ff9613a05b12c4b7c430560b6..ce0ac4b4ab738a72de3e09bd10dd5e7627d15f2c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,6 +13,14 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/
 <!-- changelog follows -->
 
 
+## [25.3.0](https://github.com/hynek/structlog/compare/25.2.0...25.3.0) - 2025-04-25
+
+### Fixed
+
+- `structlog.processors.TimeStamper` now again uses timestamps using UTC for custom format strings when `utc=True`.
+  [#713](https://github.com/hynek/structlog/pull/713)
+
+
 ## [25.2.0](https://github.com/hynek/structlog/compare/25.1.0...25.2.0) - 2025-03-11
 
 ### Added
diff --git a/PKG-INFO b/PKG-INFO
index ee85fef91f5950214f0c0fa9c487839c4e7174d7..d04857a9eec242227aee1987e9c917b750f55b7d 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 2.4
 Name: structlog
-Version: 25.2.0
+Version: 25.3.0
 Summary: Structured Logging for Python
 Project-URL: Documentation, https://www.structlog.org/
 Project-URL: Changelog, https://github.com/hynek/structlog/blob/main/CHANGELOG.md
@@ -94,15 +94,15 @@ Especially those generously supporting us at the *The Organization* tier and hig
 import pathlib, tomllib
 
 for sponsor in tomllib.loads(pathlib.Path("pyproject.toml").read_text())["tool"]["sponcon"]["sponsors"]:
-      print(f'<a href="{sponsor["url"]}"><img title="{sponsor["title"]}" src="https://www.structlog.org/en/25.2.0/_static/sponsors/{sponsor["img"]}" width="190" /></a>')
+      print(f'<a href="{sponsor["url"]}"><img title="{sponsor["title"]}" src="https://www.structlog.org/en/25.3.0/_static/sponsors/{sponsor["img"]}" width="190" /></a>')
 ]]] -->
-<a href="https://www.variomedia.de/"><img title="Variomedia AG" src="https://www.structlog.org/en/25.2.0/_static/sponsors/Variomedia.svg" width="190" /></a>
-<a href="https://tidelift.com/?utm_source=lifter&utm_medium=referral&utm_campaign=hynek"><img title="Tidelift" src="https://www.structlog.org/en/25.2.0/_static/sponsors/Tidelift.svg" width="190" /></a>
-<a href="https://klaviyo.com/"><img title="Klaviyo" src="https://www.structlog.org/en/25.2.0/_static/sponsors/Klaviyo.svg" width="190" /></a>
-<a href="https://privacy-solutions.org/"><img title="Privacy Solutions" src="https://www.structlog.org/en/25.2.0/_static/sponsors/Privacy-Solutions.svg" width="190" /></a>
-<a href="https://www.emsys-renewables.com/"><img title="emsys renewables" src="https://www.structlog.org/en/25.2.0/_static/sponsors/emsys-renewables.svg" width="190" /></a>
-<a href="https://filepreviews.io/"><img title="FilePreviews" src="https://www.structlog.org/en/25.2.0/_static/sponsors/FilePreviews.svg" width="190" /></a>
-<a href="https://polar.sh/"><img title="Polar" src="https://www.structlog.org/en/25.2.0/_static/sponsors/Polar.svg" width="190" /></a>
+<a href="https://www.variomedia.de/"><img title="Variomedia AG" src="https://www.structlog.org/en/25.3.0/_static/sponsors/Variomedia.svg" width="190" /></a>
+<a href="https://tidelift.com/?utm_source=lifter&utm_medium=referral&utm_campaign=hynek"><img title="Tidelift" src="https://www.structlog.org/en/25.3.0/_static/sponsors/Tidelift.svg" width="190" /></a>
+<a href="https://klaviyo.com/"><img title="Klaviyo" src="https://www.structlog.org/en/25.3.0/_static/sponsors/Klaviyo.svg" width="190" /></a>
+<a href="https://privacy-solutions.org/"><img title="Privacy Solutions" src="https://www.structlog.org/en/25.3.0/_static/sponsors/Privacy-Solutions.svg" width="190" /></a>
+<a href="https://www.emsys-renewables.com/"><img title="emsys renewables" src="https://www.structlog.org/en/25.3.0/_static/sponsors/emsys-renewables.svg" width="190" /></a>
+<a href="https://filepreviews.io/"><img title="FilePreviews" src="https://www.structlog.org/en/25.3.0/_static/sponsors/FilePreviews.svg" width="190" /></a>
+<a href="https://polar.sh/"><img title="Polar" src="https://www.structlog.org/en/25.3.0/_static/sponsors/Polar.svg" width="190" /></a>
 <!-- [[[end]]] -->
 
 </p>
@@ -138,28 +138,11 @@ Save time, reduce risk, and improve code health, while paying the maintainers of
 
 ## Release Information
 
-### Added
-
-- `structlog.tracebacks.Stack` now includes an `exc_notes` field reflecting the notes attached to the exception.
-  [#684](https://github.com/hynek/structlog/pull/684)
-
-
-### Changed
-
-- `structlog.stdlib.BoundLogger`'s binding-related methods now also return `Self`.
-  [#694](https://github.com/hynek/structlog/pull/694)
-
-- `structlog.processors.TimeStamper` now produces internally timezone-aware `datetime` objects.
-  Default output hasn't changed, but you can now use `%z` in your *fmt* string.
-  [#709](https://github.com/hynek/structlog/pull/709)
-
-
 ### Fixed
 
--  Expose `structlog.dev.RichTracebackFormatter` for imports.
-   [#699](https://github.com/hynek/structlog/pull/699)
--  Expose `structlog.processors.LogfmtRenderer` for imports.
-   [#701](https://github.com/hynek/structlog/pull/701)
+- `structlog.processors.TimeStamper` now again uses timestamps using UTC for custom format strings when `utc=True`.
+  [#713](https://github.com/hynek/structlog/pull/713)
+
 
 ---
 
diff --git a/src/structlog/processors.py b/src/structlog/processors.py
index 4ef7578099743f99b730d4b02c38d4c0b28a8af9..39e1532822ea0c80385c4547d7cc3798e370efbe 100644
--- a/src/structlog/processors.py
+++ b/src/structlog/processors.py
@@ -553,12 +553,18 @@ def _make_stamper(
 
         return stamper_iso_local
 
-    def stamper_fmt(event_dict: EventDict) -> EventDict:
+    def stamper_fmt_local(event_dict: EventDict) -> EventDict:
         event_dict[key] = now().astimezone().strftime(fmt)
+        return event_dict
 
+    def stamper_fmt_utc(event_dict: EventDict) -> EventDict:
+        event_dict[key] = now().strftime(fmt)
         return event_dict
 
-    return stamper_fmt
+    if utc:
+        return stamper_fmt_utc
+
+    return stamper_fmt_local
 
 
 class MaybeTimeStamper:
diff --git a/tests/processors/test_renderers.py b/tests/processors/test_renderers.py
index be8007add04b3ff316f598512c70a23e393fc3eb..1bef95f04b850f56ff5f886afe60577405df0ee9 100644
--- a/tests/processors/test_renderers.py
+++ b/tests/processors/test_renderers.py
@@ -414,6 +414,36 @@ class TestTimeStamper:
 
         assert "1980" == d["timestamp"]
 
+    @freeze_time("1980-03-25 16:00:00")
+    def test_inserts_formatted_utc(self):
+        """
+        The fmt string in UTC timezone works.
+
+        The exact hours calculated here maybe incorrect because of freezegun bugs:
+        https://github.com/spulec/freezegun/issues/348
+        https://github.com/spulec/freezegun/issues/494
+        """
+
+        ts = TimeStamper(fmt="%Y-%m-%d %H:%M:%S %Z")
+        d = ts(None, None, {})
+
+        assert "1980-03-25 16:00:00 UTC" == d["timestamp"]
+
+    @freeze_time("1980-03-25 16:00:00")
+    def test_inserts_formatted_local(self):
+        """
+        The fmt string in local timezone works.
+
+        The exact hours calculated here maybe incorrect because of freezegun bugs:
+        https://github.com/spulec/freezegun/issues/348
+        https://github.com/spulec/freezegun/issues/494
+        """
+        local_tz = datetime.datetime.now().astimezone().tzname()
+        ts = TimeStamper(fmt="%Y-%m-%d %H:%M:%S %Z", utc=False)
+        d = ts(None, None, {})
+
+        assert f"1980-03-25 16:00:00 {local_tz}" == d["timestamp"]
+
     @freeze_time("1980-03-25 16:00:00")
     def test_tz_aware(self):
         """
diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py
index 383e60dd5decb014d85ac1a732d8dd1d87f99d2a..607308d36d266571eff857027d2a26620ba0f163 100644
--- a/tests/test_stdlib.py
+++ b/tests/test_stdlib.py
@@ -663,7 +663,7 @@ class TestExtraAdder:
         handler.setLevel(0)
         logger.addHandler(handler)
         logger.setLevel(0)
-        logging.warning("allow = %s", allow)
+        logging.warning("allow = %s", allow)  # noqa: LOG015
 
         event_dict = {"event": "Some text"}
         expected = self._copy_allowed(event_dict, extra_dict, allow)