Data e ora con il linguaggio C


Le librerie standard del linguaggio C (così come quelle della maggior parte degli altri linguaggi di programmazione) contengono funzioni e tipi di dati che permettono di operare facilmente con le date e le ore. In particolare consentono di effettuare calcoli con date e ore (per es. calcolare il tempo intercorso tra due date) e interrogare l’orologio interno del computer per utilizzare l’ora e la data attuale in un programma.

In questo documento ci occuperemo di come il linguaggio C, e in particolare la versione implementata con il Dev C++, memorizza e tratta una particolare data e ora intesa come un certo istante individuato da giorno, mese e anno più ora minuti e secondi (una data del calendario + ora del giorno).
Data e ora sono espresse con un unico numero intero (4 bytes) che rappresenta, nel caso del Dev C++, il numero di secondi trascorsi dalla mezzanotte del 1/1/1970 secondo il fuso orario del meridiano di Greenwich (ora UTC – tempo coordinato universale). Se la data è antecedente al 1/1/1970 il numero dovrebbe essere negativo ma il Dev C++ non gestisce queste date.

Questo tipo di dati è chiamato time_t che in effetti è solo una ridefinizione con typedef del tipo long int (quindi un altro modo per dire long int). Si tratta di un modo molto compatto per indicare una data e un’ora (data e ora vengono compressi in soli 4 byte).

Con questo sistema la massima data e ora rappresentabile è 19/1/2038 h 03:14:07, a causa del numero massimo che può contenere una variabile intera di 4 byte. Per questo motivo molti sistemi Unix, che utilizzano questo modo per memorizzare il tempo, gestiscono in modo sbagliato le date superiori al 2038 e questo problema è noto come Unix millennium bug.
Per utilizzare le funzioni standard di libreria che trattano questo tipo di dati bisogna includere il file di intestazione time.h che viene incluso automaticamente quando si include <iostream>.

In questo file oltre ai protitipi delle funzioni che andremo ad esaminare troviamo anche la definizione della seguente struct che rappresenta data e ora decompresse:

struct tm

{

int tm_sec; /* Secondi: 0-59 */

int tm_min; /* Minuti: 0-59 */

int tm_hour; /* Ore dalla mezzanotte: 0-23 */

int tm_mday; /* Giorno del mese: 1-31 */

int tm_mon; /* Mese dell’anno: 0-11 (Gennaio = 0, Dic=11*/

int tm_year; /* Anno a partire dal 1900 */

int tm_wday; /* Giorno della settimana da Domenica: 0-6 */

int tm_yday; /* Giorno dell’anno a partire dal 1 gennaio: 0-365 */

int tm_isdst; /* +1 si considera l’ora legale, 0 ora legale ignorata,

};

Vediamo ora le principali funzioni:
time_t time(*time_t) Legge data e ora dell’orologio di sistema

Serve per leggere la data e ora dall’orologio di sistema. Restituisce un valore time_t (un intero). Il parametro normalmente è il puntatore NULL o 0, se invece è un puntatore diverso da NULL allora il risultato viene messo anche nella variabile puntata. Per esempio:

sec=time(0);

Alla variabile sec viene assegnato il numero di secondi trascorsi dalla mezzanotte del 1/1/1970 preso dall’orologio di sistema ovvero la data e ora attuale in forma compressa.
struct tm * localtime (const time_t *time) Espande data e ora in giorno, mese, anno, ore ecc.

Serve per decomprimere una data e ora estraendo giorno, mese, anno, ora, minuti, secondi, giorno della settimana e giorno dell’anno. Il parametro fornito è un puntatore a data e ora compressi, il risultato è un record del tipo tm visto sopra. Questo record si trova in un’area di memoria fissa, utilizzata da tutti gli utenti del computer, che viene sovrascritta ogni volta che si richiama la funzione.

Nella trasformazione vengono considerate le impostazioni locali del sistema operativo e quindi si considera il fuso orario e l’eventuale ora legale impostate in windows. Per esempio:

time_t s; tm *ol; // ol= puntatore a record con data e ora decompressa

s = time(0);

cout <<"Numero di secondi passati dalla mezzanotte del 1/1/1970 = "<< s<<endl;

ol=localtime(&s);

cout << "Ora locale: "<< ol->tm_hour<<':'<<ol->tm_min<<':'<<ol->tm_sec<<endl;
struct tm * localtime_r (const time_t *time, struct tm *resultp) Espande data e ora

Funziona come localtime() salvo che memorizza il risultato nel recrod resultp il cui puntatore viene fornito come parametro invece di memorizzarlo in un’area fissa.
time_t mktime (struct tm *recdataora) comprime data e ora in 4 bytes

Questa funzione fa l’operazione inversa rispetto alla precedente funzione localtime: riceve come parametro un puntatore al record di una data e ora decompressa nel formato tm e calcola e restituisce la stessa data nel formato compresso time_t.

Per effettuare il calcolo non vengono presi in considerazione i campi tm_wday e tm_yday ma solo quelli corrispondenti a anno, mese, giorno, ora, minuti e secondi.

Queste sono solo alcune delle funzioni data e ora presenti nella libreria standard del C (e quindi anche del C++), nel file libc.htm (nella cartella condivisa del server del laboratorio, purtroppo in inglese) trovate il riferimento a tutte quelle implementate nella libreria GNU C.

Differenza tra due date e ora

Per calcolare la differenza tra due date e/o ora basta trasformarle nel formato compresso (eventualmente utilizzando la funzione mktime) e fare la sottrazione tra i due numeri interi corrispondenti. Il risultato sarà il periodo intercorrente espresso in secondi. Se lo vogliamo in giorni basta dividere il risultato per 86400 (numero di secondi corrispondenti ad un giorno).

Aggiungere o sottrarre un certo periodo ad una data ora

Basta aggiungere o sottrarre alla data ora compressa il numero di secondi corrispondenti al periodo da aggiungere o sottrarre, il risultato sarà la nuova data ora compressa.

Il programma che segue legge la data e ora di sistema e la visualizza su video:

#include <iostream>

using namespace std;

int main() {

int ore,min,sec; time_t s; // s = data e ora compressa

tm *ol; // puntatore a record con data e ora decompressa

s = time(0); // legge l'ora di sistema compressa

// decomprime data e ora usando la funzione di libreria localtime

ol=localtime(&s);

cout <<"Numero di secondi passati dalla mezzanotte del 1/1/1970 = "

<< s<<endl;

/* provo a calcolare l'ora attuale partendo da s

1 giorno = 84600 secondi

sec = numero di secondi passati dalla mezzanotte di oggi */

sec =s % 86400;

ore = sec / 3600; sec %=3600; // quante ore

ore +=1; if (ore==24) ore=0; //aggiusta il fuso orario per Roma

min = sec / 60; sec %=60; // quanti minuti

cout << "sono le ore (ora solare) "<<ore<<":"<<min<<":"<<sec<<endl<<endl;
// visualizza la data e ora decompressa con localtime

cout << "Data di oggi = "<<ol->tm_mday<<'/'<<ol->tm_mon+1

<<'/'<<ol->tm_year+1900<< endl;

cout << "Ora locale effettiva: "<< ol->tm_hour<<':'<<ol->tm_min

<<':'<<ol->tm_sec<<endl;

system("Pause");

return EXIT_SUCCESS;

}

Commenti

Post popolari in questo blog

Simulazioni di reti (con Cisco Packet Tracer)

Esercizi sulla rappresentazione della virgola mobile IEEE 754 (Floating Point)