RE:COMO OBTENER NUMERO DE AÑOS ENTRE DOS FECHAS
Te paso unas funciones hechas en C (podés compilar con gcc o con borland C) que permiten procesamiento de fechas. Las había hecho para el motor firebird pero se pueden acceder desde powerbuilder vía EXTERNAL FUNCTION.
Como recibe ciertos argumentos particulares de Firebird, pudes cambias las estructuras por las normales de Fecha / Hora / Timestamp (debería recibir una estructura de tipo estructura tm en lugar de ISC_DATE o ISC_TIMESTAMP). Esto lo cambiás fácilmente. Fíjate particularmente en el método F_DATEDIFF
También te paso links de un algoritmo llamado RATADIE, que sirve para cálculos de fechas. Solución fácil y elegante para este tipo de problemas.
Espero que te ayude.
/********************************************************
FUNCIONES DE FECHA / HORA
******************************************************/
/* Replace "datetime.h" with the name of your header */
#include <time.h>
#include <ib_util.h>
#include <ibase.h>
#include <windows.h>
#include "datetime.h"
#include <string.h>
/***********************************************
F_DATEPART
***********************************************/
DLLIMPORT int *f_datepart(ISC_DATE *adt_date,const char *as_datepart)
{
struct tm ldt_date;
int li_result = -1;
isc_decode_sql_date(adt_date,&ldt_date);
//año
if (!strcmp(as_datepart,"yy"))
{
li_result = ldt_date.tm_year + 1900; //pq retorna la cantidad de años desde 1900
return (int *) li_result;
}
//mes
if (!strcmp(as_datepart,"mm"))
{
li_result = ldt_date.tm_mon + 1; //pq retorna de 0 a 11 meses desde enero
return (int *) li_result;
}
//dia real
if (!strcmp(as_datepart,"md"))
{
li_result = ldt_date.tm_mday;
return (int *) li_result;
}
//día de la semana
if (!strcmp(as_datepart,"dw"))
{
li_result = ldt_date.tm_wday;
return (int *) li_result;
}
//día del año
if (!strcmp(as_datepart,"dy"))
{
li_result = ldt_date.tm_yday;
return (int *) li_result;
}
return (int *) li_result;
};
/***********************************************
F_DATETIMEPART
************************************************/
DLLIMPORT int *f_datetimepart(ISC_TIMESTAMP *adt_datetime,const char *as_datepart)
{
struct tm ldt_datetime;
int li_result = -1;
isc_decode_timestamp(adt_datetime,&ldt_datetime);
//año
if (!strcmp(as_datepart,"yy"))
{
li_result = ldt_datetime.tm_year + 1900; //pq retorna la cantidad de años desde 1900
return (int *) li_result;
}
//mes
if (!strcmp(as_datepart,"mm"))
{
li_result = ldt_datetime.tm_mon + 1; //pq retorna de 0 a 11 meses desde enero
return (int *) li_result;
}
//dia real
if (!strcmp(as_datepart,"md"))
{
li_result = ldt_datetime.tm_mday;
return (int *) li_result;
}
//día de la semana
if (!strcmp(as_datepart,"dw"))
{
li_result = ldt_datetime.tm_wday;
return (int *) li_result;
}
//día del año
if (!strcmp(as_datepart,"dy"))
{
li_result = ldt_datetime.tm_yday;
return (int *) li_result;
}
//hora
if (!strcmp(as_datepart,"hh"))
{
li_result = ldt_datetime.tm_hour;
return (int *) li_result;
}
//minuto
if (!strcmp(as_datepart,"mi"))
{
li_result = ldt_datetime.tm_min;
return (int *) li_result;
}
//segundo
if (!strcmp(as_datepart,"ss"))
{
li_result = ldt_datetime.tm_sec;
return (int *) li_result;
}
return (int *) li_result;
};
/***********************************************
F_LEAPYEAR
************************************************/
DLLIMPORT int *f_leapyear(int *ai_year)
{
int li_return;
if (*ai_year % 4 != 0)
li_return = 0;
else if ((*ai_year % 100 == 0) && (!(*ai_year % 400 == 0)))
li_return = 0;
else
li_return = 1;
return (int *) li_return;
};
/***********************************************
F_MONTHDAYCOUNT
************************************************/
DLLIMPORT int *f_monthdaycount(int *ai_year, int *ai_month)
{
int li_leap;
int li_return;
li_leap = (int)f_leapyear(ai_year);
switch (*ai_month)
{
case 1: li_return = 31; break;
case 2: { li_return = (li_leap == 1 ? 29 : 28); break; }
case 3: li_return = 31; break;
case 4: li_return = 30; break;
case 5: li_return = 31; break;
case 6: li_return = 30; break;
case 7: li_return = 31; break;
case 8: li_return = 31; break;
case 9: li_return = 30; break;
case 10: li_return = 31; break;
case 11: li_return = 30; break;
case 12: li_return = 31; break;
default: li_return = -1;
}
return (int *) li_return;
};
/***********************************************
F_DATEDIFF
************************************************/
DLLIMPORT int *f_datediff(ISC_DATE *ad_date1,
ISC_DATE *ad_date2,
const char *as_datepart)
{
struct tm ld_date1;
struct tm ld_date2;
long ll_result;
int li_monthdaycount;
int *li_tempyear;
int *li_tempmonth;
//contenedores de resultados
int li_resultday;
int li_resultmonth;
int li_monthoffset = 0;
int li_resultyear;
int li_resulterror = -1;
if (!ad_date1)
{
return (int *) li_resulterror;
};
if (!ad_date2)
{
return (int *) li_resulterror;
};
isc_decode_sql_date(ad_date1,&ld_date1);
isc_decode_sql_date(ad_date2,&ld_date2);
/*calcular el día
If %DAY(DATE2) <= %DAY(DATE1) ;
then %DAY(RESULT) = %DAY(DATE1) - %DAY(DATE2).
If %DAY(DATE2) > %DAY(DATE1) ;
then %DAY(RESULT) = N + %DAY(DATE1) - %DAY(DATE2) ;
where N = the last day of %MONTH(DATE2). ;
%MONTH(DATE2) is then incremented by 1.*/
if (ld_date2.tm_mday <= ld_date1.tm_mday)
{
li_resultday = ld_date1.tm_mday - ld_date2.tm_mday;
}
if (ld_date2.tm_mday > ld_date1.tm_mday)
{
li_tempyear = &ld_date2.tm_year;
li_tempmonth = &ld_date2.tm_mon;
li_monthdaycount = *f_monthdaycount(li_tempyear,li_tempmonth);
li_resultday = li_monthdaycount + ld_date1.tm_mday - ld_date2.tm_mday;
// ld_date2.tm_mon += 1;
}
/*calcular el mes
If %MONTH(DATE2) <= %MONTH(DATE1) ;
then %MONTH(RESULT) = %MONTH(DATE1) - %MONTH(DATE2).
If %MONTH(DATE2) > %MONTH(DATE1) ;
then %MONTH(RESULT) = 12 + %MONTH(DATE1) - %MONTH(DATE2). ;
%YEAR(DATE2) is then incremented by 1.
*/
if (ld_date2.tm_mon <= ld_date1.tm_mon)
{
li_resultmonth = ld_date1.tm_mon - ld_date2.tm_mon;
}
if (ld_date2.tm_mon > ld_date2.tm_mon)
{
li_resultmonth = 12 + ld_date1.tm_mon - ld_date2.tm_mon;
ld_date2.tm_year += 1;
}
/*calcular el año
%YEAR(RESULT) = %YEAR(DATE1) - %YEAR(DATE2).
*/
li_resultyear = ld_date1.tm_year - ld_date2.tm_year;
//ver que parte retornar
if (!strcmp(as_datepart,"d"))
{
return (int *) li_resultday;
}
if (!strcmp(as_datepart,"m"))
{
return (int *) li_resultmonth;
}
if (!strcmp(as_datepart,"a"))
{
return (int *) li_resultyear;
}
return (int *) li_resulterror;
};
/***********************************************
F_DATETIMEDIFF
************************************************/
/*DLLIMPORT int *f_datediff(ISC_TIMESTAMP *adt_datetime1,
ISC_TIMESTAMP *adt_datetime2,
const char *as_datepart)
{
struct tm ldt_datetime1;
struct tm ldt_datetime2;
long ll_result;
int li_resultday;
int li_monthdaycount;
int *li_tempyear;
int *li_tempmonth;
isc_decode_timestamp(adt_datetime1,&ldt_datetime1);
isc_decode_timestamp(adt_datetime2,&ldt_datetime2);
if (ldt_datetime2.tm_mday <= ldt_datetime1.tm_mday)
{
li_resultday = ldt_datetime1.tm_mday - ldt_datetime2.tm_mday;
}
if (ldt_datetime2.tm_mday > ldt_datetime1.tm_mday)
{
li_tempyear = (int *) ldt_datetime2.tm_year;
li_tempmonth = (int *) ldt_datetime2.tm_mon;
li_monthdaycount = (int) f_monthdaycount(li_tempyear,li_tempmonth);
li_resultday = li_monthdaycount + ldt_datetime1.tm_mday - ldt_datetime2.tm_mday;
}
return (int *) li_resultday;
}; */
BOOL APIENTRY DllMain (HINSTANCE hInst /* Library instance handle. */ ,
DWORD reason /* Reason this function is being called. */ ,
LPVOID reserved /* Not used. */ )
{
switch (reason)
{
case DLL_PROCESS_ATTACH:
break;
case DLL_PROCESS_DETACH:
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
}
/* Returns TRUE on success, FALSE on failure */
return TRUE;
}
/*************************************************************
PÁGINAS CON ALGORITMO RATADIE
Y ALGUNOS COMENTARIOS
************************************************************/
http://www.capecod.net/~pbaum/date/date0.htm
http://www.capecod.net/~pbaum/date/rata.htm