campo-sirio/include/date.cpp
guy f99c477005 confapp.cpp Migliorata leggibilita' ed indentazione
config.cpp    Sostituiti fexist con TFilename::exist
controls.*    Migliorato supporto per il resizing dei campi
date.*        Promossi da byte a int i parametri di weekday e monthname


git-svn-id: svn://10.65.10.50/trunk@6576 c028cbd2-c16b-5b4b-a496-9718f37d4682
1998-04-30 14:59:01 +00:00

644 lines
14 KiB
C++
Executable File
Raw Blame History

#include <ctype.h>
#include <time.h>
#define __DATE_CPP
#include <date.h>
#ifndef FOXPRO
#include <real.h>
#endif
#include <strings.h>
#define DAYYEAR 365
#define DAYBIAS 36525L
///////////////////////////////////////////////////////////
// Utility functions
///////////////////////////////////////////////////////////
HIDDEN TDate __tmp_date;
HIDDEN char __date_tmp_string[128];
HIDDEN const byte _days_in_month[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
TDate::TDate(const TDate &d) : _val(d._val)
{}
TDate::TDate(long l) : _val(l)
{
if (_val == TODAY)
{
time_t lt;
if (time(&lt) == -1)
return;
struct tm * timeloc = localtime(&lt);
if (timeloc == NULL)
fatal_box("Impossibile reperire la data corrente del sistema.");
_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 = ((y % 4 ) == 0)); 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;
if (len == 8)
{
for (int 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]);
}
}
#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;
switch(month)
{
case 4:
case 6:
case 9:
case 11:
d = 30;
break;
case 2:
d = year % 4 ? 28 : 29;
break;
default:
d = 31;
break;
}
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()
{
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 string();
}
TDate& TDate::operator =(const char* s)
{
return *this = TDate(s);
}
void TDate::print_on(ostream& out) const
{
out << string();
}
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;
}
// @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 <t TDate_mgafmt>), 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 <t TDate_order>; default gma_date)
{
if (!ok() || *this == botime)
return "";
if (yearf == ANSI)
{
yearf = full;
ord = amg_date;
sep='\0';
}
TString df(16), yf(16), mf(16);
bool letterflag = FALSE;
// format day
if (dayf == letters)
{
#ifndef FOXPRO
const real ddd(day());
df = ddd.string("LETTERE");
letterflag = TRUE;
#endif
}
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)
{
#ifndef FOXPRO
const real ddd(year());
yf = ddd.string("LETTERE");
letterflag = TRUE;
#endif
}
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("%do trimestre", (month() / 3) + 1);
}
else
mf.format(monthf == brief ? "%d" : "%02d", month());
if ((letterflag && sep == '-') || sep == 'S')
sep = ' ';
// build date string
TFixed_string dfm(__date_tmp_string, 128);
dfm.cut(0);
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 __date_tmp_string;
}
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
{
const TDate y(1, 1, year());
return (int) ((date2julian()-y.date2julian())/7 )+1;
}
void TDate::addmonth(int nmonth)
{
const int wday = day();
int wyear = year();
int wmonth = month() + nmonth;
while (wmonth > 12)
{
wmonth -= 12;
wyear++;
}
_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;
if (len == 8)
{
for (int 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 <= _days_in_month[m - 1] || (m == 2 && (y % 4 == 0) && d == 29);
}
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
{
__tmp_date = a.julian2date(a.date2julian() + nday);
return __tmp_date;
}
TDate& operator +(const long nday, const TDate& b)
{
__tmp_date = b.julian2date(b.date2julian() + nday);
return __tmp_date;
}
// @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
{
__tmp_date = a.julian2date(a.date2julian() - nday);
return __tmp_date;
}
// @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 <p a> con la data <p b>
void swap(
TDate& a, // @parm Prima data da scambiare
TDate& b) // @parm Seconda data da scambiare
{
__tmp_date = b;
b = a;
a = __tmp_date;
}
// @doc EXTERNAL
// @func Ritorna la data piu' piccola tra <p a> e <p b>
const TDate& fnc_min(
const TDate& a, // @parm Prima data da confrontare
const TDate& b) // @parm Secondo data da confrontare
{
if (a < b) return a;
else return b;
}
// @doc EXTERNAL
// @func Ritorna la data piu' grande tra <p a> e <p b>
const TDate& fnc_max(
const TDate& a, // @parm Prima data da confrontare
const TDate& b) // @parm Secondo data da confrontare
{
if (a > b) return a;
else return 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 <p f> permette di settare un tipo di formattazione
// della data:
// <nl>1<> carattere -<gt> FORMATO. Puo' assumere i seguenti valori:
// <nl> 1 = giorno-mese-anno
// <nl> 2 = mese-anno-giorno
// <nl> 3 = anno-giorno-mese
// <nl> 4 = solo anno
// <nl> 5 = solo mese
// <nl> 6 = solo giorno
// <nl> 7 = mese-anno
// <nl><nl>2<> carattere -<gt> Formato GIORNO. Puo assumere i seguenti valori:
// <nl> 2 = formato normale (es. 4)
// <nl> 4 = formato con 0 (es. 04)
// <nl> 5 = lettere (es. quattro)
// <nl> 6 = giorno della settimana
// <nl><nl>3<> carattere -<gt> Formato MESE. Puo assumere i seguenti valori:
// <nl> 2 = formato normale (es. 4)
// <nl> 4 = formato con 0 (es. 04)
// <nl> 5 = lettere (es. quattro)
// <nl> 7 = trimestre
// <nl><nl>4<> carattere -<gt> Formato ANNO. Puo' assumere i seguenti valori:
// <nl> 2 = breve (es. 95)
// <nl> 4 = lungo (es. 1995)
// <nl><nl>5<> carattere -<gt> Carattere SEPARATORE. Puo' essere un carattere o lo spazio
{
CHECKS(memchr(f, 0, 5) == NULL, "Bad date format ", 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 <p m> e' maggiore di 12 viene calcolato il nome del
// mese corrispondente a tale cifra (es. 15 = "Marzo")
{
CHECKD(m >= 1 && m <= 12, "Bad month ", m);
const char* nomi[12] =
{
"Gennaio", "Febbraio", "Marzo", "Aprile", "Maggio", "Giugno",
"Luglio", "Agosto", "Settembre", "Ottobre", "Novembre", "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.
// <nl>Se il parametro <p d> 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* nomi[7] =
{ "Lunedi", "Martedi", "Mercoledi", "Giovedi", "Venerdi", "Sabato", "Domenica" };
return nomi[(d-1) % 7];
}