Skip to content

Commit 08ed51d

Browse files
Document adding timezone offset to Apache error log timestamps.
Expand the timezone section of the application issues guide to explain the ErrorLogFormat %t options (c/u/z) and give verified, ready-to-use ErrorLogFormat examples that reproduce the default layout with a timezone offset added, using %{uz}t or compact ISO 8601 %{cuz}t. Warn about the leading-% strftime pitfall and note that the c/u/z options are formatted by Apache itself and are portable across Linux, macOS and Windows whereas strftime forms are not. Frame the whole as a partial mitigation that follows from the TZ recommendation rather than a separate aside.
1 parent a667f79 commit 08ed51d

1 file changed

Lines changed: 63 additions & 8 deletions

File tree

docs/user-guides/application-issues.rst

Lines changed: 63 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -344,14 +344,69 @@ matches the default for many applications, including Django when
344344
``TIME_ZONE`` is left at its ``UTC`` default. If the application uses a
345345
different timezone, set ``TZ`` to that same timezone instead.
346346

347-
Note that there is no Apache log format directive which will solve this by
348-
forcing UTC. Both ``ErrorLogFormat`` and ``CustomLog`` / ``LogFormat``
349-
format their ``%t`` timestamps from the process's local time, derived from
350-
``TZ``; even the compact ISO 8601 forms such as ``%{cu}t`` use local time,
351-
not UTC. The ``%{cuz}t`` form (Apache 2.4.58 and later) at least appends
352-
the numeric timezone offset, so lines stamped in different timezones can
353-
be told apart rather than silently misread, but it does not make them
354-
consistent.
347+
Where you are not able to change how Apache is started, a log format
348+
directive offers a partial mitigation, though not a cure. It is worth
349+
being clear about its limits, because reaching for the log configuration
350+
is the natural first instinct. No ``ErrorLogFormat`` or ``CustomLog`` /
351+
``LogFormat`` option can force these timestamps to a fixed zone such as
352+
UTC; ``%t`` is always formatted from the emitting process's local time,
353+
derived from ``TZ``. What a log format *can* do is make the timezone of
354+
each line explicit, so that lines stamped by processes in different
355+
timezones can be told apart rather than silently misread.
356+
357+
In an ``ErrorLogFormat`` the ``%t`` field accepts a small set of single
358+
letter options inside the braces:
359+
360+
* ``%t`` produces the default ``ctime`` style, ``Fri Jun 05 08:42:44 2026``.
361+
* ``%{u}t`` is the same but with microseconds. This is what the Apache
362+
default ``ErrorLogFormat`` uses.
363+
* the ``c`` option switches to the compact ISO 8601 form,
364+
``2026-06-05 08:42:36``.
365+
* the ``z`` option (Apache 2.4.58 and later) appends the numeric timezone
366+
offset, ``+1000``.
367+
368+
The options combine, so ``%{cu}t`` is compact ISO 8601 with microseconds
369+
but still no offset, and ``%{cuz}t`` is that with the offset added on the
370+
end.
371+
372+
To keep the familiar default layout and simply add the timezone offset,
373+
take the Apache default ``ErrorLogFormat`` and change its ``%{u}t`` field
374+
to ``%{uz}t``::
375+
376+
ErrorLogFormat "[%{uz}t] [%-m:%l] [pid %P:tid %T] %7F: %E: [client\ %a] %M% ,\ referer\ %{Referer}i"
377+
378+
A line then looks like the following, identical to the default apart from
379+
the trailing ``+1000``::
380+
381+
[Fri Jun 05 08:42:29.986168 2026 +1000] [mpm_event:notice] [pid 37192:tid 140704575428864] AH00489: ...
382+
383+
If you prefer the compact ISO 8601 timestamp, use ``%{cuz}t`` instead::
384+
385+
ErrorLogFormat "[%{cuz}t] [%-m:%l] [pid %P:tid %T] %7F: %E: [client\ %a] %M% ,\ referer\ %{Referer}i"
386+
387+
[2026-06-05 08:42:36.978307 +1000] [mpm_event:notice] [pid 37243:tid 140704575428864] AH00489: ...
388+
389+
A word of caution about the syntax. The ``c``, ``u`` and ``z`` letters are
390+
options, not ``strftime`` conversions, and must appear directly inside the
391+
braces with no leading ``%``. If you write ``%{%cuz}t`` instead of
392+
``%{cuz}t``, the leading ``%`` switches the field into ``strftime`` mode,
393+
where ``%c`` expands to the C library's locale date and time and the
394+
remaining ``uz`` is copied through literally, producing nonsense such as
395+
``Fri Jun 5 08:42:25 2026uz``.
396+
397+
This distinction also matters across platforms. The ``c``, ``u`` and ``z``
398+
options are formatted by Apache itself and behave identically on Linux,
399+
macOS and Windows. The ``strftime`` forms, such as ``%{%d/%b/%Y %T}t``,
400+
are passed to the platform C library's ``strftime(3)``, whose set of
401+
supported conversions varies; Windows in particular omits or alters
402+
several of them, with ``%z`` for example yielding a timezone name rather
403+
than a numeric offset. Preferring ``%{cuz}t`` over a hand written
404+
``strftime`` string therefore also gives consistent output everywhere.
405+
406+
Adding the offset lets the two timezones be distinguished, but it does not
407+
make them consistent. The only way to have every process agree remains to
408+
start the Apache parent process with the same ``TZ`` the application uses,
409+
as described above.
355410

356411
Be aware also that this only addresses divergence between processes. If a
357412
single daemon process hosts multiple sub interpreters that set different

0 commit comments

Comments
 (0)