Gestión de tiempos en Dart con DateTime y Duration
Para trabajar con el tiempo en Dart, necesitas distinguir entre un punto en el tiempo (un instante específico) y un intervalo de tiempo (una cantidad de tiempo). Para el primero usamos la clase DateTime, que representa un momento exacto en una línea temporal, mientras que para el segundo usamos Duration, que es esencialmente un “pedazo” de tiempo (como 5 minutos o 2 días).
Cuando ejecutas DateTime.now(), obtienes el instante actual en la zona horaria de tu máquina. Si necesitas trabajar con estándares de servidores o bases de datos, lo ideal es usar DateTime.now().toUtc(). La lógica interna de esto es que la computadora mide el tiempo como un número gigante de milisegundos transcurridos desde una fecha de referencia llamada Unix Epoch (1 de enero de 1970). DateTime es la abstracción que te permite manipular ese número de forma legible, permitiéndote acceder a propiedades como year, month o day sin hacer cálculos matemáticos manuales.
Usarás Duration cuando necesites sumar o restar tiempo a un instante (por ejemplo, “qué fecha será dentro de 30 días”) o cuando quieras saber cuánto tiempo pasó entre dos eventos mediante el método difference. Si intentas realizar aritmética matemática directamente sobre un DateTime (como fecha + 10), el compilador te dará un error; la forma correcta es usar add(Duration) o subtract(Duration).
Si cometes errores al comparar fechas, como asumir que dos objetos son iguales solo porque caen en el mismo día, podrías romper validaciones críticas de lógica de negocio. Ten en cuenta que DateTime solo entiende de “local” o “UTC”; si necesitas manejar zonas horarias específicas con nombres (como “Europe/Madrid”), deberás usar paquetes externos como timezone.
void main() {
// 1. Obtener el momento exacto actual en UTC
final ahoraUtc = DateTime.now().toUtc();
print('Momento actual (UTC): $ahoraUtc');
// 2. Crear una fecha específica manualmente
// Constructor: año, mes, día, hora, minuto, segundo
final fechaEvento = DateTime.utc(2024, 12, 24, 20, 0, 0);
print('Fecha del evento: $fechaEvento');
// 3. Parsear una fecha desde un String (formato ISO 8601)
final fechaDesdeString = DateTime.parse('2025-01-01T12:00:00Z');
print('Fecha parseada: $fechaDesdeString');
// 4. Usar Duration para definir un intervalo
final tiempoEspera = Duration(days: 7, hours: 3, minutes: 30);
// 5. Aritmética de fechas: Sumar una duración a un DateTime
final fechaVencimiento = fechaEvento.add(tiempoEspera);
print('Vencimiento (evento + espera): $fechaVencimiento');
// 6. Calcular la diferencia entre dos puntos en el tiempo
final diferencia = fechaVencimiento.difference(ahoraUtc);
print('Faltan ${diferencia.inDays} días y ${diferencia.inHours % 24} horas para el vencimiento');
// 7. Comparaciones
if (fechaVencimiento.isAfter(ahoraUtc)) {
print('El evento aún no ha ocurrido.');
}
if (fechaEvento.weekday == DateTime.sunday) {
print('El evento es un domingo.'); // 7 es Domingo
}
// 8. Conversión de zona horaria
print('Evento en mi zona local: ${fechaEvento.toLocal()}');
}
Desglose del ejemplo
Al ejecutar el código, verás cómo ahoraUtc utiliza el método toUtc() para asegurar que el punto de partida sea neutro. Cuando creamos fechaEvento mediante el constructor DateTime.utc(...), estamos definiendo un punto exacto en el tiempo sin depender de la configuración de la máquina donde corra el código.
Fíjate en la variable tiempoEspera. No es una fecha, es una magnitud de tiempo. Al aplicarla con fechaEvento.add(tiempoEspera), el motor de Dart calcula internamente la nueva posición en la línea temporal. El método difference es clave: cuando restamos fechaVencimiento.difference(ahoraUtc), el resultado no es un número, sino otro objeto Duration. Por eso, para mostrar “días” o “horas”, debemos acceder a sus propiedades como inDays o inHours.
Finalmente, nota que fechaEvento.weekday devuelve un entero. En Dart, los días de la semana empiezan en 1 (Lunes) y terminan en 7 (Domingo). Esta es una distinción importante si estás construyendo lógica que dependa de calendarios laborales.
El error frecuente
Un error muy común al comparar fechas para validar “si es el mismo día” es utilizar isAtSameMomentAs(). Este método compara la precisión hasta el microsegundo.
// ERROR COMÚN
final hoy = DateTime.now(); // Digamos que es 2023-10-27 10:00:00.500
final mañana = DateTime(2023, 10, 27, 10, 0, 0); // El mismo día, pero con 500ms de diferencia
if (hoy.isAtSameMomentAs(mañana)) {
// Esto NUNCA se ejecutará, aunque para un humano sean el mismo día
}
Si tu lógica depende de comparar días, años o meses, nunca compares el objeto DateTime completo; compara sus propiedades individuales (year, month, day) o asegúrate de “limpiar” la hora antes de comparar.
N° 113