next up previous contents index
Next: Gestione minimale dei files Up: Approfondimenti. I files d'intestazione Previous: Tipi primitivi   Indice   Indice analitico

Gestione data e ora locali

In questa sottosezione impareremo a gestire la data e l'ora locali della nostra macchina. La libreria utilizzata è time.h. La prima funzione che presentiamo è la seguente:
time_t time (time_t* risultato)
da noi già utilizzata per generare numeri casuali; come si vede il valore di ritorno di time è time_t, un tipo a noi sconosciuto. In realtà non si tratta altro che del sinonimo di un tipo primitivo (spesso long int), il quale assume un significato diverso a seconda del compilatore e della macchina sulla quale esso funziona. L'unico argomento accettato dalla funzione è un puntatore a time_t: se esso è non nullo allora il valore di ritorno della funzione viene assegnato anche a risultato. Se, per qualche motivo indipendente dalla nostra volontà, non sono disponibili data e ora locali viene tornato il codice di errore -1. Il valore del ritorno di time corrisponde di solito al numero di secondi trascorsi dalla mezzanotte del 1 gennaio 1970, secondo il Coordinated Universal Time; vediamo il seguente esempio:

// ex8_5_1
#include <iostream.h>
#include <time.h>
void main() {
  time_t risultato;
  time_t ora = time (0);
  time (&risultato);
  if ( ora != (time_t)(-1) )
    cout << ora << "\n" << risultato << "\n";
  cout << "spazio occupato da time_t: " << sizeof(time_t);
}

esempio di output:
951300989
951300989
spazio occupato da time_t: 4

Prima osservazione: il numero di bytes occupato da una variabile time_t è lo stesso occupato dal un long int; una domanda che è lecito porsi è la seguente: cosa succederà quanto il numero di secondi trascorsi dal 1/1/1970 non potrà più essere contenuto in un long int? Un numero intero con segno sappiamo essere uguale massimo a $2^{31}$, dunque passati circa 2 miliardi di secondi (più di 68 anni) dal 1/1/1970 ci troveremmo in un bel problema, del tutto simile al celebrerrimo Y2K bug. Tuttavia l'eventualità che nel 2038 si usino ancora macchine che memorizzano numeri interi su 32 bit è irrealizzabile; si tenga presente che già memorizzando gli interi su ``solo'' 64 bit potremmo stare tranquilli per 73'117'802'169 anni, ben più dell'età dell'universo. Seconda osservazione: abbiamo a disposizione due metodi per acquisire l'ora locale, come vediamo nell'esempio ex8_5_1.cpp; il primo consiste nell'utilizzare il valore di ritorno di time, il secondo nel passare per indirizzo una variabile alla stessa funzione; il risultato, come ovvio, è lo stesso.

Possiamo dunque avere a nostra disposizione il numero di secondi trascorsi dalla mezzanotte del 1/1/1970; tale informazione tuttavia ci è ben poco utile: in teoria siamo costretti tutte le volte che vogliamo trovare l'ora locale a effettuare complicati calcoli per ricavarla. Ciò non è in pratica necessario perché esiste una funzione di libreria che effettua questo lavoro per noi:

struct tm* localtime (const time_t* t)
Tale funzione converte una variabile di tipo time_t, presumibilmente ricavata tramite time, in un puntatore alla struttura tm; tale struct è definita all'interno della libreria time.h e contiene i seguenti campi8.5:

 int tm_sec secondi
 int tm_min minuti
 int tm_hour ore (0-23)
 int tm_mday giorno del mese (1-31)
 int tm_mon mese dell'anno (0-11)
 int tm_year anno dopo il 1900
 int tm_wday giorno della settimana da Domenica (0-6)
 int tm_yday giorno dell'anno dal 1 Gennaio (0-365)
 int tm_isdst ora legale

L'unica nota riguarda il campo tm_isdst, il quale controlla l'ora legale: se il valore restituito è positivo allora l'ora legale è in vigore, se esso è nullo non lo è, se infine il valore è negativo allora non è disponibile nessuna informazione sull'ora legale. Vediamo un semplice esempio:


// ex8_5_2
#include <iostream.h>
#include <time.h>

void main() {
  time_t ora_corrente;
  tm* ora_locale;

  ora_corrente = time(0);
  ora_locale = localtime (&ora_corrente);

  char giorno_settimana[11];
  char ora_legale[40];
  switch (ora_locale->tm_wday) {
  case 0: strcpy (giorno_settimana, "Domenica"); break;
  case 1: strcpy (giorno_settimana, "Lunedi`"); break;
  case 2: strcpy (giorno_settimana, "Martedi`"); break;
  case 3: strcpy (giorno_settimana, "Mercoledi`"); break;
  case 4: strcpy (giorno_settimana, "Giovedi`"); break;
  case 5: strcpy (giorno_settimana, "Venerdi`"); break;
  case 6: strcpy (giorno_settimana, "Sabato"); break;
  }

  if (ora_locale->tm_isdst > 0)
    strcpy (ora_legale, "ora legale in vigore");
  else if (ora_locale->tm_isdst == 0)
    strcpy (ora_legale, "ora legale NON in vigore");
  else
    strcpy (ora_legale, "nessuna informazione sull'ora legale");

  cout << "sono le ore " << ora_locale->tm_hour <<
    ":" << ora_locale->tm_min <<
    "," << ora_locale->tm_sec <<
    "\ndel giorno " << giorno_settimana <<
    "," << ora_locale->tm_mday <<
    "/" << ora_locale->tm_mon <<
    "/" << ora_locale->tm_year + 1900 <<
    "\n" << ora_legale << "\n";
}

esempio di output:
sono le ore 12:2,33
del giorno Mercoledi`,23/1/2000
ora legale NON in vigore

I passaggi da effettuare se si vuole avere a disposizione ora e data locali sono i seguenti: dichiarare una variabile time_t nella quale memorizzare il numero di secondi trascorsi dalla mezzanotte del 1/1/1970, tramite la funzione time; dichiarare una variabile di tipo puntatore a struttura tm nella quale memorizzare le informazioni dettagliate su data e ora tramite la funzione localtime; sfruttare gli appropriati campi della struttura tm.

Vediamo ancora due funzioni che risultano spesso utili:

time_t mktime (struct tm* t)
char* ctime (const time_t* t)
La prima effettua l'operazione inversa di localtime: converte una struttura tm, passata per indirizzo, in una variabile time_t. La nota più interessante riguarda il fatto che, nella conversione, i campi mancanti vengono completati. Ad esempio se noi vogliamo sapere il giorno della settimana di una certa data, basta creare una struttura tm, convertirla in time_t tramite la funzione mktime e riconvertirla tramite localtime; vediamo un esempio:

// ex8_5_3
#include <iostream.h>
#include <time.h>
void main() {
  tm* ora_corrente = new tm;
  cout << "giorno del mese? "; cin >> ora_corrente->tm_mday;
  cout << "mese dell'anno? ";  cin >> ora_corrente->tm_mon;
  cout << "anno (4 cifre)? ";  cin >> ora_corrente->tm_year;
  ora_corrente->tm_mon -= 1;
  ora_corrente->tm_year -= 1900;
  time_t t = mktime (ora_corrente);
  ora_corrente = localtime (&t);
  cout << "il giorno della settimana e`: " << ora_corrente->tm_wday;
}

esempio di output:
giorno del mese? 1
mese dell'anno? 1
anno (4 cifre)? 2000
il giorno della settimana e`: 6

Si noti che abbiamo dovuto togliere una unità dal campo tm_mon, perché di solito noi indichiamo i mesi da 1 a 12 piuttosto che da 0 a 11, e abbiamo dovuto sottrarre al campo tm_year 1900, perché l'anno viene memorizzato a partire proprio da 1900 nella struttura tm. Nel caso la funzione mktime fallisca la conversione, essa torna il codice di errore -1.

La funzione ctime converte un puntatore costante a time_t in una stringa contenente le principali informazioni su data e ora; vediamo un esempio8.6


// ex8_5_4
#include <iostream.h>
#include <time.h>
void main() {
  time_t ora= time(0);
  cout << ctime(&ora);
}

esempio di output:
Wed Feb 23 12:24:03 2000

Nella libreria GNU, conforme alle specifiche ANSI C Standard, i simboli utilizzati per i giorni della settimana sono, a partire dal Domenica, i seguenti: `Sun', `Mon', `Tue', `Wed', `Thu', `Fri', `Sat'; per i quanto riguarda i mesi abbiamo: `Jan', `Feb', `Mar', `Apr', `May', `Jun', `Jul', `Aug', `Sep', `Oct', `Nov', `Dec'.

ex-2
si scriva un programma che stampi la data corrente: giorno della settimana, giorno del mese, nome del mese, anno a 2 cifre;
ex-3
si scriva una funzione che accetti una variabile time_t (per indirizzo) e le sommi esattamente un giorno solare; si verifichi il funzionamento con la ctime;


next up previous contents index
Next: Gestione minimale dei files Up: Approfondimenti. I files d'intestazione Previous: Tipi primitivi   Indice   Indice analitico
Claudio Cicconetti
2000-09-06