Home > Listati di programmi C > Calcoli con date

CALCOLI CON DATE

Questi programmi gestiscono le date dal 1-1-1583 al 31-12-3000.

Il 1583 e' il primo anno intero in cui si e' applicata la riforma gregoriana; per evitare complicazioni non ho considerato l'epoca del calendario giuliano.

Il limite massimo del 3000 l'ho deciso arbitrariamente, ma penso che possa andare bene per la maggior parte delle applicazioni.

Le date sono rappresentate con stringhe di tipo gg-mm-aaaa.

Invece del trattino si possono usare anche altri caratteri separatori, modificando il valore di SEP nel file date_lib.h.

La funzione ok_formato_data() verifica se la stringa di input puo' essere considerata una data valida nel suddetto formato, ma non entra nel merito sulla correttezza della data.

Quindi approva anche date del tipo 30-02-1981, 10-12-1200, ecc.

Invece censura date tipo 08/03/2019, 11-9-2001, ecc.

ok_data_num() riceve in input una tripla di interi che rappresentano giorno, mese, anno e verifica se la data corrispondente e' ammessa.

La funzione ok_data() verifica la correttezza del formato e della data, usando le due f. precedenti.

La funzione leggi_data() serve per l'input di date da tastiera.

Ho pensato che la rappresentazione di date con stringhe e' piu' comoda rispetto alle rappresentazioni con numeri (o struct di numeri), con riferimento ai casi in cui sia necessario salvare date su file (di testo o di struct con campo data); ok_data() puo' servire anche per riconoscere ed estrarre date da file di testo.

Naturalmente questo implica delle elaborazioni piu' laboriose, rispetto alla gestione diretta in formato numerico.

Le funzioni estrai_giorno(), estrai_mese(), estrai_anno() ricevono in input una stringa-data e rendono in uscita il numero intero corrispondente a giorno, mese, anno. Tutte e tre si avvalgono della funzione copia_char_str(), che permette di copiare una parte della stringa di input in una stringa locale, poi convertita in intero.

data_num_str() riceve in input una tripla di interi e crea la stringa-data corrispondente.

Le funzioni inc_data() e dec_data() ricevono in input una stringa data e rendono in uscita la stringa-data del giorno successivo o precedente.

inc_data_num() e dec_data_num() fanno la stessa cosa, ma operando sulla tripla di numeri giorno, mese, anno.


Ho prestato una particolare attenzione al problema di calcolare il numero di giorni compresi fra due date (incluse).

Questo valore non deve essere confuso con la differenza fra due date.

Esempi:

il periodo 18-03-1993 / 18-03-1993 e' formato da 1 giorno, ma la differenza fra le due date e' 0;

il periodo 18-03-1993 / 19-03-1993 e' formato da 2 giorni, ma la differenza e' 1.

Comunque, usando le mie funzioni e' possibile facilmente calcolare anche la differenza, basta decrementare di 1 il valore di uscita.

Per il calcolo del numero di giorni compresi fra due date (incluse) ho creato tre funzioni, che usano algoritmi diversi.


conta_gg_periodo_1() calcola separatamente il numero di giorni dei seguenti tre periodi:

1) dalla data iniziale al 31 dicembre dello stesso anno; si usa la funzione conta_gg_fine();

2) il periodo intermedio, formato da anni interi; non basta moltiplicare per 365 il numero di anni, ma bisogna tenere conto anche dei bisestili; per fare questo ho creato le funzioni conta_multipli() e conta_bisest(); la prima risolve un problema piu' generale, cioe', dato un intervallo delimitato da due interi a, b (b >= a), rende in uscita il numero dei multipli di n presenti nell'intervallo (con a, b inclusi e con n > 1); la seconda usa la prima per risolvere il problema specifico di sapere quanti bisestili ci sono nel periodo dall'anno xxxx all'anno yyyy.

La regola e' che gli anni multipli di 4 sono bisestili, pero' se sono anche multipli di 100 non sono bisestili, ma se sono anche multipli di 400 tornano a essere bisestili;

3) il periodo dal 1 gennaio (dell'anno di appartenenza della data finale) alla data finale; si usa la funzione conta_gg_inizio().

Sommando il numero di giorni dei tre periodi si ottiene il risultato finale.

Ho tenuto conto dei casi particolari, come date iniziale/finale nello stesso anno o in anni consecutivi (quindi senza periodo intermedio di anni interi).


conta_gg_periodo_2() utilizza le due funzioni data_num() e num_data().

La prima riceve in input una stringa-data e genera un numero ad essa associabile, secondo questa regola: alla data 01-01-1583 corrisponde il numero 1, a 02-01-1583 il numero 2, e cosi' via fino al 31-12-3000 associato a 517914. Cosi' e' possibile instaurare una corrispondenza biunivoca fra date e numeri.

Spiego il funzionamento con un esempio: data di input 07-09-1993; calcola il numero di giorni dall'anno 1583 al 1992, che e' uguale a 149650 (= (1992 - 1583 + 1) * 365), incrementato del numero di bisestili (calcolato con conta_bisest()) cioe' 100.

Si aggiunge il numero di giorni dal 01-01-1993 al 07-09-1993, che e' 250 (calcolato con conta_gg_inizio())). Quindi alla data 07-09-1993 e' associato il numero 150000 (= 149650 + 100 + 250).

La seconda esegue il lavoro inverso, dato un numero rende in uscita la data associata.

Calcola la divisione intera fra 150000 e 366, che e' 409. Somma 1583 e 409, ottenendo 1992; questo anno e' approssimativamente vicino a quello richiesto 1993.

Si chiama la funzione data_num() passando in input la data 01-01-1992 e si ottiene 149385; si calcola la differenza 150000 - 149385, che e' 615; quindi, partendo da 01-01-1992 si incrementa 615 volte la data fermandosi al 07.09.1993, che e' la data cercata.

Per calcolare il numero di giorni di un certo periodo basta convertire in numeri le date di inizio-fine, calcolare la differenza e incrementare di 1.

Ho usato data_num() e num_data() anche per le funzioni che sommano/sottraggono a una data un certo numero di giorni.


conta_gg_periodo_3() procede in questo modo: trova separatamente il numero di giorni del periodo 01-01-1583 / data iniziale e del periodo 01-01-1583 / data finale; calcolando la differenza fra i due valori ottenuti (incrementata di 1) si ottiene il numero di giorni del periodo data iniziale / data finale.

Il meccanismo e' analogo a quello della funzione precedente, pero' i numeri associati ai periodi di anni interi non vengono calcolati, ma si trovano gia' pronti in un'apposita struttura dati.

Prima dell'azionamento di questa funzione bisogna chiamare alloca_gg_anni(), che inserisce in memoria heap le somme cumulative dei giorni, per tutti gli anni dal 1583 al 3000.

alloca_gg_anni ha come argomento un puntatore doppio, che ho chiamato pp_giorni.

conta_gg_periodo_3(), oltre alle date di inizio e fine, ha anche un argomento puntatore semplice (l'ho chiamato p_giorni), che consente di accedere ai dati inseriti in memoria dalla funzione precedente.

Nei programmi che chiamano le due funzioni, ho chiamato p_gg_anni il puntatore passato alle funzioni stesse.

Quindi i dati presenti in p_giorni[] sono i seguenti:

anno 1583, giorni 365;

anno 1584, giorni 731 (= gg anno precedente 365 + giorni dell'anno corrente 366);

anno 1585, giorni 1096 (= giorni anni precedenti 731 + giorni anno corrente 365);

.................................................................................

anno 2998, giorni 517184 (= giorni anni precedenti 516819 + giorni anno corrente 365);

anno 2999, giorni 517549 (= giorni anni precedenti 517184 + giorni anno corrente 365);

anno 3000, giorni 517914 (= giorni anni precedenti 517549 + piu' giorni anno corrente 365).

Con MIN_ANNO = 1583 e MAX_ANNO = 3000, p_giorni[] contiene 1418 interi (= 3000 - 1583 + 1).

Per accedere alla locazione di memoria dell'anno x, si calcola (x - 1583).


Il programma per generare calendari lo sto riscrivendo, non e' ancora pronto.

Pero' ho gia' preparato le funzioni base, per ricavare da una data il nome di mese e giorno della settimana.


Per compilare il programma (con gcc): gcc -o op_date op_date.c date_lib.c


File date_lib.h

File date_lib.c

Operazioni con date

Creazione di un calendario in formato HTML

Calendari 1900-2099


Home


www.corradodamiano.it

posta@corradodamiano.it