Ejemplo de Fecha con Punteros
Lo primero que vamos a hacer es crear una estructura Fecha y como mencionamos antes, las estructuras deben pasarse siempre como direcciones de memoria por que las mismas ocupan demasiado espacio y al pasarla como direcciones de memoria solo ocupan 4 bytes. Pero esto no es absoluto ya que varía dependiendo de la situación, de modo que, si mi estructura está comprendida por uno o dos caracteres únicamente ocupa 2 bytes de memoria, y sería incluso conveniente pasar la estructura completa en lugar del puntero.
typedef struct { int d; int m; int a; } Fecha;
Una vez realizado esto en funciones .h voy a ir al main para definirlo y voy a crear dos funciones.
#include "funciones.h" int main() { Fecha fInicio; ingresarFecha(&fInicio); mostrarFecha(&fInicio); return 0; }
Como se puede ver, envío como dirección de memoria para que ocupen menos espacio y asi pasar un solo parámetro y no 3.
Luego en funciones.c voy a crear estas funciones.
#include "funciones.h" void ingresarFecha(Fecha *f) { puts("Ingrese fecha ( D/M/A):"); scanf("%d / %d / %d", &f->d, &f->m, &f->a); } void mostrarFecha(Fecha *f) { printf("%d / %d / %d", f->d, f->m, f->a); }
Lo primero que vemos en este código es que uso el comando puts. El comando puts no va imprimir valores de ninguna variable. La función puts
solo puede imprimir cadenas de caracteres y siempre añadirá un salto de línea al final. Si se desea imprimir otros tipos de datos o controlar el formato de salida con más detalle, se debe usar la función printf
.
Lo segundo que se puede ver en la función ingresarFecha es que recibimos la fecha como puntero y cuando la usamos deberiamos escribir : (*f).d pero para simplificar esto voy a hacer f->d .
En la función mostrarFecha podríamos haberle agregado la cantidad de dígitos que queremos que muestre de la siguiente forma:
printf("%02d / %02d / %04d", f->d, f->m, f->a);
Una vez que tengo esto, yo podría hacer que mi función ingresarFecha, valide si es una fecha Valida. Para esto, voy a hacer lo siguiente:
void ingresarFecha(Fecha *f) { puts("Ingrese fecha ( D/M/A):"); scanf("%d / %d / %d", &f->d, &f->m, &f->a); while(!esFechaValida(f)) { puts("Ingrese fecha valida( D/M/A):"); scanf("%d / %d / %d", &f->d, &f->m, &f->a); } }
Si yo pusiera en la función esFechaValida *f, estaria mandando una copia de una estructura. En este caso no me cambiaria en nada porque solo voy a validar y devolver si es válida o no, pero se aconseja mandar la dirección por ende el asterisco no lo ponemos y asi mandamos una copia del puntero. Otra cosa a tener en cuenta es que cuando escribo delante de una función la palabra es por lo general voy a devolver un bool.
Para validar una fecha tengo que tener en cuenta que se va a utilizar el calendario gregoriano que es el calendario utilizado en gran parte del mundo hoy en día. Fue introducido por el Papa Gregorio XIII en 1582 como una reforma del calendario juliano, con el objetivo de corregir la discrepancia acumulada entre el año solar y el año calendario. Las principales características del calendario gregoriano son:
- Año Bisiesto: Año bisiesto es aquel que tiene un día extra, el 29 de febrero. Sin embargo, no todos los años divisibles por 4 son bisiestos en el calendario gregoriano. Los años que son divisibles por 100 pero no por 400 no son bisiestos. Por ejemplo, el año 1900 no fue bisiesto, pero el año 2000 sí lo fue.
- Año de 365 Días: La mayoría de los años tienen 365 días.
- Meses: El calendario gregoriano tiene 12 meses, la mayoría con 30 o 31 días, excepto febrero que tiene 28 días en años normales y 29 días en años bisiestos.
- Alineación con el Año Solar: Aunque el calendario gregoriano es más preciso que su predecesor juliano, todavía existe una ligera discrepancia entre el año calendario y el año solar. Esta discrepancia es de aproximadamente 0.002% por año y puede acumularse con el tiempo.
- El calendario gregoriano se utiliza ampliamente en la mayoría de los países para cuestiones civiles, comerciales y religiosas. Sin embargo, algunas culturas y religiones todavía utilizan calendarios diferentes basados en otros sistemas. Por ejemplo, el calendario hebreo y el calendario islámico tienen sus propias reglas y estructuras.
bool esFechaValida( const Fecha *f) { if( f->a >= 1601) // Calendario Gregoriano if(f->m >= 1 && f->m <= 12) if(f->d>=1 && f->d <= cantDiasMes(f->m, f-> a)) return true; return false; }
Una vez tenido en cuenta el año, los meses y los dias, voy a tener que crear una función para la cantidad de Dias del Mes dependiendo el año y el mes, por este motivo envio ambos valores por parametros.
int cantDiasMes( int m, int a) { int dm[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31}; if( m==2 && esBisiesto(a)) return 29; return dm[m]; }
En esta función, voy a crear un vector de 13 elementos, donde el elemento 0 no lo voy a usar y los restantes los voy a usar para completar con la cantidad de dias que tiene cada mes. En el caso de febrero voy a colocar 28 y si el año es Bisiesto, voy a devolver 29.
Finalmente para la función esBisiesto, debe devolver un bool y debe verificar lo siguiente:
Un año bisiesto es aquel que es divisible entre 4, excepto en casos excepcionales. Para determinar si un año es bisiesto:
- Si el año es divisible entre 4, continúa al paso 2. Si no es divisible entre 4, entonces no es un año bisiesto.
- Si el año es divisible entre 100, continúa al paso 3. Si no es divisible entre 100, entonces es un año bisiesto.
- Si el año es divisible entre 400, entonces es un año bisiesto. Si no es divisible entre 400, no es un año bisiesto.
RECORDAR QUE EL TIPO DE DATO BOOL NO ES UN TIPO DE DATO DE C , POR ENDE SE DEBE AGREGAR LA LIBRERIA:
#include <stdbool.h>
Finalmente la función esBisiesto quedaría:
bool esBisiesto(int a) { return (a %4 ==0 && a%100!=0) || a%400==0); }
Para verificar esto:
- 2000 es divisible entre 4, 100 y 400, por lo que es un año bisiesto.
- 1900 es divisible entre 4 y 100, pero no entre 400, por lo que no es un año bisiesto.
- 2024 es divisible entre 4 y no es divisible entre 100, por lo que es un año bisiesto.
Ahora, si yo quisiera sumar dias a una fecha, por ejemplo:
al 15/08/2023 le quiero sumar 90 dias. Me daria: 105/08/2023. Como me paso de 31 dias que tiene agosto, le resto estos 31 y le sumo uno al mes. Esto me daria 74 / 09 / 2023, como septiembre tiene 30 dias, se los resto y me daría 44 / 10 / 2023 y como octubre tiene 31, lo vuelvo a restar y finalmente me daria 13/11/2023.
Entonces, voy a crear una función que sume una cantidad de dias y una fecha que voy a recibir por parámetro y voy a devolver una fecha nueva. Para esto voy a hacer:
Fecha sumarDiasaFecha ( const Fecha *f, int dias) { int cdm; Fecha fSuma = *f; fSuma.d += dias; while ( fSuma.d > (cdm = cantDiasMes(fSuma.m, fSuma.a))) { fSuma.d -= cdm; fSuma.m +=1; if ( fSuma.m > 12) { fSuma.a+=1; fSuma.m= 1; } } return fSuma; }
Como se puede ver, cree una variable donde voy a guardar la cantidad de dias del mes que se llama cdm, luego cree otra estructura del tipo Fecha, donde por copia le asigno la fecha que recibo por parametro ( esto se puede hacer solo si son del mismo tipo ) y finalmente hago un while usando la función «cantDiasMes» y restando los dias del mes y sumando a los meses.
Tarea:
- Comparar 2 fechas : int compararFecha( const tFecha * , const tFecha *);
- Hacer la diferencia entre 2 fechas.
- Restar dias a una fecha.
- Determinar la cantidad de dias desde una fecha hasta otra fecha, que será negativa si la primera es mayor que la segunda.
- Calcular la edad de una persona.
- Decir el Dia de la semana. Devuelve un entero con el día de la semana.
Restar dias.
Fecha restarDias(const Fecha *f,const int dias) { int cmd; Fecha fResta=*f; fResta.d-=dias; while(fResta.d<0) { cmd=cantDiasMes(fResta.m,fResta.a); fResta.d+=cmd; fResta.m-=1; if(fResta.m<1) { fResta.a-=1; fResta.m=12; } } return fResta; }