Trabajo avanzado con fechas y horas en Kotlin
\n\nEn el desarrollo moderno con Kotlin, el manejo adecuado de fechas y horas no es solo una conveniencia, sino una necesidad. A nivel avanzado, el desarrollador debe lidiar con zonas horarias, períodos, duraciones y operaciones complejas de formato. En este artículo, exploraremos las herramientas y técnicas clave que le ayudarán a escribir código robusto y eficiente.
\n\n1. Clases principales: LocalDate, LocalTime, LocalDateTime e Instant
\n\nKotlin hereda completamente la potente biblioteca java.time (JSR-310), que se ha convertido en el estándar para trabajar con fechas y horas en Java 8 y versiones posteriores. Para Kotlin Multiplatform existe la biblioteca kotlinx-datetime, pero en proyectos JVM, java.time sigue siendo la más popular.
LocalDate, LocalTime, LocalDateTime
\nEstas clases representan fecha y hora sin vincularlas a una zona horaria. Son ideales para almacenar cumpleaños, horarios y otros datos donde la zona horaria no es relevante.
\n\nimport java.time.LocalDate\nimport java.time.LocalTime\nimport java.time.LocalDateTime\n\nfun main() {\n val date = LocalDate.now()\n val time = LocalTime.of(14, 30, 0)\n val dateTime = LocalDateTime.of(date, time)\n \n println("Fecha: $date")\n println("Hora: $time")\n println("Fecha y hora: $dateTime")\n \n // Sumar y restar días\n val tomorrow = date.plusDays(1)\n println("Mañana: $tomorrow")\n}\n\nInstant — marca de tiempo para máquinas
\nInstant representa un punto en la línea de tiempo en UTC. Es indispensable para registro de eventos, intercambio de datos entre servidores y trabajo con APIs.
import java.time.Instant\n\nfun main() {\n val now = Instant.now()\n println("Momento actual en UTC: $now")\n \n // Conversión desde milisegundos\n val fromEpoch = Instant.ofEpochMilli(1_700_000_000_000)\n println("Desde milisegundos: $fromEpoch")\n}\n\n2. Zonas horarias: ZonedDateTime y OffsetDateTime
\n\nCuando una aplicación trabaja con usuarios de diferentes regiones, es necesario considerar las zonas horarias. Para ello existen ZonedDateTime (con información completa de la zona) y OffsetDateTime (solo el desplazamiento respecto a UTC).
import java.time.ZonedDateTime\nimport java.time.ZoneId\nimport java.time.ZoneOffset\n\nfun main() {\n // Hora actual en Nueva York\n val newYork = ZonedDateTime.now(ZoneId.of("America/New_York"))\n println("Nueva York: $newYork")\n \n // Conversión desde UTC\n val utcNow = ZonedDateTime.now(ZoneOffset.UTC)\n val moscowTime = utcNow.withZoneSameInstant(ZoneId.of("Europe/Moscow"))\n println("Moscú: $moscowTime")\n \n // OffsetDateTime para desplazamientos simples\n val offsetTime = java.time.OffsetDateTime.now(ZoneOffset.ofHours(3))\n println("+3 horas: $offsetTime")\n}\n\nImportante: Para la interfaz de usuario, use siempre ZonedDateTime para manejar correctamente el cambio de horario de verano/invierno. OffsetDateTime es adecuado para desplazamientos fijos, por ejemplo, al trabajar con registros.
3. Diferencia entre fechas: Period y Duration
\n\nPara calcular la diferencia de tiempo, Kotlin proporciona dos clases: Period (para fechas, en días/meses/años) y Duration (para intervalos precisos en segundos/nanosegundos).
Period — trabajo con unidades calendario
\nimport java.time.LocalDate\nimport java.time.Period\n\nfun main() {\n val birthDate = LocalDate.of(1990, 5, 15)\n val today = LocalDate.now()\n val age = Period.between(birthDate, today)\n \n println("Edad: ${age.years} años, ${age.months} meses, ${age.days} días")\n \n // Añadir un período a una fecha\n val nextMonth = today.plus(Period.ofMonths(1))\n println("En un mes: $nextMonth")\n}\n\n