feat: Add timezone configuration for Docker to ensure correct time handling in production and development environments
This commit is contained in:
129
DEPLOYMENT_TIMEZONE_FIX.md
Normal file
129
DEPLOYMENT_TIMEZONE_FIX.md
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
# Quick Deployment Guide - Timezone Fix
|
||||||
|
|
||||||
|
## For Production Server
|
||||||
|
|
||||||
|
1. **SSH into your server** where Docker is running
|
||||||
|
|
||||||
|
2. **Navigate to project directory**
|
||||||
|
```bash
|
||||||
|
cd /path/to/panel
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Pull latest code** (includes timezone fixes)
|
||||||
|
```bash
|
||||||
|
git pull origin main
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Stop running containers**
|
||||||
|
```bash
|
||||||
|
docker-compose -f docker-compose.prod.yml down
|
||||||
|
```
|
||||||
|
|
||||||
|
5. **Rebuild Docker images** (this is critical - it bakes in the timezone configuration)
|
||||||
|
```bash
|
||||||
|
docker-compose -f docker-compose.prod.yml build --no-cache
|
||||||
|
```
|
||||||
|
|
||||||
|
6. **Start containers**
|
||||||
|
```bash
|
||||||
|
docker-compose -f docker-compose.prod.yml up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
7. **Verify timezone is correct**
|
||||||
|
```bash
|
||||||
|
# Check container timezone
|
||||||
|
docker-compose -f docker-compose.prod.yml exec app date
|
||||||
|
# Should show Polish time with CEST/CET timezone
|
||||||
|
|
||||||
|
# Example output:
|
||||||
|
# Sat Oct 4 19:45:00 CEST 2025
|
||||||
|
```
|
||||||
|
|
||||||
|
8. **Test the fix**
|
||||||
|
- Post a new note at a known time (e.g., 19:45)
|
||||||
|
- Verify it displays the same time (19:45)
|
||||||
|
- Test both project notes and task notes
|
||||||
|
|
||||||
|
## What Changed
|
||||||
|
|
||||||
|
### Code Changes
|
||||||
|
- ✅ Fixed `datetime('now', 'localtime')` in all database queries
|
||||||
|
- ✅ Updated display formatters to use Europe/Warsaw timezone
|
||||||
|
- ✅ Fixed note display in components
|
||||||
|
|
||||||
|
### Docker Changes (Critical!)
|
||||||
|
- ✅ Set `ENV TZ=Europe/Warsaw` in Dockerfile
|
||||||
|
- ✅ Configured system timezone in containers
|
||||||
|
- ✅ Added TZ environment variable to docker-compose files
|
||||||
|
|
||||||
|
## Why Rebuild is Necessary
|
||||||
|
|
||||||
|
The timezone configuration is **baked into the Docker image** during build time:
|
||||||
|
- `ENV TZ=Europe/Warsaw` - Set during image build
|
||||||
|
- `RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime` - Executed during image build
|
||||||
|
|
||||||
|
Just restarting containers (`docker-compose restart`) will **NOT** apply these changes!
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### If times are still wrong after deployment:
|
||||||
|
|
||||||
|
1. **Verify you rebuilt the images**
|
||||||
|
```bash
|
||||||
|
docker images | grep panel
|
||||||
|
# Check the "CREATED" timestamp - should be recent
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Check if container has correct timezone**
|
||||||
|
```bash
|
||||||
|
docker-compose -f docker-compose.prod.yml exec app date
|
||||||
|
```
|
||||||
|
Should show Polish time, not UTC!
|
||||||
|
|
||||||
|
3. **Check SQLite is using correct time**
|
||||||
|
```bash
|
||||||
|
docker-compose -f docker-compose.prod.yml exec app node -e "const db = require('better-sqlite3')('./data/database.sqlite'); console.log(db.prepare(\"SELECT datetime('now', 'localtime') as time\").get());"
|
||||||
|
```
|
||||||
|
Should show current Polish time
|
||||||
|
|
||||||
|
4. **Force rebuild if needed**
|
||||||
|
```bash
|
||||||
|
docker-compose -f docker-compose.prod.yml down
|
||||||
|
docker system prune -f
|
||||||
|
docker-compose -f docker-compose.prod.yml build --no-cache
|
||||||
|
docker-compose -f docker-compose.prod.yml up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
## Expected Behavior After Fix
|
||||||
|
|
||||||
|
### Before Fix (Docker in UTC):
|
||||||
|
```
|
||||||
|
User posts note at 10:30 Poland time
|
||||||
|
→ Docker sees 08:30 UTC as "local time"
|
||||||
|
→ SQLite stores: 08:30
|
||||||
|
→ Display shows: 08:30 ❌ (2 hours off!)
|
||||||
|
```
|
||||||
|
|
||||||
|
### After Fix (Docker in Europe/Warsaw):
|
||||||
|
```
|
||||||
|
User posts note at 10:30 Poland time
|
||||||
|
→ Docker sees 10:30 Poland time as "local time"
|
||||||
|
→ SQLite stores: 10:30
|
||||||
|
→ Display shows: 10:30 ✅ (correct!)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Important Notes
|
||||||
|
|
||||||
|
1. **Old notes**: Notes created before this fix may still show incorrect times (they were stored in UTC)
|
||||||
|
2. **New notes**: All new notes after deployment will show correct times
|
||||||
|
3. **Audit logs**: Continue to work correctly (they always used ISO format)
|
||||||
|
4. **Zero downtime**: Can't achieve - need to stop/rebuild/start containers
|
||||||
|
|
||||||
|
## Quick Check Command
|
||||||
|
|
||||||
|
After deployment, run this one-liner to verify everything:
|
||||||
|
```bash
|
||||||
|
docker-compose -f docker-compose.prod.yml exec app sh -c 'date && node -e "console.log(new Date().toLocaleString(\"pl-PL\"))"'
|
||||||
|
```
|
||||||
|
|
||||||
|
Both outputs should show the same Polish time!
|
||||||
156
DOCKER_TIMEZONE_FIX.md
Normal file
156
DOCKER_TIMEZONE_FIX.md
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
# 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)
|
||||||
|
|
||||||
|
```dockerfile
|
||||||
|
# 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)
|
||||||
|
|
||||||
|
```dockerfile
|
||||||
|
# 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)
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
environment:
|
||||||
|
- NODE_ENV=development
|
||||||
|
- TZ=Europe/Warsaw
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Updated docker-compose.prod.yml (Production)
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
environment:
|
||||||
|
- NODE_ENV=production
|
||||||
|
- TZ=Europe/Warsaw
|
||||||
|
- NEXTAUTH_SECRET=...
|
||||||
|
- NEXTAUTH_URL=...
|
||||||
|
```
|
||||||
|
|
||||||
|
## How to Apply
|
||||||
|
|
||||||
|
### Option 1: Rebuild Docker Images
|
||||||
|
```bash
|
||||||
|
# Stop containers
|
||||||
|
docker-compose down
|
||||||
|
|
||||||
|
# Rebuild images
|
||||||
|
docker-compose build --no-cache
|
||||||
|
|
||||||
|
# Start containers
|
||||||
|
docker-compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
### Option 2: For Production Deployment
|
||||||
|
```bash
|
||||||
|
# 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:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 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
|
||||||
|
|
||||||
|
1. **TZ Environment Variable**: Tells all processes (including Node.js and SQLite) what timezone to use
|
||||||
|
2. **Symlink /etc/localtime**: Updates system timezone for the entire container
|
||||||
|
3. **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
|
||||||
|
|
||||||
|
1. **Must rebuild images**: Just restarting containers is not enough - the timezone configuration is baked into the image
|
||||||
|
2. **All existing data**: Old notes will still show incorrect times (they were stored in UTC)
|
||||||
|
3. **New notes**: Will now display correctly
|
||||||
|
4. **DST handling**: Europe/Warsaw automatically handles Daylight Saving Time transitions
|
||||||
|
|
||||||
|
## Alternative Approach (Not Recommended)
|
||||||
|
|
||||||
|
Instead of changing container timezone, you could:
|
||||||
|
1. Store everything in UTC (like audit logs do with ISO format)
|
||||||
|
2. Always convert on display
|
||||||
|
|
||||||
|
But this requires more code changes and the current approach is simpler and more maintainable.
|
||||||
|
|
||||||
|
## Files Modified
|
||||||
|
|
||||||
|
1. `Dockerfile` - Added TZ configuration
|
||||||
|
2. `Dockerfile.dev` - Added TZ configuration
|
||||||
|
3. `docker-compose.yml` - Added TZ environment variable
|
||||||
|
4. `docker-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)
|
||||||
@@ -1,6 +1,10 @@
|
|||||||
# Use Node.js 22.11.0 as the base image
|
# Use Node.js 22.11.0 as the base image
|
||||||
FROM node:22.11.0
|
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
|
||||||
|
|
||||||
# Install git
|
# Install git
|
||||||
RUN apt-get update && apt-get install -y git && rm -rf /var/lib/apt/lists/*
|
RUN apt-get update && apt-get install -y git && rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
# Use Node.js 22.11.0 as the base image
|
# Use Node.js 22.11.0 as the base image
|
||||||
FROM node:22.11.0
|
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
|
||||||
|
|
||||||
# Install git for development
|
# Install git for development
|
||||||
RUN apt-get update && apt-get install -y git && rm -rf /var/lib/apt/lists/*
|
RUN apt-get update && apt-get install -y git && rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ services:
|
|||||||
- ./uploads:/app/public/uploads
|
- ./uploads:/app/public/uploads
|
||||||
environment:
|
environment:
|
||||||
- NODE_ENV=production
|
- NODE_ENV=production
|
||||||
|
- TZ=Europe/Warsaw
|
||||||
- NEXTAUTH_SECRET=${NEXTAUTH_SECRET:-your-secret-key-generate-a-strong-random-string-at-least-32-characters}
|
- NEXTAUTH_SECRET=${NEXTAUTH_SECRET:-your-secret-key-generate-a-strong-random-string-at-least-32-characters}
|
||||||
- NEXTAUTH_URL=${NEXTAUTH_URL:-https://panel2.wastpol.pl}
|
- NEXTAUTH_URL=${NEXTAUTH_URL:-https://panel2.wastpol.pl}
|
||||||
- AUTH_TRUST_HOST=true
|
- AUTH_TRUST_HOST=true
|
||||||
|
|||||||
@@ -13,3 +13,4 @@ services:
|
|||||||
- ./data:/app/data
|
- ./data:/app/data
|
||||||
environment:
|
environment:
|
||||||
- NODE_ENV=development
|
- NODE_ENV=development
|
||||||
|
- TZ=Europe/Warsaw
|
||||||
|
|||||||
Reference in New Issue
Block a user