#include #include #include #define __DATE_CPP #include #include #include #include #define DAYYEAR 365 #define DAYBIAS 36525L static const byte _days_in_month[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; inline bool is_leap(int year) { return (year % 4) == 0; } /////////////////////////////////////////////////////////// // Utility functions /////////////////////////////////////////////////////////// TDate::TDate(const TDate &d) : _val(d._val) {} TDate::TDate(long l) : _val(l) { if (_val == TODAY) { _val = NULLDATE; time_t lt; if (time(<) != -1) { struct tm * timeloc = localtime(<); if (timeloc != NULL) _val = makedata(timeloc->tm_mday, timeloc->tm_mon+1, timeloc->tm_year + 1900); } } else { if (_val == 0) _val = NULLDATE; else { if (_val < 1000000L) { long wd = _val; int cnt = 1900; if (wd > DAYBIAS) { wd -= DAYBIAS; cnt += 100; } else while (wd < 0) { cnt -= 100; wd += DAYBIAS; } int m, y, leap; for(y = 0; wd > DAYYEAR + (leap = is_leap(y)); y++) wd -= (DAYYEAR + leap); for(m = 0; wd > (_days_in_month[m] + (leap && (m == 1))); m++) wd -= (_days_in_month[m] + (leap && (m == 1))); _val = makedata((int) wd, m+1, y+cnt); } } } } TDate::TDate(const char* s) { _val = NULLDATE; const int len = (s && *s) ? strlen(s) : 0; if (len != 8 && len != 10) return; int d = 0, m = 0, y = 0, i; if (len == 8) { for (i = 0; i < 8; i++) if (!isdigit(s[i])) break; if (i == 8) { TString8 str(s); d = atoi(((const char *)str)+6); str.cut(6); m = atoi(((const char *)str)+4); str.cut(4); y = atoi(((const char *)str)+0); } } else if (len == 10) { if (s[2] == s[5] && !isdigit(s[2])) { d = atoi(s); m = atoi(&s[3]); y = atoi(&s[6]); } } #ifdef DBG if (d < 1 || d > 31 || m < 1 || m > 12 || y < 0) yesnofatal_box("Lamentati con Guy se la data %s non viene accettata!", s); #endif _val = makedata(d, m, y); } TDate::TDate(int day, int month, int year) { if (day >= 1 && day <= 31 && month >= 1 && month <= 12 && year > 0) _val = makedata(day, month, year); else _val = NULLDATE; } int TDate::last_day(int month, int year) // parse_filastrok( // "trenta giorni ha novembre // con april, giugno e settembre // son ventotto case uno // per default ce n'ha trentuno"); { int d = _days_in_month[month-1]; if (month == 2 && is_leap(year)) d++; return d; } void TDate::set_end_month() { _val = makedata(last_day(month(),year()),month(),year()); } bool TDate::is_end_month() { return day() == last_day(month(),year()); } bool TDate::empty() const { return _val == 0; } int TDate::wday() const { // day of week (1=lunedi) // DDJ algorithm (4/1995) Della serie: "non e' colpa mia se funziona". int m = month(); int d = day(); int y = year(); if (m <= 2) // Gennaio e Febbraio sono gli ultimi mesi dell'anno scorso { y --; m += 12; } return ((d + 2*m + 3*(m+1)/5 + y + y/4 - y/100 + y/400) % 7) + 1; // Pure magic } void TDate::set_day(int n) { CHECK(n > 0 && n < 32, "TDate::set_day: giorno insensato"); _val = makedata(n, month(), year()); } void TDate::set_month(int n) { CHECK(n > 0 && n < 13, "TDate::set_month: mese impossibile"); _val = makedata(day(), n, year()); } void TDate::set_year(int n) { _val = makedata(day(), month(), n); } TDate::operator const char*() const { return stringa(); } TDate& TDate::operator =(const char* s) { return *this = TDate(s); } TDate& TDate::operator =(long val) { if (val < 0L) // TODAY *this = TDate(val); else _val = val; return *this; } void TDate::print_on(ostream& out) const { out << stringa(); } void TDate::read_from(istream& in) { char s[256]; in >> s; TDate d(s); _val = d._val; } TObject* TDate::dup() const { TDate * d = new TDate(*this); return d; } const char* TDate::stringa() const { if (_val <= 0) return ""; TString& dfm = get_tmp_string(10); dfm.format("%02d-%02d-%04d", day(), month(), year()); return dfm; } // @doc EXTERNAL // @mfunc Ritorna la data in formato di stringa (anche in formato ANSI) // // @rdesc Se si tratta di una data valida ritorna la stringa secondo il // formato scelto (vedi ), altrimenti ritorna "" char* TDate::string( TDate_mgafmt yearf, // @parm Formato per l'anno (default def) char sep, // @parm Carattere separatore (default '-') TDate_mgafmt dayf, // @parm Formato per il giorno (default def) TDate_mgafmt monthf, // @parm Formato per il mese (default def) TDate_order ord) const // @parm Ordine con la quale visualizzare la data // (vedi ; default gma_date) { if (!ok() || *this == botime) return ""; TString& dfm = get_tmp_string(80); if (yearf == ANSI) { dfm.format("%08ld", _val); return dfm.get_buffer(); } TString80 df, yf, mf; bool letterflag = false; // format day if (dayf == letters) { const real ddd(day()); df = ddd.string("LETTERE"); letterflag = true; } else if (dayf == weekday) { df.format("%s %d", itow(wday()), day()); letterflag = true; } else df.format(dayf == brief ? "%d" : "%02d", day()); // format year if (yearf == letters) { const real ddd(year()); yf = ddd.string("LETTERE"); letterflag = true; } else if (yearf == brief) yf.format("%02d", year() % 100); else yf.format("%04d", year()); // format month if (monthf == letters) { letterflag = true; mf = itom(month()); } else if (monthf == quarter) { if (ord < m_date) ord = ma_date; mf.format("%s %d", TR("trimestre"), (month()/3)+1); } else mf.format(monthf == brief ? "%d" : "%02d", month()); if ((letterflag && sep == '-') || sep == 'S') sep = ' '; // build date string switch (ord) { case mga_date: dfm << mf << sep << df << sep << yf; break; case amg_date: dfm << yf << sep << mf << sep << df; break; case a_date: dfm << yf; break; case m_date: dfm << mf; break; case g_date: dfm << df; break; case ma_date: dfm << mf << sep << yf; break; default: dfm << df << sep << mf << sep << yf; break; } return dfm.get_buffer(); } long TDate::date2julian() const { const int d = day(), m = month(), y = year(); return (long)(d - 32076) + 1461L * (y + 4800L + (m - 14) / 12) / 4 + 367 * ( m - 2 - (m - 14) / 12 * 12) / 12 - 3 * ((y + 4900L + (m - 14) / 12) / 100) / 4 + 1; } long TDate::julian2date(long julian) const { long x, z, m, d, y; const long daysPer400Years = 146097L; const long fudgedDaysPer4000Years = 1460970L + 31; x = julian + 68569L; z = 4 * x / daysPer400Years; x = x - (daysPer400Years * z + 3) / 4; y = 4000 * (x + 1) / fudgedDaysPer4000Years; x = x - 1461 * y / 4 + 31; m = 80 * x / 2447; d = x - 2447 * m / 80; x = m / 11; m = m + 2 - 12 * x; y = 100 * (z - 49) + y + x; return makedata((int) d, (int) m, (int) y); } int TDate::day() const { return int(_val % 100L); } int TDate::month() const { return int((_val % 10000L) / 100L); } int TDate::year() const { return int(_val / 10000L); } int TDate::week() const { TDate y(1, 1, year()); const int w = y.wday(); if (w > 1) y -= w-1; return int((*this - y) / 7 + 1); } void TDate::set_easter(int n) { if (n > 0) set_year(n); const int y = year(); const int g = y % 19; const int c = y / 200; const int h = (c - c / 4 - (8 * c + 13) / 25 + 19 * g+ 15) % 30; const int i = h - (h / 28) * (1 - (29 / (h + 1)) * ((21 - g) / 11)); const int j = (y + y / 4 + i + 2 - c + c / 4) % 7; const int l = i - j; const int m = 3 + (l + 40) / 44; set_month(m); const int d = l + 28 - 31 * (m / 4); set_day(d); } bool TDate::is_holiday() const { if (wday() > 5) // Week-end return true; const int d = day(); const int m = month(); if ((m == 1) && ((d == 1) || (d == 6))) // Capodanno ed Epifania return true; if ((m == 4) && (d == 25)) // Liberazione return true; if ((m == 5) && (d == 1)) // Festa dei Lavoratori return true; if ((m == 6) && (d == 2)) // Festa della Repubblica return true; if ((m == 8) && (d == 15)) // Ferragosto return true; if ((m == 11) && (d == 1)) // Ognissanti return true; if ((m == 12) && ((d == 8) || (d == 25) || (d == 26))) return true; if (m == 3 || m == 4 && wday() == 1) { TDate angelo; angelo.set_easter(year()); ++angelo; if (angelo == *this) return true; } return false; } TDate& TDate::operator +=(long nday) { const long d = day() + nday; if (d > 0 && d < 29) _val += nday; else _val = julian2date(date2julian() + nday); return *this; } void TDate::get_week_year(int &weekd, int &yeard, bool complete) { weekd = week(); yeard = year(); const int wday = TDate(1,1,yeard).wday(); if (complete) { if (wday != 1) weekd --; if (weekd <= 0) { weekd = 52; yeard --; } } else { if (weekd > 52) { weekd = 1; yeard ++; } } } void TDate::addmonth(int nmonth) { int wday = day(); int wyear = year(); int wmonth = month() + nmonth; while (wmonth > 12) { wmonth -= 12; wyear++; } while (wmonth <= 0) { wmonth += 12; wyear--; } const int last = last_day(wmonth, wyear); if (wday > last) wday = last; _val = makedata(wday, wmonth, wyear); } void TDate::addyear(int nyear) { const int wday = day(); const int wmonth = month(); const int wyear = year() + nyear; _val = makedata(wday, wmonth, wyear); } bool TDate::isdate(const char* s) { const int len = strlen(s); if (len != 8 && len != 10) return false; int d = 0, m = 0, y = 0, i; if (len == 8) { for (i = 0; i < 8; i++) if (!isdigit(s[i])) break; if (i == 8) { TString16 str(s); d = atoi(((const char *)str)+6); str.cut(6); m = atoi(((const char *)str)+4); str.cut(4); y = atoi(((const char *)str)+0); } } else if (len == 10) { if (s[2] == s[5] && !isdigit(s[2])) { d = atoi(s); m = atoi(&s[3]); y = atoi(&s[6]); } } if (d < 1 || d > 31 || m < 1 || m > 12 || y < 0) return false; return d <= last_day(m,y); } bool TDate::ok() const { return _val > 0; } // @doc EXTERNAL // @func TDate& | operator + | Incrementa la data di un certo numero di giorni TDate operator +( const TDate& a, // @parm Data a cui aggiungere i giorni long nday) // @parm Numero di giorni da aggiungere // @syntax operator + (const TDate& a, long nday) // @syntax operator + (long nday, const TDate& a) // // @comm E' indifferente quale parametro viene passato per primo { TDate tmp(a); tmp += nday; return tmp; } TDate operator +(const long nday, const TDate& b) { TDate tmp(b); tmp += nday; return tmp; } // @doc EXTERNAL // @func TDate& | operator - | Decrementa la data di un certo numero di giorni TDate operator -( const TDate& a, // @parm Data da decrementare long nday) // @parm Numero di giorni da togliere { TDate tmp(a); tmp += -nday; return tmp; } // @doc EXTERNAL // @func TDate& | operator - | Calcola la differenza tra due date long operator -( const TDate& a, // @parm Data da decrementare const TDate& b) // @parm Data da sottrarre { const long diff = a.date2julian() - b.date2julian(); return diff; } // @doc EXTERNAL // @func Scambia la data

con la data

void swap( TDate& a, // @parm Prima data da scambiare TDate& b) // @parm Seconda data da scambiare { const TDate tmp = b; b = a; a = tmp; } // @doc EXTERNAL // @func Ritorna la data piu' piccola tra

e

const TDate& fnc_min( const TDate& a, // @parm Prima data da confrontare const TDate& b) // @parm Secondo data da confrontare { return (a < b) ? a : b; } // @doc EXTERNAL // @func Ritorna la data piu' grande tra

e

const TDate& fnc_max( const TDate& a, // @parm Prima data da confrontare const TDate& b) // @parm Secondo data da confrontare { return (a > b) ? a : b; } /////////////////////////////////////////////////////////// // TFormatted_date /////////////////////////////////////////////////////////// TFormatted_date::TFormatted_date(int day, int month, int year, const char* form) : TDate(day, month, year) { set_format(form); } TFormatted_date::TFormatted_date(const TDate& d, const char* form) : TDate(d) { set_format(form); } TFormatted_date::TFormatted_date(const TFormatted_date& d) : TDate(d) { set_format(d._format); } // @doc EXTERNAL // @mfunc Permette di stabilire il criterio di formattazione delle date void TFormatted_date::set_format( const char* f) // @parm Stringa di 5 caratteri che indica il formato della data // @comm Ogni carattere del parametro

permette di settare un tipo di formattazione // della data: // 1° carattere - FORMATO. Puo' assumere i seguenti valori: // 1 = giorno-mese-anno // 2 = mese-anno-giorno // 3 = anno-giorno-mese // 4 = solo anno // 5 = solo mese // 6 = solo giorno // 7 = mese-anno // 2° carattere - Formato GIORNO. Puo assumere i seguenti valori: // 2 = formato normale (es. 4) // 4 = formato con 0 (es. 04) // 5 = lettere (es. quattro) // 6 = giorno della settimana // 3° carattere - Formato MESE. Puo assumere i seguenti valori: // 2 = formato normale (es. 4) // 4 = formato con 0 (es. 04) // 5 = lettere (es. quattro) // 7 = trimestre // 4° carattere - Formato ANNO. Puo' assumere i seguenti valori: // 2 = breve (es. 95) // 4 = lungo (es. 1995) // 5° carattere - Carattere SEPARATORE. Puo' essere un carattere o lo spazio o essere omesso (sep= char nullo) { CHECKS(memchr(f, 0, 4) == NULL, "Bad date format (you must define all the first 4 chars) :", f); memcpy(_format, f, 5); } const char* TFormatted_date::string() const { TDate_mgafmt yearf = (TDate_mgafmt)(_format[3] - '0'); char sep = _format[4]; TDate_mgafmt dayf = (TDate_mgafmt)(_format[1] - '0'); TDate_mgafmt monthf = (TDate_mgafmt)(_format[2] - '0'); TDate_order ord = (TDate_order)(_format[0] - '0'); return TDate::string(yearf, sep, dayf, monthf, ord); } /////////////////////////////////////////////////////////// // Utility functions /////////////////////////////////////////////////////////// // @doc EXTERNAL // @func Converte un numero da 1 a 12 nel corrispondente mese const char* itom( int m) // @parm Numero del mese da convertire in parole (da 1 a 12) // @comm Se il parametro

e' maggiore di 12 viene calcolato il nome del // mese corrispondente a tale cifra (es. 15 = "Marzo") { CHECK(m>=1, "Il mese indicato deve essere un numero da 1 a 12 "); const char* const nomi[12] = { TR("Gennaio"), TR("Febbraio"), TR("Marzo"), TR("Aprile"), TR("Maggio"), TR("Giugno"), TR("Luglio"), TR("Agosto"), TR("Settembre"), TR("Ottobre"), TR("Novembre"), TR("Dicembre") }; return nomi[(m-1) % 12]; } // @doc EXTERNAL // @func Ritorna il nome del giorno (1-7) const char* itow( int d) // @parm Numero del giorna da convertire in parole (da 1 a 7) // @comm Come primo giorno della setimana e' preso il Lunedi. // Se il parametro

e' maggiore di 7 viene calcolato il nome del // giorno corrispondente a tale cifra (es. 15 = "Lunedi") { CHECKD(d >= 1 && d <= 7, "Bad week day ", d); const char* const nomi[7] = { TR("Lunedì"), TR("Martedì"), TR("Mercoledì"), TR("Giovedì"), TR("Venerdì"), TR("Sabato"), TR("Domenica") }; return nomi[(d-1) % 7]; }