module Fecha (Fecha, nuevaFe, diaFe, mesFe, anioFe, sumaFe, diasEntreFe) where data Fecha = Fec Int deriving(Eq, Ord) instance Show Fecha where show f = show (diaFe f) ++ "/" ++ show (mesFe f) ++ "/" ++ show (anioFe f) ----------------------- -- Funciones pedidas -- ----------------------- nuevaFe :: Int -> Int -> Int -> Fecha nuevaFe dia mes anio = Fec (diasDesdeCero dia mes anio) anioFe :: Fecha -> Int anioFe (Fec d) = obtenerElAnio d mesFe :: Fecha -> Int mesFe (Fec d) = obtenerElMes (obtenerDiasSobrantesAnio d) (obtenerElAnio d) diaFe (Fec d) = obtenerDiasSobrantesMes (obtenerDiasSobrantesAnio d) (obtenerElAnio d) sumaFe :: Fecha -> Int -> Fecha sumaFe (Fec f) d = Fec (f+d) diasEntreFe :: Fecha -> Fecha -> Int diasEntreFe (Fec f1) (Fec f2) = f2 - f1 ---------------- -- Auxiliares -- ---------------- -- devuelve el numero de dia desde el 1/1/0001 diasDesdeCero :: Int -> Int -> Int -> Int diasDesdeCero d m a = diasHastaElAnio a + diasHastaElMes m a + d -- devuelve la cantidad de dias hasta el comienzo del anio desde 1/1/0001 diasHastaElAnio :: Int -> Int diasHastaElAnio a | a > 0 = auxDiasHastaElAnio a 1 auxDiasHastaElAnio :: Int -> Int -> Int auxDiasHastaElAnio a c | a == c = 0 | esBisiesto a = 366 + auxDiasHastaElAnio a (c + 1) | otherwise = 365 + auxDiasHastaElAnio a (c + 1) -- devuelve los dias desde el comienzo del anio hasta el mes indicado diasHastaElMes :: Int -> Int -> Int diasHastaElMes m a | m > 0 && a > 0 = auxDiasHastaElMes m a 1 auxDiasHastaElMes :: Int -> Int -> Int -> Int auxDiasHastaElMes m a c | c == m = 0 auxDiasHastaElMes m a c | c < m && esMesDeTreinta c = 30 + auxDiasHastaElMes m a (c + 1) | c < m && esMesDeTreintaYUno c = 31 + auxDiasHastaElMes m a (c + 1) | c < m && m == 2 && esBisiesto a = 29 + auxDiasHastaElMes m a (c + 1) | c == 2 && not (esBisiesto a) = 28 + auxDiasHastaElMes m a (c + 1) esBisiesto a = (a `mod` 4 == 0 && a `mod` 100 /= 0 ) || (a `mod` 400 == 0) -- TODO: se puede usar `elem`? esMesDeTreinta m = m `elem` [4,6,9,11] -- TODO: se puede usar `elem`? esMesDeTreintaYUno m = m `elem` [1,3,5,7,8,10,12] -- devuelve la maxima cantidad posible de anios que se le -- le puede restar a la cantidad de dias indicada obtenerElAnio :: Int -> Int obtenerElAnio d | d > 0 = auxObtenerElAnio d 1 auxObtenerElAnio :: Int -> Int -> Int auxObtenerElAnio d c | d < 366 && esBisiesto c = c | d < 365 = c | not (esBisiesto c) = auxObtenerElAnio (d-365) (c+1) | esBisiesto c = auxObtenerElAnio (d-366) (c+1) -- devuelve el resto en dias despues de restar la mayor -- cantidad posible de anios obtenerDiasSobrantesAnio :: Int -> Int obtenerDiasSobrantesAnio d | d > 0 = auxObtenerDiasSobrantesAnio d 1 auxObtenerDiasSobrantesAnio :: Int -> Int -> Int auxObtenerDiasSobrantesAnio d c | d < 366 && esBisiesto c = d | d < 365 = d | not (esBisiesto c) = auxObtenerDiasSobrantesAnio (d-365) (c+1) | esBisiesto c = auxObtenerDiasSobrantesAnio (d-366) (c+1) -- analogo a obtenerElAnio pero con el numero de dia dentro de un anio obtenerElMes :: Int -> Int -> Int obtenerElMes d a | d > 0 && a > 0 = auxObtenerElMes d a 1 auxObtenerElMes :: Int -> Int -> Int -> Int auxObtenerElMes d a c | d <= 31 && esMesDeTreintaYUno c = c | d <= 30 && esMesDeTreinta c = c | d <= 29 && c == 2 && esBisiesto a = c | d <= 28 && c == 2 && not (esBisiesto a) = c | esMesDeTreintaYUno c = auxObtenerElMes (d - 31) a (c + 1) | esMesDeTreinta c = auxObtenerElMes (d - 30) a (c + 1) | c == 2 && esBisiesto a = auxObtenerElMes (d - 29) a (c + 1) | c == 2 && not (esBisiesto a) = auxObtenerElMes (d - 28) a (c + 1) -- analogo a obtenerDiasSobrantesAnio pero con el numero de dia dentro de un anio obtenerDiasSobrantesMes :: Int -> Int -> Int obtenerDiasSobrantesMes d a | d > 0 && a > 0 = auxObtenerDiasSobrantesMes d a 1 auxObtenerDiasSobrantesMes :: Int -> Int -> Int -> Int auxObtenerDiasSobrantesMes d a c | d <= 31 && esMesDeTreintaYUno c = d | d <= 30 && esMesDeTreinta c = d | d <= 29 && c == 2 && esBisiesto a = d | d <= 28 && c == 2 && not (esBisiesto a) = d | esMesDeTreintaYUno c = auxObtenerDiasSobrantesMes (d - 31) a (c + 1) | esMesDeTreinta c = auxObtenerDiasSobrantesMes (d - 30) a (c + 1) | c == 2 && esBisiesto a = auxObtenerDiasSobrantesMes (d - 29) a (c + 1) | c == 2 && not (esBisiesto a) = auxObtenerDiasSobrantesMes (d - 28) a (c + 1)