6.1 KiB
6.1 KiB
Timezone Validation Script
🔍 Problema Detectado
Datos actuales:
- BD:
2025-10-15 01:55:00+00(UTC) - API retorna:
2025-10-14T19:55:00Z(UTC) - Frontend muestra:
14/10/2025, 13:55:00(America/Mexico_City = UTC-6)
Análisis:
- ❌ BD → API: Diferencia de 6 horas (Oct 15 01:55 → Oct 14 19:55)
- ✅ API → Frontend: Correcto (Oct 14 19:55 UTC → Oct 14 13:55 CST)
🐛 Causa Probable
El ValueConverter en el DbContext está causando una conversión incorrecta:
// SplashPageDbContext.cs línea 66-69
property.SetValueConverter(new ValueConverter<DateTime, DateTime>(
v => v.ToUniversalTime(), // Al guardar: siempre UTC
v => DateTime.SpecifyKind(v, DateTimeKind.Utc) // Al leer: marcar como UTC ❌
));
Problema:
- PostgreSQL almacena:
2025-10-15 01:55:00+00(UTC) - Npgsql lee y convierte al timezone local del servidor (probablemente UTC-6)
- El ValueConverter solo hace
SpecifyKind(v, Utc)sin reconvertir - Resultado: La fecha está en timezone local pero marcada como UTC
✅ Pasos de Validación
1. Verificar Timezone del Servidor
Ejecuta en el servidor donde corre el backend:
# Linux/Mac
date
timedatectl
# Windows
tzutil /g
2. Verificar Configuración de PostgreSQL
Ejecuta en PostgreSQL:
-- Ver timezone de la sesión
SHOW timezone;
-- Ver la fecha tal como está almacenada
SELECT
"ScheduledDateTime",
"ScheduledDateTime" AT TIME ZONE 'UTC' as utc_time,
"ScheduledDateTime" AT TIME ZONE 'America/Mexico_City' as mexico_time
FROM "SplashScheduledEmails"
WHERE "Id" = 'tu-guid-aqui';
3. Crear Endpoint de Diagnóstico Temporal
Agrega este controlador temporal para diagnosticar:
Archivo: src/SplashPage.Web.Host/Controllers/DiagnosticController.cs
using Microsoft.AspNetCore.Mvc;
using Abp.Domain.Repositories;
using SplashPage.Splash;
using System;
using System.Linq;
using System.Threading.Tasks;
namespace SplashPage.Web.Host.Controllers
{
[Route("api/[controller]")]
public class DiagnosticController : SplashPageControllerBase
{
private readonly IRepository<SplashScheduledEmail, Guid> _repository;
public DiagnosticController(IRepository<SplashScheduledEmail, Guid> repository)
{
_repository = repository;
}
[HttpGet("timezone-test/{id}")]
public async Task<object> TimezoneTest(Guid id)
{
var entity = await _repository.FirstOrDefaultAsync(id);
if (entity == null) return NotFound();
var scheduledDateTime = entity.ScheduledDateTime;
return new
{
// Información del servidor
serverTimezone = TimeZoneInfo.Local.DisplayName,
serverTimezoneId = TimeZoneInfo.Local.Id,
serverCurrentTime = DateTime.Now,
serverCurrentTimeUtc = DateTime.UtcNow,
// Fecha desde la BD
fromDatabase = new
{
value = scheduledDateTime,
kind = scheduledDateTime.Kind.ToString(),
ticks = scheduledDateTime.Ticks,
// Diferentes representaciones
asString = scheduledDateTime.ToString("yyyy-MM-ddTHH:mm:ss.fffZ"),
asIso = scheduledDateTime.ToString("o"),
toUtc = scheduledDateTime.ToUniversalTime(),
toLocal = scheduledDateTime.ToLocalTime(),
},
// Lo que se serializa en JSON
serializedValue = scheduledDateTime // ASP.NET lo serializa automáticamente
};
}
}
}
4. Llamar al Endpoint de Diagnóstico
# Reemplaza {id} con un GUID real de tu BD
curl https://localhost:44311/api/Diagnostic/timezone-test/{id}
5. Verificar la Respuesta
Compara:
fromDatabase.valuevsserializedValuefromDatabase.kind- Debería ser "Utc"fromDatabase.toUtcvs valor en BD
🔧 Solución
Opción 1: Corregir ValueConverter (Recomendado)
Archivo: src/SplashPage.EntityFrameworkCore/EntityFrameworkCore/SplashPageDbContext.cs
// Reemplazar líneas 66-69 con:
property.SetValueConverter(new ValueConverter<DateTime, DateTime>(
v => DateTime.SpecifyKind(v, DateTimeKind.Utc), // Al guardar: asegurar que es UTC
v => DateTime.SpecifyKind(v, DateTimeKind.Utc) // Al leer: marcar como UTC (sin conversión)
));
Nota: PostgreSQL con Npgsql ya maneja la conversión correctamente si le indicamos que use UTC.
Opción 2: Configurar Npgsql para usar UTC
Archivo: src/SplashPage.EntityFrameworkCore/EntityFrameworkCore/SplashPageEntityFrameworkModule.cs
Agregar en la configuración de DbContext:
AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", false);
AppContext.SetSwitch("Npgsql.DisableDateTimeInfinityConversions", true);
Opción 3: Remover ValueConverter Completamente
Si PostgreSQL + Npgsql ya están manejando UTC correctamente:
// Comentar o eliminar el ValueConverter
// foreach (var property in entityType.GetProperties())
// {
// if (property.ClrType == typeof(DateTime) || property.ClrType == typeof(DateTime?))
// {
// property.SetValueConverter(...);
// }
// }
🧪 Test Esperado
Después de la corrección:
- BD:
2025-10-15 01:55:00+00(UTC) - API retorna:
2025-10-15T01:55:00Z(UTC) ✅ - Frontend muestra:
14/10/2025, 19:55:00(America/Mexico_City = UTC-6) ✅
📝 Notas Importantes
- Restart requerido: Después de cambiar el ValueConverter, reinicia la aplicación
- Migración NO requerida: Este es solo un cambio de configuración
- Datos existentes: No se requiere actualizar datos en BD
- Compatibilidad: Verifica que otros DateTime fields funcionen correctamente
🚀 Ejecución de Validación
- Ejecutar endpoint de diagnóstico
- Aplicar la corrección elegida
- Reiniciar aplicación
- Re-ejecutar endpoint de diagnóstico
- Verificar que fechas coincidan
- Probar en frontend que fechas se muestren correctamente