Esercizio: Calcolo della data a partire dal numero di giorno dell'anno
Esercizio
Vogliamo realizzare una funzione in linguaggio C che prenda in ingresso due valori:
- un numero indicante l'anno;
- un numero che indica il numero di giorni trascorsi a partire dal 1° gennaio di quell'anno.
Questa funzione deve restituire il mese e il giorno del mese corrispondenti.
Ad esempio, prendendo in ingresso i valori anno = 2023
e giorni = 156
restituisca in uscita i valori mese = 6
(ossia giugno) e giorno = 5
.
Implementazione
Come si evince dal testo dell'esercizio, la funzione da implementare deve prendere in ingresso due valori e restituire due valori in uscita. Motivo per cui dobbiamo utilizzare i puntatori come argomento della funzione.
La possibile firma della funzione può essere la seguente:
void calcola_data(unsigned int anno,
unsigned int giorno_dell_anno,
unsigned int *mese,
unsigned int *giorno);
Per prima cosa dobbiamo notare che i mesi dell'anno non hanno durata uguale. Alcuni mesi sono di 30 giorni, altri di 31 mentre febbraio è di 28.
Per poter gestire queste differenze possiamo utilizzare un array che contiene il numero di giorni corrispondenti al mese:
void calcola_data(unsigned int anno,
unsigned int giorno_dell_anno,
unsigned int *mese,
unsigned int *giorno) {
unsigned int giorni_mese[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
/* ... */
}
L'array giorni_mese
contiene i giorni del mese a seconda dell'indice corrispondente. Per cui 0
equivale a gennaio e quindi il valore corrispondente sarà 31
. Analogamente febbraio corrisponderà all'indice 1
, per cui alla locazione con indice 1
è memorizzato 28
, e così via.
Il secondo passaggio consiste nel verificare se l'anno passato come parametro sia bisestile o meno. Nel caso in cui sia bisestile dobbiamo cambiare il valore corrispondente al numero di giorni di febbraio.
Un anno è bisestile quando:
- Non è un anno secolare (ossia non è divisibile per 100) ed è divisibile per 4;
- Oppure è un anno secolare divisibile per 400.
Per cui:
void calcola_data(unsigned int anno,
unsigned int giorno_dell_anno,
unsigned int *mese,
unsigned int *giorno) {
unsigned int giorni_mese[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
/* Verifica se l'anno è bisestile o meno */
if (anno % 4 == 0 && anno % 100 != 0 || anno % 400 == 0) {
/* Nel caso di anno bisestile aggiunge un giorno a febbraio */
giorni_mese[1] = 29;
}
/* ... */
}
Il passo successivo consiste nel realizzare un ciclo for
che scorre i mesi e sottrae il numero di giorni corrispondenti al valore di giorno_dell_anno
. Il ciclo termina quando il numero di giorni rimanenti è inferiore al numero di giorni del mese successivo. In tal caso l'indice del ciclo for
rappresenta il mese calcolato.
Per cui aggiungiamo una variabile i
di supporto per il ciclo e scriviamo la funzione in questo modo:
void calcola_data(unsigned int anno,
unsigned int giorno_dell_anno,
unsigned int *mese,
unsigned int *giorno) {
unsigned int giorni_mese[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
/* Verifica se l'anno è bisestile o meno */
if (anno % 4 == 0 && anno % 100 != 0 || anno % 400 == 0) {
/* Nel caso di anno bisestile aggiunge un giorno a febbraio */
giorni_mese[1] = 29;
}
/*
* Scorre l'array giorni_mese e decrementa giorno_dell_anno
* fino a quando non si arriva al mese corrispondente,
* cioè quando giorno_dell_anno è minore o uguale al numero
* di giorni del mese corrente
*/
for (i = 0; giorno_dell_anno > giorni_mese[i]; i++) {
giorno_dell_anno -= giorni_mese[i];
}
*mese = i + 1;
*giorno = giorno_dell_anno;
}
Programma completo
Proviamo adesso a scrivere il programma completo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
|
Se proviamo a compilare e eseguire il programma otteniamo:
Inserisci l'anno: 2019
Inserisci il giorno dell'anno: 365
Il giorno 365 dell'anno 2019 corrisponde al 31/12/2019
Provando ad eseguire con dati diversi otteniamo:
Inserisci l'anno: 2023
Inserisci il giorno dell'anno: 156
Il giorno 156 dell'anno 2023 corrisponde al 5/6/2023