Cuando se trabaja con fechas en SQL, a veces se necesita calcular el final del mes. Los meses son complicados. Algunos tienen 28 días, otros 30 o 31, y de vez en cuando hay un año bisiesto.
Entonces, dada una fecha, ¿cómo se calcula el número de días que quedan en el mes?
El cálculo es realmente un proceso de dos pasos:
- Determinar la última fecha del mes.
- Calcular la diferencia en días, entre la fecha en cuestión y el paso 1.
Podemos usar la función DATEDIFF para calcular la diferencia en días, pero ¿cómo calcular el último día del mes?
Usando EOMONTH para calcular el fin de mes
En SQL Server 2012 y superior, se puede usar la función EOMONTH para devolver el último día del mes.
Por ejemplo
SELECT EOMONTH('02/04/2016')
Devuelve el 29/02/2016
Como puedes ver la función EOMONTH tiene en cuenta el año bisiesto.
Así que para calcular el número de día desde una fecha hasta el final del mes podrías escribir
SELECT DATEDIFF(d,'02/04/2016', EOMONTH('02/04/2016'))
Que devuelve 25.
Intentemos un ejemplo más completo que calcule los días restantes de un LoanDate para el mes actual del LoanDate:
BEGIN TRANSACTION-- Sample DataCREATE TABLE LoanDate (LoanID INT, LoanDate DATE);INSERT INTO LoanDate Values (1, '1/1/2016');INSERT INTO LoanDate Values (1, '1/15/2016');INSERT INTO LoanDate Values (1, '1/31/2016');INSERT INTO LoanDate Values (1, '2/15/2016');INSERT INTO LoanDate Values (1, '3/15/2016');INSERT INTO LoanDate Values (1, '4/15/2016');INSERT INTO LoanDate Values (1, '5/15/2016');INSERT INTO LoanDate Values (1, '6/15/2016');INSERT INTO LoanDate Values (1, '7/15/2016');INSERT INTO LoanDate Values (1, '8/15/2016');INSERT INTO LoanDate Values (1, '9/15/2016');INSERT INTO LoanDate Values (1, '10/15/2016');INSERT INTO LoanDate Values (1, '11/15/2016');INSERT INTO LoanDate Values (1, '12/15/2016');-- Select LoanDate, Days in Month, and Days Remaining in MonthSELECT LoanID, LoanDate, EOMONTH(LoanDate) LoanDateEndOfMonth, DATEDIFF(d, LoanDate, EOMONTH(LoanDate)) as DaysRemainingFROM LoanDateROLLBACK
Aquí está el resultado:
Como puede ver, el DaysRemaining cambia según el mes. Además, observe que cuando la fecha se produce en la misma fecha que el final del mes, como la fila 3, cero días permanecen.
Ahora vamos a ver cómo usted iría sobre el cálculo de esto si usted está usando SQL 2008 R2 o antes.
Método de la vieja escuela para calcular el último día del mes
El cálculo es realmente el mismo proceso de dos pasos:
- Determinar la última fecha del mes
- Calcular la diferencia en días, entre la fecha en cuestión y el paso 1.
Sin embargo, la diferencia está en cómo determinamos la última fecha del mes. Como EOMONTH no está disponible, tenemos que calcularlo a la «vieja usanza». Hay varios métodos para hacerlo. Aquí hay uno.
Calcularemos el último día del mes utilizando dos funciones: DATEADD y DAY.
Usaremos DATEADD para añadir un mes a la fecha. Luego la función DAY para determinar el número de días desde el comienzo del mes. Restando esto a la fecha que acabamos de calcular (la que va un mes por delante), podemos obtener la última fecha del mes.
Ok, sé que suena confuso, así que vamos a desglosarlo usando este diagrama:
Usando el mismo ejemplo que hicimos con EOMONTH tenemos la siguiente sentencia que podemos usar para probar:
BEGIN TRANSACTION-- Sample DataCREATE TABLE LoanDate (LoanID INT, LoanDate DATE);INSERT INTO LoanDate Values (1, '1/1/2016');INSERT INTO LoanDate Values (1, '1/15/2016');INSERT INTO LoanDate Values (1, '1/31/2016');INSERT INTO LoanDate Values (1, '2/15/2016');INSERT INTO LoanDate Values (1, '3/15/2016');INSERT INTO LoanDate Values (1, '4/15/2016');INSERT INTO LoanDate Values (1, '5/15/2016');INSERT INTO LoanDate Values (1, '6/15/2016');INSERT INTO LoanDate Values (1, '7/15/2016');INSERT INTO LoanDate Values (1, '8/15/2016');INSERT INTO LoanDate Values (1, '9/15/2016');INSERT INTO LoanDate Values (1, '10/15/2016');INSERT INTO LoanDate Values (1, '11/15/2016');INSERT INTO LoanDate Values (1, '12/15/2016');-- Select LoanDate, Days in Month, and Days Remaining in MonthSELECT LoanID, LoanDate, DATEADD(dd,-(DAY(DATEADD(mm,1,LoanDate))), DATEADD(mm,1,LoanDate)) LoanDateEndOfMonth, DATEDIFF(d,LoanDate, DATEADD(dd,-(DAY(DATEADD(mm,1,LoanDate))), DATEADD(mm,1,LoanDate))) as DaysRemainingFROM LoanDateROLLBACK
Aquí están los resultados:
Entonces, ¿qué método deberías usar?
Si estoy escribiendo código y sé que se ejecutará en SQLServer 2012 o superior, me iría por el método EOMONTH ya que es mucho más fácil de leer; sin embargo, creo que conocer y entender el método usando DATEADD y DAY ayudan a entender mejor cómo manipular fechas.