• ¿Qué es un lenguaje de programación?
  • Entorno de Desarrollo en macOS
WeiseRatel
  • ¿Qué es Swift?
  • ¿Hablamos?
  • Sobre WeiseRatel.com
No Result
View All Result
  • ¿Qué es Swift?
  • ¿Hablamos?
  • Sobre WeiseRatel.com
No Result
View All Result
WeiseRatel
No Result
View All Result
Home Lenguajes de Programación Swift

Swift – Trabajo con Fechas

Josué V. Herrera by Josué V. Herrera
in Swift
Reading Time: 13 mins read
A A
Trabajo con Fechas, Swift
11
SHARES
36
VIEWS
Compartir en FacebookCompartir en Twitter

En esta ocasión aprenderemos a trabajar con fechas y hora. Veremos como gestionar esas necesidades que usualmente requerimos cuando ejecutamos operaciones sobre unidades de tiempo.

[better-ads type=’banner’ banner=’159′ ]

El trabajo con fechas y hora en Swift se centra principalmente en las siguientes estructuras:

  • Date: Nos permite representar un punto en el tiempo, independientemente del sistema de calendario o de la franja horaria.
  • DateFormatter: Nos permite crear cadenas de texto en representación de una fecha y hora determinado, cadenas que luego podemos convertir a un objeto Date.
  • Calendar: Encapsula los distintos sistemas de control de tiempo (Gregoriano, Persa, Budista…) en los cuales se definen datos como el inicio, la duración y las divisiones del año.
  • DateComponentsFormatter: Toma una cantidad determinada de tiempo y la representa como una cadena de texto legible.
  • DateIntervalFormatter: Toma dos fechas y crea a partir de estas una cadena de texto legible.

Quisiera agregar que la estructura Date también nos permite comparar fechas, calcular el intervalo de tiempo, la creación de una nueva fecha producto de un intervalo de tiempo, entre otras posibilidades.

La estructura Date

Comencemos por lo más básico y usual, veamos como obtener la fecha y hora actual. Esto lo hacemos mediante la estructura Date, de esta manera:

let date = Date()

print(date)

la salida en pantalla sería:

2016-11-14 16:15:11 +0000

Como podemos ver el código es bien simple, una línea de hecho. Ahora, con respecto a la salida en pantalla creo que es evidentemente que será distinta para cada cual que ejecute este código. Lo que sí debemos tener en cuenta es que la hora la estamos obteniendo en UTC / GMT, y esto lo podemos comprobar teniendo en cuenta dos indicios:

  • El primero sería que la hora no es la correcta, en mi caso está adelantada 5 horas.
  • El segundo se encuentra al final de la línea donde se muestra el texto «+0000», esto último ya nos confirma que la fecha y hora nos la está dando en Tiempo Medio de Greenwich (GMT) o como también se le conoce el Tiempo Universal Coordinado (UTC).

Yo ahora me encuentro en Quito / Ecuador y la zona horaria aquí es de -5 o para seguir el formato que nos devuelve Date sería de -0500, esto quiere decir que estoy 5 horas atrás con respecto al UTC / GMT. Es evidente que tenemos un problema con la localización lo cual puede deberse a una mala configuración de alguno de los parámetros que conforman el Locale en sistemas Unix / Linux.

La clase DateFormatter

En mi caso el problema no reside en el Locale del sistema, la estructura Date por defecto nos devuelve la información teniendo en cuenta UTC / GMT.

[better-ads type=’banner’ banner=’160′ ]

Para lograr resultados que cumplan con nuestra zona horaria, que nos muestren el horario en formato de 12 horas, el año primero seguido por el mes y por último el día, todas estás variaciones y otras, las podemos conseguir haciendo uso de DateFormatter.

Veamos el ejemplo anterior en una versión adaptada a nuestras necesidades:

let date = Date()

print(date)

let dateFormatter = DateFormatter()

dateFormatter.dateStyle = .full
dateFormatter.timeStyle = .full

print(dateFormatter.string(from: date))

la salida en pantalla:

2016-11-14 18:35:52 +0000
Monday, November 14, 2016 at 1:35:52 PM Ecuador Time

En esta salida vemos la diferencia tan grande que existe entre estas dos líneas. La primera línea de la salida es la correspondiente al código anterior seguida de otra mucho más amigable y sobre todo con información correcta.

Lo único que hemos hecho es crear una instancia de DateFormatter en la línea 5 para luego establecer que estilo de fecha queremos que nos muestre. Aquí vemos los distintos estilos con los que contamos y su respectiva salida:

EstiloSalida en Pantalla
.fullMonday, November 14, 2016 at 2:43:02 PM Ecuador Time
.longNovember 14, 2016 at 2:43:44 PM GMT-5
.mediumNov 14, 2016, 2:44:29 PM
.short11/14/16, 2:44 PM
.noneNo muestra nada

esta salida en pantalla se logra estableciendo los valores de fecha y hora al mismo estilo.

En la columna de la salida también nos podemos percatar de que los resultados están en Inglés ya que trabajo con mi sistema en este idioma. Si cuando estamos desarrollando una aplicación deseamos que el usuario, sin importar dónde esté, obtenga la información en pantalla acorde a su región, a su zona horaria, su moneda, etc.

¿Pudiéramos lograr esto?

La respuesta es sí, a continuación una variante del código anterior.

let date = Date()

print(date)

let dateFormatter = DateFormatter()

dateFormatter.locale = Locale(identifier: "es_EC")

dateFormatter.dateStyle = .full
dateFormatter.timeStyle = .full

print(dateFormatter.string(from: date))

la nueva salida sería:

2016-11-15 13:59:22 +0000
martes, 15 de noviembre de 2016, 08:59:22 hora de Ecuador

En este ejemplo hemos solamente añadido la línea 7 con la cual establecemos el Locale de la instancia de DateFormatter a es_EC, es decir Español de Ecuador, ya que es_ES que sería Español de España no serviría pues aunque se comparte el mismo idioma la moneda en Europa es el Euro y en Ecuador el dólar estadounidense.

Cambiando el Formato por Defecto

Quizás el formato mostrado por defecto sea muy largo y solamente con poner la fecha y la hora sería más que suficiente para cubrir nuestras necesidades:

dateFormatter.setLocalizedDateFormatFromTemplate("ddMMyy hh:mm:ss")

En esta línea hemos establecido un template por el cual la instancia de DateFormatter se guiará para mostrarnos la fecha y hora. Importante aclarar, aunque lo creo muy evidente, que el template que hemos definido no es texto al azar, para que este sea válido tiene cumplir con el formato de fecha y tiempo establecido en la ISO8601.

La salida en pantalla producida es:

15/11/16 2:26:39 p.m.

Comparar dos Fechas

Como ya he comentado en Swift las fechas se manejan con la estructura Date y esta representa un instante de tiempo, lo cual incluye tanto una fecha como una hora. Así que a la hora de comparar dos fechas tenemos que tener también en cuenta el tiempo, aunque en dependencia de la necesidad, este puede ser desestimado.

[better-ads type=’banner’ banner=’161′ ]

En algunas situaciones el 18 de Noviembre de 2016 es solamente lo que nos interesa, manejamos este dato como un todo sin importarnos de unidades menores como las 24 horas que lo componen.

Pero cuando queremos comparar dos fechas no es lo mismo «18/12/2016 12:15:37» a  «18/12/2016 12:15:38», ambos son momentos distintos en el tiempo, con la diferencia de un segundo pero finalmente distintos aun cuando la fecha es la misma.

Antes de comparar dos fechas necesitamos tenerlas como información, como dato manejable, en nuestro caso como instancias de Date con las cuales podamos trabajar, así que, de paso, veamos como definir un momento en el tiempo distinto al actual:

var firstDateComponents = DateComponents()

firstDateComponents.day = 01
firstDateComponents.month = 01
firstDateComponents.year = 2017

firstDateComponents.timeZone = TimeZone(abbreviation: "UTC")

var firstDate = Calendar(identifier: Calendar.Identifier.gregorian).date(from: firstDateComponents)

print(firstDate!)

la salida en pantalla de nuestra primera fecha sería:

2017-01-01 00:00:00 +0000

Para crear una fecha, para definir un instante en el tiempo, nos hemos apoyado en DateComponents, en cuya instancia encapsulamos los componentes que conforman la primera fecha que deseamos representar.

Luego para obtener una instancia de Date hacemos uso de Calendar, ejecutamos su inicializador al cual le pasamos como parámetro el sistema de calendario que usaremos, al mismo tiempo que ejecutamos el método date de la instancia de Calendar que nos devuelve su inicializador. Este método y específicamente esta sobrecarga nos devuelve una instancia de Date a partir de una instancia de DateComponents.

Dicho esto continuemos con nuestra comparación, añadamos otra fecha con un mes de diferencia con respecto a la primera:

var firstDateComponents = DateComponents()
var secondDateComponents = DateComponents()

firstDateComponents.day = 01
firstDateComponents.month = 01
firstDateComponents.year = 2017

firstDateComponents.timeZone = TimeZone(abbreviation: "UTC")

secondDateComponents.day = 01
secondDateComponents.month = 02
secondDateComponents.year = 2017

secondDateComponents.timeZone = TimeZone(abbreviation: "UTC")

var firstDate = Calendar(identifier: Calendar.Identifier.gregorian).date(from: firstDateComponents)
var secondDate = Calendar(identifier: Calendar.Identifier.gregorian).date(from: secondDateComponents)

print(firstDate!)
print(secondDate!)

if (firstDate?.compare(secondDate!) == .orderedAscending) {
    
    print("firstDate < secondDate")
    
} else if (firstDate?.compare(secondDate!) == .orderedDescending) {
    
    print("firstDate > secondDate")
    
} else if (firstDate?.compare(secondDate!) == .orderedSame) {
    
    print("firstDate = secondDate")
    
} // else if

la salida en pantalla:

firstDate < secondDate

En esta última versión del ejemplo hemos usado el método compare de nuestra instancia Date el cual nos permite comparar dos fechas devolviendo un valor ComparisionResult que nos indica el orden temporal de la fecha establecida en la instancia que ejecuta el método y la fecha pasada como parámetro.

Los valores posibles del enum ComparisionResult son:

ComparisionResultDescripción
.orderedAscendingLa fecha representada por la instancia Date es anterior a la pasada como parámetro.
.orderedDescendingLa fecha representada por la instancia Date es posterior a la pasada como parámetro.
.orderedSame La fecha representada por la instancia Date es igual a la pasada como parámetro.

La ejecución de estos chequeos se realizan de la línea 22 a la 34 en una estructura if / else-if. Con respecto a este segmento del código no creo que esta sea la opción que brinde más legibilidad, pero se usó para mostrar el uso del método compare.

A mi modo de ver, la versión más óptima de este segmento sería la siguiente:

if (firstDate! < secondDate!) {
    
    print("firstDate < secondDate")
    
} else if (firstDate! > secondDate!) {
    
    print("firstDate > secondDate")
    
} else if (firstDate! == secondDate!) {
    
    print("firstDate = secondDate")
    
} // else if

Claramente es un código mucho más limpio gracias a la sobrecarga de operadores y que a simple vista comprendemos la intención que percibe, mientras que en la versión anterior tenemos que comenzar por verificar que valor de retorno tiene el método compare para luego consultar los valores que comprenden al enum ComparisionResult.

Objeto Date a partir de un String

Una caso de estudio que no puede faltar en este artículo es aquel donde necesitamos hacer un parse sobre una cadena de texto que representa una fecha y con esta información crear un objeto Date. Esto es muy sencillo:

var dateString = "23/04/2017"

var dateStringFormatter = DateFormatter()

dateStringFormatter.dateFormat = "dd/MM/yyyy"

var dateFromString = dateStringFormatter.date(from: dateString)

print(dateStringFormatter.string(from: dateFromString!))

la salida en pantalla:

23/04/2017

Lo primero que debemos establecer es la fecha en modo texto para luego crear una instancia de DateFormatter a la cual le especificamos el formato de la fecha para que este sepa como hacer el parse correctamente.

Continuamos pasando como parámetro al método date nuestra fecha en modo texto y de tipo String, esto nos devuelve un objeto Date. En la última línea imprimimos el contenido de la instancia de Date llamada dateFromString a través de DateFormatter para que la salida corresponda al formato especificado en la línea 5.

Formateando Componentes de Fecha y Hora

Como ya comentamos al inicio con DateComponentsFormatter podemos ir un poco más allá de lo que logramos con DateFormatter ya que podemos obtener una representación más literal de una cantidad de tiempo determinada. Veamos:

var someDateComponents = DateComponents()

someDateComponents.day = 23
someDateComponents.month = 04
someDateComponents.year = 2017
someDateComponents.calendar = Calendar(identifier: .gregorian)
someDateComponents.timeZone = TimeZone(abbreviation: "UTC")

var someDateComponentsFormatter = DateComponentsFormatter()

someDateComponentsFormatter.unitsStyle = .full
someDateComponentsFormatter.includesApproximationPhrase = true
someDateComponentsFormatter.includesTimeRemainingPhrase = true
someDateComponentsFormatter.allowedUnits = [.month, .day, .hour]

let futureDate = someDateComponents.date

let remainingTime = someDateComponentsFormatter.string(from: Date(), to: futureDate!)!

var outputDateFormatter = DateFormatter()

outputDateFormatter.dateFormat = "dd/MM/yyyy"

print("From today \(outputDateFormatter.string(from: Date())) to 23/04/2017 there is \(remainingTime)")

la salida en pantalla sería:

From today 21/11/2016 to 23/04/2017 there is About 5 months, 1 day, 1 hour remaining

Lo primero que hemos hecho aquí es algo que ya hemos visto. Creamos una fecha en el futuro (23/04/2017), luego una instancia de DateComponentsFormatter, configuramos el estilo, los segmentos de texto informativo que deseamos sean incluidos y las unidades de tiempo que manejaremos.

Luego convertimos nuestra instancia DateComponent a una de tipo Date en pos de ser usada en la siguiente en la cual es pasada como parámetro a la instancia de DateComponentsFormatter que nos devuelve una cadena de caracteres en representación del segmento de tiempo comprendido entre el momento actual y la fecha que hemos establecido en el futuro. Esta cadena de texto es interpolada en la última línea.

Formateando Intervalos de Tiempo

En ocaciones es necesario, dada una cantidad de tiempo, determinar una fecha futura. Por ejemplo si un cliente aplica por una subscripción mensual conocer la próxima fecha de pago es bastante sencillo, pero si por alguna razón el lapso de tiempo es variable ya la cosa cambia.

Por ejemplo si ahora nos dicen que el tiempo es de 48 días a partir de ahora y luego de 64 días, pues ya no es tan sencillo determinar la fecha en cuestión sin vernos enfrascados en código extra. Para esto nos puede ayudar Date, uno de sus inicializadores y por último DateIntervalFormatter para mostrarnos este segmento que comienza en el momento actual hasta una fecha final que quizás no sepamos cual es:

let intervalFormatter = DateIntervalFormatter()

intervalFormatter.dateStyle = .full
intervalFormatter.timeStyle = .medium

let startDate = Date()

let endDate = Date(timeInterval: 172800, since: startDate)

let intervalFormatterOutputString = intervalFormatter.string(from: startDate, to: endDate)

print(intervalFormatterOutputString)

la salida en pantalla:

Tuesday, November 22, 2016, 2:07:31 AM - Thursday, November 24, 2016, 2:07:31 AM

La anterior explicación más la salida en pantalla, creo que son más que claras en explicar lo que deseábamos lograr en este ejemplo. La línea a destacar sería la 8 donde creamos una fecha final pasando como parámetro la cantidad de segundos en el futuro donde caducaría la actual suscripción de nuestro usuario.

Luego en la línea 10 hacemos uso de una instancia de DateIntervalFormatter en pos de lograr el formato que podemos observar en la salida en pantalla.

Eso es todo amigos, está de más enfatizar la importancia del trabajo con fechas y hora. Es un apartado que siempre debemos de dominar o tener a la mano una referencia como el artículo actual donde hallar respuestas rápidas a las necesidades más comunes.

Falta aún mucho por aprender en nuestro camino a convertirnos en iOS Developer. Suscríbete a nuestra lista de correo y síguenos en nuestras redes sociales. Mantente al tanto de todas nuestras publicaciones.

Espero que todo cuanto se ha dicho aquí, de una forma u otra le haya servido de aprendizaje, de referencia, que haya valido su preciado tiempo.

Este artículo, al igual que el resto, será revisado con cierta frecuencia en pos de mantener un contenido de calidad y actualizado.

¡Cualquier duda o sugerencia, ya sea errores a corregir o ejemplos a añadir, será más que bienvenida, necesaria!

Josué V. Herrera

Josué V. Herrera

Desarrollador Swift / iOS. Llevo en el mundo de la informática más de 15 años, trabajado con varios lenguajes de programación y frameworks como Swift, C++ / Qt, C#, Java, entre otros. También he fungido como administrador de redes, bases de datos y sistemas Linux (algún que otro BSD) desde 2005 hasta la actualidad. Soy “Experto en Administración y Seguridad de Redes” por la Universidad Tecnológica Nacional FRVM de Córdoba, Argentina.

Artículos relacionados

La Sentencia Guard, Swift
Swift

Swift – La Sentencia Guard

Funciones de Órden Superior, Swift
Swift

Swift – Funciones de Órden Superior

¿Cómo iterar sobre tipos de datos propios?, Swift
Swift

Swift – ¿Cómo iterar sobre tipos de datos propios?

Gestión de Archivos, Swift
Swift

Swift – Gestión de Archivos

Load More
0 0 votos
Article Rating
Suscríbete
Login
Notificar de
guest

guest

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.

0 Comments
Inline Feedbacks
Ver todos los comentarios

Suscríbete

Únete!

Únete!

Suscríbete a nuestra lista de correo y mantente actualizado con las nuevas publicaciones.

Se ha suscrito correctamente!

Entradas recientes

  • Estructuras de Datos – Lista Enlazada
  • MariaDB – Comandos Básicos
  • MariaDB – Instalación y Configuración
  • ¿Cómo hacer una instalación limpia de macOS Ventura?
  • Git – Instalación y Configuración

Categorías

  • Bases de Datos (2)
    • MariaDB (2)
  • Estructuras de Datos (3)
  • Gestión de Dependencias (2)
    • Swift Package Manager (2)
  • Git (2)
  • Guías (2)
  • Lenguajes de Programación (27)
    • Swift (27)
  • Sobre WiseRatel.com
  • Política de Privacidad
  • Política de Cookies
  • ¿Hablamos?
Powered by humans!

© 2022 WeiseRatel. All Rights Reserved.

No Result
View All Result
  • ¿Qué es Swift?
  • ¿Hablamos?
  • Sobre WeiseRatel.com

© 2022 WeiseRatel. All Rights Reserved.

wpDiscuz
RECIBE CONTENIDO SIMILAR EN TU CORREO

RECIBE CONTENIDO SIMILAR EN TU CORREO

Suscríbete a nuestra lista de correo y mantente actualizado con las nuevas publicaciones.

Se ha suscrito correctamente!

Cookies Para que este sitio funcione adecuadamente, a veces instalamos en los dispositivos de los usuarios pequeños ficheros de datos, conocidos como cookies. La mayoría de los grandes sitios web también lo hacen.
Aceptar cookies
Leer más
Ajustes de cookies
Configuración de Cookie Box
Configuración de Cookie Box

Ajustes de privacidad

Decida qué cookies desea permitir. Puede cambiar estos ajustes en cualquier momento. Sin embargo, esto puede hacer que algunas funciones dejen de estar disponibles. Para obtener información sobre eliminar las cookies, por favor consulte la función de ayuda de su navegador. MÁS INFORMACIÓN SOBRE LAS COOKIES QUE USAMOS.

Con el deslizador, puede habilitar o deshabilitar los diferentes tipos de cookies:

  • Block all
  • Essential
  • Functionality
  • Analytics
  • Advertising

Este sitio web

  • Esencial: Recordar sus ajustes de permisos de cookies
  • Esencial: Permitir cookies de sesión
  • Esencial: Recopilar la información que introduzca en el formulario de contacto de un boletín informativo y otros formularios en todas las páginas
  • Esencial: Hacer un seguimiento de lo que introduzca en la cesta de la compra
  • Esencial: Verificar que ha iniciado sesión en su cuenta de usuario
  • Esencial: Recordar la versión del idioma seleccionado

Este sitio web no

  • Recordar los datos de inicio de sesión
  • Funcionalidad: Recordar los ajustes de redes sociales
  • Funcionalidad: Recordar el país y la región seleccionados
  • Análisis: Hacer un seguimiento de las páginas visitadas y de la interacción en las mismas
  • Análisis: Hacer un seguimiento de la ubicación y la región según la dirección IP
  • Análisis: Hacer un seguimiento del tiempo pasado en cada página
  • Análisis: Aumentar la calidad de los datos de las funciones estadísticas
  • Publicidad: Adaptar la información y la publicidad a sus intereses según, p.ej., el contenido que ha visitado antes. (Actualmente no usamos segmentación ni cookies de segmentación)
  • Publicidad: Recopilar información personalmente identificable como el nombre y la ubicación

Este sitio web

  • Esencial: Recordar sus ajustes de permisos de cookies
  • Esencial: Permitir cookies de sesión
  • Esencial: Recopilar la información que introduzca en el formulario de contacto de un boletín informativo y otros formularios en todas las páginas
  • Esencial: Hacer un seguimiento de lo que introduzca en la cesta de la compra
  • Esencial: Verificar que ha iniciado sesión en su cuenta de usuario
  • Esencial: Recordar la versión del idioma seleccionado
  • Funcionalidad: Recordar todos los ajustes de redes sociales
  • Funcionalidad: Recordar el país y la región seleccionados

Este sitio web no

  • Análisis: Hacer un seguimiento de las páginas visitadas y de la interacción en las mismas
  • Análisis: Hacer un seguimiento de la ubicación y la región según la dirección IP
  • Análisis: Hacer un seguimiento del tiempo pasado en cada página
  • Análisis: Aumentar la calidad de los datos de las funciones estadísticas
  • Publicidad: Adaptar la información y la publicidad a sus intereses según, p.ej., el contenido que ha visitado antes. (Actualmente no usamos segmentación ni cookies de segmentación)
  • Publicidad: Recopilar información personalmente identificable como el nombre y la ubicación

Este sitio web

  • Esencial: Recordar sus ajustes de permisos de cookies
  • Esencial: Permitir cookies de sesión
  • Esencial: Recopilar la información que introduzca en el formulario de contacto de un boletín informativo y otros formularios en todas las páginas
  • Esencial: Hacer un seguimiento de lo que introduzca en la cesta de la compra
  • Esencial: Verificar que ha iniciado sesión en su cuenta de usuario
  • Esencial: Recordar la versión del idioma seleccionado
  • Funcionalidad: Recordar todos los ajustes de redes sociales
  • Funcionalidad: Recordar el país y la región seleccionados
  • Análisis: Hacer un seguimiento de las páginas visitadas y de la interacción en las mismas
  • Análisis: Hacer un seguimiento de la ubicación y la región según la dirección IP
  • Análisis: Hacer un seguimiento del tiempo pasado en cada página
  • Análisis: Aumentar la calidad de los datos de las funciones estadísticas

Este sitio web no

  • Publicidad: Adaptar la información y la publicidad a sus intereses según, p.ej., el contenido que ha visitado antes. (Actualmente no usamos segmentación ni cookies de segmentación)
  • Publicidad: Recopilar información personalmente identificable como el nombre y la ubicación

Este sitio web

  • Funcionalidad: Recordar los ajustes de redes sociales
  • Funcionalidad: Recordar el país y la región seleccionados
  • Análisis: Hacer un seguimiento de las páginas visitadas y de la interacción en las mismas
  • Análisis: Hacer un seguimiento de la ubicación y la región según la dirección IP
  • Análisis: Hacer un seguimiento del tiempo pasado en cada página
  • Análisis: Aumentar la calidad de los datos de las funciones estadísticas
  • Publicidad: Adaptar la información y la publicidad a sus intereses según, p.ej., el contenido que ha visitado antes. (Actualmente no usamos segmentación ni cookies de segmentación)
  • Publicidad: Recopilar información personalmente identificable como el nombre y la ubicación

Este sitio web no

  • Recordar los datos de inicio de sesión
Guardar cerrar