diff --git a/TIMEZONE_SETUP.md b/TIMEZONE_SETUP.md new file mode 100644 index 0000000..367471e --- /dev/null +++ b/TIMEZONE_SETUP.md @@ -0,0 +1,209 @@ +# Configuración de Zona Horaria - Atlantic/Canary + +## Cambios Implementados + +Se ha configurado la zona horaria de **Atlantic/Canary (Islas Canarias, España)** en toda la aplicación: + +### 1. Base de Datos PostgreSQL +- **Zona horaria**: `Atlantic/Canary` (UTC+0 en invierno, UTC+1 en verano con horario de verano) +- Variables de entorno agregadas: + - `TZ=Atlantic/Canary` + - `PGTZ=Atlantic/Canary` + +### 2. Backend FastAPI +- Configuración de zona horaria de Python al inicio de la aplicación +- Conexión a PostgreSQL configurada con timezone +- Event listener para establecer timezone en cada conexión +- Variable de entorno: `TZ=Atlantic/Canary` + +### 3. Frontend React +- Los filtros de fecha usan el constructor de Date con zona horaria local +- Las fechas se muestran en formato español (es-ES) + +## Aplicar los Cambios + +### Desarrollo Local + +1. **Parar los contenedores actuales**: + ```powershell + docker-compose down + ``` + +2. **Aplicar la migración de zona horaria a la base de datos**: + ```powershell + docker-compose up -d postgres + + # Esperar a que PostgreSQL esté listo + Start-Sleep -Seconds 5 + + # Aplicar migración + docker-compose exec postgres psql -U checklist_user -d checklist_db -f /docker-entrypoint-initdb.d/../migrations/set_timezone_canary.sql + ``` + + **Alternativa manual**: + ```powershell + # Copiar el archivo SQL al contenedor + docker cp migrations/set_timezone_canary.sql checklist-db:/tmp/ + + # Ejecutarlo + docker-compose exec postgres psql -U checklist_user -d checklist_db -f /tmp/set_timezone_canary.sql + ``` + +3. **Reconstruir y levantar todos los servicios**: + ```powershell + docker-compose build + docker-compose up -d + ``` + +4. **Verificar la configuración**: + ```powershell + # Verificar timezone en PostgreSQL + docker-compose exec postgres psql -U checklist_user -d checklist_db -c "SHOW timezone;" + + # Verificar timezone en backend + docker-compose exec backend python -c "import time; print(time.tzname)" + ``` + +### Producción + +#### Docker Compose Production + +1. **Parar servicios**: + ```bash + docker-compose -f docker-compose.prod.yml down + ``` + +2. **Aplicar migración**: + ```bash + docker-compose -f docker-compose.prod.yml up -d postgres + docker cp migrations/set_timezone_canary.sql syntria-db-prod:/tmp/ + docker-compose -f docker-compose.prod.yml exec postgres psql -U syntria_user -d syntria_db -f /tmp/set_timezone_canary.sql + ``` + +3. **Reconstruir imágenes y desplegar**: + ```bash + ./build-and-push.sh # o build-and-push.ps1 en Windows + docker-compose -f docker-compose.prod.yml pull + docker-compose -f docker-compose.prod.yml up -d + ``` + +#### Docker Swarm + +1. **Aplicar migración en el nodo manager**: + ```bash + # Encontrar el contenedor de PostgreSQL + docker ps | grep syntria_db + + # Copiar y ejecutar migración + docker cp migrations/set_timezone_canary.sql :/tmp/ + docker exec psql -U syntria_user -d syntria_db -f /tmp/set_timezone_canary.sql + ``` + +2. **Actualizar stack**: + ```bash + docker stack deploy -c docker-stack.yml syntria + ``` + +## Verificación Post-Despliegue + +### 1. Verificar Zona Horaria de PostgreSQL +```sql +-- Debería mostrar: Atlantic/Canary +SHOW timezone; + +-- Verificar hora actual del servidor +SELECT NOW(); +SELECT CURRENT_TIMESTAMP; +``` + +### 2. Verificar Backend +```bash +docker-compose exec backend python -c " +from datetime import datetime +import time +print('Timezone:', time.tzname) +print('Hora actual:', datetime.now()) +print('UTC:', datetime.utcnow()) +" +``` + +### 3. Probar en la Aplicación +1. Crear una nueva inspección +2. Verificar que la fecha/hora de inicio coincida con la hora local de Canarias +3. Filtrar por fecha y verificar que el filtro funcione correctamente + +## Comportamiento de las Fechas + +### Fechas Existentes +- Las fechas ya guardadas en la base de datos **no se modifican** +- PostgreSQL las almacena internamente en UTC +- Se mostrarán en hora de Canarias al consultarlas + +### Nuevas Fechas +- Se guardarán con timezone de Canarias +- Se convertirán automáticamente a UTC para almacenamiento +- Se mostrarán en hora de Canarias al recuperarlas + +## Horario de Verano + +La zona horaria `Atlantic/Canary` maneja automáticamente el horario de verano: +- **Invierno (octubre - marzo)**: UTC+0 / WET (Western European Time) +- **Verano (marzo - octubre)**: UTC+1 / WEST (Western European Summer Time) + +## Troubleshooting + +### Las fechas siguen mostrándose incorrectas + +1. Verificar que los contenedores se reiniciaron después de los cambios: + ```powershell + docker-compose restart + ``` + +2. Verificar logs del backend: + ```powershell + docker-compose logs backend | Select-String -Pattern "timezone|TZ" + ``` + +3. Limpiar caché del navegador y recargar la aplicación + +### Error al conectar a la base de datos + +Si ves errores relacionados con timezone al conectar: +``` +could not find timezone "Atlantic/Canary" +``` + +Solución: +```bash +# Entrar al contenedor de PostgreSQL +docker-compose exec postgres sh + +# Instalar datos de zona horaria (si no están instalados) +apk add --no-cache tzdata + +# Salir y reiniciar +exit +docker-compose restart postgres +``` + +### Las fechas en el frontend no coinciden + +El frontend usa la zona horaria del navegador del usuario. Si el usuario está en una zona diferente a Canarias, verá las fechas en su hora local. Para forzar visualización en hora de Canarias en el frontend, se pueden usar bibliotecas como `date-fns-tz` o `luxon`. + +## Archivos Modificados + +- ✅ `docker-compose.yml` - Variables TZ para postgres y backend +- ✅ `docker-compose.prod.yml` - Variables TZ para postgres y backend +- ✅ `docker-stack.yml` - Variables TZ para db y backend +- ✅ `backend/app/core/database.py` - Configuración de conexión con timezone +- ✅ `backend/app/main.py` - Configuración de TZ de Python +- ✅ `migrations/set_timezone_canary.sql` - Script de migración +- ✅ `frontend/src/App.jsx` - Uso correcto de fechas locales + +## Notas Importantes + +⚠️ **Después de aplicar estos cambios en producción**: +- Hacer backup de la base de datos antes de aplicar cambios +- Aplicar en horario de bajo tráfico +- Verificar que todas las funcionalidades de fecha/hora funcionan correctamente +- Informar a los usuarios si hay cambios visibles en las fechas mostradas diff --git a/backend/app/core/database.py b/backend/app/core/database.py index e728703..5ac6c32 100644 --- a/backend/app/core/database.py +++ b/backend/app/core/database.py @@ -1,4 +1,4 @@ -from sqlalchemy import create_engine +from sqlalchemy import create_engine, event from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker from app.core.config import settings @@ -6,9 +6,17 @@ from app.core.config import settings engine = create_engine( settings.DATABASE_URL, pool_pre_ping=True, - echo=settings.ENVIRONMENT == "development" + echo=settings.ENVIRONMENT == "development", + connect_args={"options": "-c timezone=Atlantic/Canary"} ) +# Configurar zona horaria al conectar +@event.listens_for(engine, "connect") +def set_timezone(dbapi_conn, connection_record): + cursor = dbapi_conn.cursor() + cursor.execute("SET TIME ZONE 'Atlantic/Canary';") + cursor.close() + SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) Base = declarative_base() diff --git a/backend/app/main.py b/backend/app/main.py index 1f1f30a..4e2837d 100644 --- a/backend/app/main.py +++ b/backend/app/main.py @@ -1,4 +1,10 @@ +# ============= CONFIGURACIÓN DE ZONA HORARIA ============= +import os +os.environ['TZ'] = 'Atlantic/Canary' +import time +time.tzset() + # ============= LOGO CONFIGURABLE ============= from fastapi import FastAPI, File, UploadFile, Form, Depends, HTTPException, status diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index 3453500..c593611 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -6,6 +6,8 @@ services: POSTGRES_DB: ${POSTGRES_DB:-syntria_db} POSTGRES_USER: ${POSTGRES_USER:-syntria_user} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + TZ: Atlantic/Canary + PGTZ: Atlantic/Canary ports: - "5432:5432" volumes: @@ -29,6 +31,7 @@ services: OPENAI_API_KEY: ${OPENAI_API_KEY} ENVIRONMENT: production ALLOWED_ORIGINS: ${ALLOWED_ORIGINS:-http://localhost,http://localhost:5173} + TZ: Atlantic/Canary ports: - "8000:8000" volumes: diff --git a/docker-compose.yml b/docker-compose.yml index 16ba8d8..8ddc7a7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,6 +6,8 @@ services: POSTGRES_DB: ${POSTGRES_DB:-checklist_db} POSTGRES_USER: ${POSTGRES_USER:-checklist_user} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-checklist_pass_2024} + TZ: Atlantic/Canary + PGTZ: Atlantic/Canary ports: - "5432:5432" volumes: @@ -25,6 +27,7 @@ services: SECRET_KEY: ${SECRET_KEY:-your-secret-key-change-in-production-min-32-chars} OPENAI_API_KEY: ${OPENAI_API_KEY} ENVIRONMENT: ${ENVIRONMENT:-development} + TZ: Atlantic/Canary ports: - "8000:8000" volumes: diff --git a/docker-stack.yml b/docker-stack.yml index 328fe18..2f5523e 100644 --- a/docker-stack.yml +++ b/docker-stack.yml @@ -7,6 +7,8 @@ services: POSTGRES_DB: syntria_db POSTGRES_USER: syntria_user POSTGRES_PASSWORD: syntria_secure_2024 + TZ: Atlantic/Canary + PGTZ: Atlantic/Canary volumes: - postgres_data:/var/lib/postgresql/data networks: @@ -35,6 +37,7 @@ services: GEMINI_API_KEY: tu_api_key_de_gemini ENVIRONMENT: production ALLOWED_ORIGINS: http://localhost,https://syntria.tudominio.com + TZ: Atlantic/Canary networks: - syntria_network - network_public diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index d901dfc..d9b6b52 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -4181,13 +4181,15 @@ function InspectionsTab({ inspections, user, onUpdate, onContinue }) { if (dateFrom || dateTo) { const inspectionDate = new Date(inspection.started_at) if (dateFrom) { - const fromDate = new Date(dateFrom) - fromDate.setHours(0, 0, 0, 0) + // Crear fecha en hora local del usuario + const [year, month, day] = dateFrom.split('-') + const fromDate = new Date(year, month - 1, day, 0, 0, 0, 0) matchesDate = matchesDate && inspectionDate >= fromDate } if (dateTo) { - const toDate = new Date(dateTo) - toDate.setHours(23, 59, 59, 999) + // Crear fecha en hora local del usuario + const [year, month, day] = dateTo.split('-') + const toDate = new Date(year, month - 1, day, 23, 59, 59, 999) matchesDate = matchesDate && inspectionDate <= toDate } } diff --git a/migrations/set_timezone_canary.sql b/migrations/set_timezone_canary.sql new file mode 100644 index 0000000..5a7457a --- /dev/null +++ b/migrations/set_timezone_canary.sql @@ -0,0 +1,16 @@ +-- Migración: Configurar zona horaria de Canarias en la base de datos +-- Fecha: 2024-12-08 +-- Descripción: Establece Atlantic/Canary como zona horaria por defecto + +-- Establecer zona horaria para la sesión actual +SET TIME ZONE 'Atlantic/Canary'; + +-- Configurar zona horaria por defecto para la base de datos +ALTER DATABASE checklist_db SET timezone TO 'Atlantic/Canary'; + +-- Nota: Las fechas existentes en la base de datos se mantendrán tal cual están almacenadas +-- PostgreSQL almacena las fechas con timezone en UTC internamente y las convierte según la zona horaria configurada +-- Si necesitas convertir fechas existentes, ejecuta manualmente según sea necesario + +-- Para verificar la configuración: +SHOW timezone;