4.2 KiB
4.2 KiB
Docker Timezone Configuration Fix
Problem
Even after fixing the SQLite datetime('now', 'localtime') calls, notes posted at 10:00 still showed as 08:00 when running in Docker.
Root Cause
Docker containers run in UTC timezone by default!
When using datetime('now', 'localtime') in SQLite:
- On local Windows machine: Uses Windows timezone (Europe/Warsaw) → ✅ Correct
- In Docker container: Uses container timezone (UTC) → ❌ Wrong by 2 hours
Example:
User posts at 10:00 Poland time (UTC+2)
↓
Docker container thinks local time is 08:00 UTC
↓
SQLite datetime('now', 'localtime') stores: 08:00
↓
Display shows: 08:00 (wrong!)
Solution
Set the Docker container timezone to Europe/Warsaw
1. Updated Dockerfile (Production)
# Use Node.js 22.11.0 as the base image
FROM node:22.11.0
# Set timezone to Europe/Warsaw (Polish timezone)
ENV TZ=Europe/Warsaw
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# ... rest of Dockerfile
2. Updated Dockerfile.dev (Development)
# Use Node.js 22.11.0 as the base image
FROM node:22.11.0
# Set timezone to Europe/Warsaw (Polish timezone)
ENV TZ=Europe/Warsaw
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# ... rest of Dockerfile
3. Updated docker-compose.yml (Development)
environment:
- NODE_ENV=development
- TZ=Europe/Warsaw
4. Updated docker-compose.prod.yml (Production)
environment:
- NODE_ENV=production
- TZ=Europe/Warsaw
- NEXTAUTH_SECRET=...
- NEXTAUTH_URL=...
How to Apply
Option 1: Rebuild Docker Images
# Stop containers
docker-compose down
# Rebuild images
docker-compose build --no-cache
# Start containers
docker-compose up -d
Option 2: For Production Deployment
# Pull latest code with fixes
git pull
# Rebuild production image
docker-compose -f docker-compose.prod.yml build --no-cache
# Restart
docker-compose -f docker-compose.prod.yml up -d
Verification
After rebuilding and restarting, verify timezone inside container:
# Check timezone
docker exec -it <container_name> date
# Should show: Sat Oct 4 19:00:00 CEST 2025
# Check Node.js sees correct timezone
docker exec -it <container_name> node -e "console.log(new Date().toLocaleString('pl-PL', {timeZone: 'Europe/Warsaw'}))"
# Should show current Polish time
# Check SQLite sees correct timezone
docker exec -it <container_name> node -e "const db = require('better-sqlite3')('./data/database.sqlite'); console.log(db.prepare(\"SELECT datetime('now', 'localtime')\").get());"
# Should show current Polish time
Why This Works
- TZ Environment Variable: Tells all processes (including Node.js and SQLite) what timezone to use
- Symlink /etc/localtime: Updates system timezone for the entire container
- echo TZ > /etc/timezone: Ensures the timezone persists
Now when SQLite uses datetime('now', 'localtime'):
- Container local time is 10:00 Poland time
- SQLite stores: 10:00
- Display shows: 10:00 ✅
Important Notes
- Must rebuild images: Just restarting containers is not enough - the timezone configuration is baked into the image
- All existing data: Old notes will still show incorrect times (they were stored in UTC)
- New notes: Will now display correctly
- DST handling: Europe/Warsaw automatically handles Daylight Saving Time transitions
Alternative Approach (Not Recommended)
Instead of changing container timezone, you could:
- Store everything in UTC (like audit logs do with ISO format)
- Always convert on display
But this requires more code changes and the current approach is simpler and more maintainable.
Files Modified
Dockerfile- Added TZ configurationDockerfile.dev- Added TZ configurationdocker-compose.yml- Added TZ environment variabledocker-compose.prod.yml- Added TZ environment variable
Testing Checklist
After deployment:
- Container shows correct date/time with
docker exec <container> date - Post a new note at known time (e.g., 10:30)
- Verify note displays the same time (10:30)
- Check both project notes and task notes
- Verify audit logs still work correctly
- Check task timestamps (date_started, date_completed)