Skip to content

Commit 7210b85

Browse files
authored
Timezone log fix (#323)
1 parent dd194aa commit 7210b85

5 files changed

Lines changed: 52 additions & 3 deletions

File tree

apprise_api/core/settings/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
APP_COPYRIGHT = "Copyright (C) 2026 Chris Caron <lead2gold@gmail.com>"
3737
APP_LICENSE = "MIT"
3838
APP_URL = "https://github.com/caronc/apprise-api"
39-
APP_VERSION = "1.4.0"
39+
APP_VERSION = "1.4.1"
4040

4141
# Disable Timezones
4242
USE_TZ = False

apprise_api/gunicorn.conf.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,23 @@
2323
# THE SOFTWARE.
2424
import multiprocessing
2525
import os
26+
import time
2627

2728
# This file is launched with the call:
2829
# gunicorn --config <this file> core.wsgi:application
2930

31+
# Apply the TZ environment variable before workers are forked so that Python's
32+
# time functions (used by logging formatters) use the same timezone as every
33+
# other process in the container (nginx, supervisord, etc.).
34+
if hasattr(time, "tzset"):
35+
time.tzset()
36+
3037
raw_env = [
3138
"LANG={}".format(os.environ.get("LANG", "en_US.UTF-8")),
3239
"DJANGO_SETTINGS_MODULE=core.settings",
40+
# Carry the resolved TZ into every worker so Python's logging formatter
41+
# uses the same timezone as nginx (which reads /etc/localtime directly).
42+
"TZ={}".format(os.environ.get("TZ", "Etc/UTC")),
3343
]
3444

3545
# This is the path as prepared in the docker compose
@@ -66,3 +76,10 @@
6676
# Enabling gunicorn's own access log produces duplicate entries
6777
accesslog = None
6878
loglevel = "warn"
79+
80+
81+
def post_fork(_server, _worker):
82+
# Re-apply TZ in each worker after fork so Python's time functions
83+
# (used by the logging formatter) use the same timezone as nginx.
84+
if hasattr(time, "tzset"):
85+
time.tzset()

apprise_api/supervisord-startup

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,38 @@
2222
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2323
# THE SOFTWARE.
2424

25+
# Timezone setup: ensure all processes (nginx, gunicorn, Python logging) use
26+
# the same timezone so log timestamps are always aligned.
27+
#
28+
# When TZ is set it is the authority: /etc/localtime is updated to match so
29+
# that C programs such as nginx, which read the file directly, agree with
30+
# Python (which reads TZ via time.tzset() in gunicorn.conf.py).
31+
#
32+
# When TZ is not set it is derived from the environment in priority order:
33+
# 1. /etc/localtime symlink target (common Docker host-timezone pattern)
34+
# 2. /etc/timezone (plain-file bind-mount fallback)
35+
# The derived name is exported as TZ so Python and nginx both pick it up.
36+
if [ -n "${TZ}" ]; then
37+
if [ -f "/usr/share/zoneinfo/${TZ}" ]; then
38+
echo "${TZ}" > /etc/timezone 2>/dev/null || true
39+
echo "Timezone: ${TZ}"
40+
else
41+
echo "WARNING: TZ='${TZ}' is not a valid timezone name; timestamps may be inaccurate"
42+
fi
43+
elif [ -L /etc/localtime ]; then
44+
_tz=$(readlink /etc/localtime | sed 's|.*/zoneinfo/||')
45+
if [ -n "${_tz}" ] && [ -f "/usr/share/zoneinfo/${_tz}" ]; then
46+
export TZ="${_tz}"
47+
echo "Timezone derived from /etc/localtime symlink: ${TZ}"
48+
fi
49+
elif [ -f /etc/timezone ]; then
50+
_tz=$(cat /etc/timezone 2>/dev/null | tr -d '[:space:]')
51+
if [ -n "${_tz}" ] && [ -f "/usr/share/zoneinfo/${_tz}" ]; then
52+
export TZ="${_tz}"
53+
echo "Timezone derived from /etc/timezone: ${TZ}"
54+
fi
55+
fi
56+
2557
# Nginx configuration file
2658
NGINX_CONF=/opt/apprise/webapp/etc/nginx.conf
2759
echo "$STRICT_MODE" | cut -c1 | grep -E -m1 -q -i '\(a|y|1|e|t|+)\)' 2>/dev/null

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ build-backend = "setuptools.build_meta"
2727

2828
[project]
2929
name = "apprise-api"
30-
version = "1.4.0"
30+
version = "1.4.1"
3131
authors = [{ name = "Chris Caron", email = "lead2gold@gmail.com" }]
3232
license = "MIT"
3333
dependencies = [

swagger.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ info:
55
description: >
66
A lightweight REST framework that wraps the Apprise API Notification
77
Library. See https://github.com/caronc/apprise-api for details.
8-
version: 1.4.0
8+
version: 1.4.1
99

1010
servers:
1111
- url: http://localhost:8000

0 commit comments

Comments
 (0)