I think that this idea (adding a timestamp to exceptions) was already discussed previously, but I failed to find the link. Or maybe it was your PR gh-129337 that you created in January 2025.
I found the recent project dttb (created last January) which uses sys.excepthook to add a timestamp to exceptions. It uses datetime.datetime.now() and so has a resolution of 1 microsecond. It formats the timestamp at the beginning:
[2026-01-28 14:30:15.123456+08:00]
Traceback (most recent call last):
...
Error: something wrong
I find it interesting to put the timestamp at the start and don’t change str(exc).
Specification:
A new read/write attribute __timestamp_ns__ is added to BaseException. It stores nanoseconds since the Unix epoch
You should mention that’s a timestamp in the UTC time zone.
When timestamps are disabled, or for control flow exceptions (see below), the value is 0.
You should also use the value 0 when reading the clock fails. It’s rare but it can happen when the syscall is blocked by a sandbox (by mistake).
For the Python API (exc.__timestamp_ns__ attribute), would it make sense to return None instead of 0 when the timestamp is not set?
PYTHON_TRACEBACK_TIMESTAMPS environment variable
Set to us or 1 for microsecond-precision decimal timestamps, ns for nanoseconds, or iso for ISO 8601 UTC format. Empty, unset, or 0 disables timestamps (the default).
Can you mention that ISO 8601 format has a resolution of 1 microsecond?
Display Format:
The us format produces <@1776017164.530916> and the ns format produces <@1776017178687320256ns>.
I would prefer to use <@1776017178.687320256> format for ns, similar to the us format but with 3 extra digits after the dot. For example, using this format you can copy/paste the number to datetime.datetime.fromtimestamp() and time.gmtime():
>>> import datetime as dt
>>> print(dt.datetime.fromtimestamp(1776017178.687320256))
2026-04-12 20:06:18.687320
>>> import time
>>> time.gmtime(1776017178.687320256)
time.struct_time(tm_year=2026, tm_mon=4, tm_mday=12, tm_hour=18, tm_min=6, tm_sec=18, tm_wday=6, tm_yday=102, tm_isdst=0)
Performance Measurements.
FYI Linux and other operating systems provide a CLOCK_REALTIME_COARSE clock faster than CLOCK_REALTIME but with a worse resolution. For example, on Linux 6.19.10 with glibc 2.42, I measured in Python that CLOCK_REALTIME has a resolution of 137 nanoseconds, whereas CLOCK_REALTIME_COARSE only has a resolution of 1 ms! I don’t think that 1 ms resolution is enough for exception timestamps. Reading CLOCK_REALTIME_COARSE takes 28.8 ns +- 0.7 ns, whereas reading CLOCK_REALTIME takes 40.7 ns +- 1.6 ns.
TracebackException and the public formatting functions (print_exc, print_exception, format_exception, format_exception_only) gain a no_timestamp keyword argument (default False) that suppresses timestamp display even when globally enabled.
I dislike double negation (ex: no_timestamp=False). Would it be possible to change the parameter to timestamp instead (ex: timestamp=True)?
Rejected Ideas: Millisecond Precision.
Why not also offering the choice to format a timestamp with microsecond resolution? (PYTHON_TRACEBACK_TIMESTAMPS=ms)