Sin embargo, no es raro que nos encontremos con código, (a veces antiguo, a veces no) que trata las fechas "a mano".
Este es un un ejemplo real de una función que ví en una aplicación PHP:
function sumaMes($fecha,$mesesSumar,$formatoDMA=false) { $dia = $this->separaFecha($fecha,"D"); $mes = $this->separaFecha($fecha,"M"); $ano = $this->separaFecha($fecha,"A"); $mesResult = $mes; if (!empty($mes)) { for ($n = $mes; $n<($mes + $mesesSumar); $n++) { if ($n == 12) { $mesResult = 1; $ano++; } else $mesResult++; } } $mes = $this->cerosLeft($mesResult, 2); if ($formatoDMA) $resp = "$dia-$mes-$ano"; else $resp = "$ano-$mes-$dia"; return $resp; }
Esta función está tal y como la encontré. En apariencia, el código parece correcto, y funciona bien hasta que hacemos operaciones como sumar un mes a un 30 de enero, lo que nos devuelve un 30 de febrero.
Este tipo de errores se detectan cuando utilizamos una base de datos y protesta cuando intentamos grabar una fecha no válida.
Si estamos creando un fichero tipo XML o similar, tenemos un problema; tarde o temprano lo descubriremos, o más bien, lo descubrirán los clientes por nosotros.
Esto de despotricar del código de otros es fácil; hay gente a la que le parece divertido.
Sin embargo, cuando heredas un código como éste y te toca mantenerlo, o tienes que hacer un traspaso de datos que ha pasado por este código, créeme, no es divertido.
La función
sumaMes()
lá encontré en una aplicación que utilizaba una versión antigua de MySQL que, sorprendentemente, se tragaba fechas como el 31 de abril. El traspaso de esos datos a PostgreSQL fue toda una aventura.El tratar las fechas como texto, descomponerlas y hacer operaciones, no es lo más adecuado.
Una cosa es analizar y descomponer un texto que representa una fecha, y otra hacer operaciones con la fecha.
Vamos a ver un par de ejemplos de tratamiento de fechas:
- Añadir / restar intervalos
- Cálculo del último día del mes
Añadir / Restar intervalos
Vamos a ver varios ejemplos de cómo añadir 30 días, y restar un año en fechas en PHP, C#, JavaScript y PostgreSQL:PHP
/* Sumar 30 días */ $f = new DateTime(); $f->add(new DateInterval('P30D')); echo $f->format('d-M-Y'); /* Restar 1 año */ $f = new DateTime(); $f->sub(new DateInterval('P1Y')); echo $f->format('d-M-Y');
La clase
DateInterval
es la que nos permite definir el intervalo con el que operamos sobre la fecha actual.
Hay que tener en cuenta que se modifica el objeto original, lo que puede ser una ventaja o un inconveniente.C#
/* Sumar 30 días */ var f= DateTime.Today; var f2 = f.AddDays(30); Console.WriteLine($"Original {f} Nueva: {f2}"); /* Restar 1 año */ var f= DateTime.Today; var f2 =f.AddYears(-1); Console.WriteLine($"Original {f} Nueva: {f2}");
En C#, la clase
Datetime
nos proporciona métodos para operar con la fecha.A diferencia de PHP, estos métodos devuelven un nuevo objeto de tipo
DateTime
, manteniendo el objeto original intacto.JavaScript
/* Sumar 30 días */ var f= new Date(); f.setDate(f.getDate() + 30); console.log(f); /* Restar 1 año */ var f= new Date(); f.setFullYear(f.getFullYear() - 1); console.log(f);
En JavaScript lo que hacemos, es modificar las propiedades del objeto
Date()
.PostgreSQL
-- Sumar 30 días SELECT current_date + 30 SELECT cast(current_date + INTERVAL '1 day' AS date) -- Restar 1 año SELECT cast(current_date - INTERVAL '1 year' AS date)
En PostgreSQL, podemos sumar o restar días directamente con un entero. También podemos utilizar
INTERVAL
Al utilizar
INTERVAL
, nos devuelve un timestamp
. Si lo que queremos es un tipo 'date
', hacemos el casting.
Último día del mes
Esta es una operación muy frecuente.Seguramente que habrás visto código en el que tenemos un array de 12 elementos que contiene los días de los meses; luego selecciona el elemento correspondiente al mes, y si es febrero, se comprueba si el año es bisiesto y devuelve 29 en lugar de 28.
Dependiendo del lenguaje, hay formas más o menos sencillas de calcular el último día del mes.
PHP
echo date('t'); // último día del mes actual /* Ultimo día del mes de una fecha concreta */ $fecha = new DateTime('2016-02-10'); echo $fecha->format('t'); // 29 echo $día;
En PHP es muy sencillo,podemos pasar el parámetro 't' la la función
date()
(utiliza la fecha del sistema), o bien, utilizar el método format()
en un objeto DateTime
.
C#
class Fechas { public static DateTime UltimoDiaMes(DateTime fechaOrigen) { DateTime fecha = new DateTime(fechaOrigen.Year, fechaOrigen.Month, 1); return fecha.AddMonths(1).AddDays(-1); } }
En C#, lo más sencillo es crear un objeto
DateTime
con el primer día del mes; Luego, sumamos un mes (la fecha se "posiciona" en el día 1 del mes siguiente) y restamos un día.
Esta función de ejemplo recibe como parámetro un objeto
DateTime
del que partimos para hacer el cálculo.Si queremos calcular el último día del mes actual llamamos a esta función así:
DateTime fechaUDM = Fechas.UltimoDiaMes(new DateTime());La variable
fechaUDM
es un objeto DateTime
que almacena al último día del mes actual.Si sólo queremos el día, lo extraemos del objeto
DateTime
.
int día = Fechas.UltimoDiaMes(new DateTime()).Day;
JavaScript
var fecha = new Date(); fecha.setMonth(fecha.getMonth() + 1); fecha.setDate(0);
En JavaScript, el método es similar a C#:
Primero, incrementamos el mes, y luego llamamos a setDate() con el valor 0; esto nos sitúa en el último día del mes anterior. Si el valor es -1 pasaríamos al penúltimo día del mes anterior, y así.
PostgreSQL
SELECT cast(date_trunc('month', current_date) + interval '1 month - 1 day' AS date)
En PostgreSQL, la función
date_trunc()
con el parámetro 'month'
devuelve una fecha correspondiente al primer día del mes. En realidad, lo que hace es recortar la fecha al nivel / precisión que indicamos. En este caso, recorta a nivel de mes, con lo que mantiene el año y el mes del segundo parámetro.
Este cálculo lo encontré aquí: PostgreSQL: Date LastDay
Una aclaración: estos ejemplos de código no me los he inventado yo, los podréis encontrar en foros o en la documentación de los distintos lenguajes, más o menos con la misma apariencia.
No hay comentarios:
Publicar un comentario