viernes, 24 de mayo de 2013

Programando en Borland C++ 5.02 (Cap.III)

Hola de nuevo, amigos del Blog.
 
En la pasada entrega dijimos que este capítulo estaría dedicado a la simulación de botones en modo texto pero esto va ligado al uso del ratón y otras funciones más complejas por lo que lo dejaremos para más adelante.
 
En esta entrega hablaremos del tratamiento de fechas y horas.
 
Es habitual que en los programas informáticos se necesite la gestión de estos datos. Suele ser bastante tedioso, por eso, para facilitar esta labor crearemos unas funciones que nos ayuden en su tratamiento y gestión.
 
Veremos cómo dar formato a las fechas de manera que se visualicen con distintas plantillas. Ej.: "27 de abril de 2013" o "27-Abr-2013" o "27/04/13", etc.
 
Usaremos la Fecha Juliana o Día Juliano y veremos su utilidad a la hora de almacenar la información o realizar cálculos con fechas.

También veremos el COMPUTUS o cálculo de la fecha de Pascua.
 
La fecha juliana es el número de días y fracción transcurridos desde el mediodía del 1º de enero del año 4713 a. C. Así la fecha juliana es una cuenta continua de días y fracciones contados desde un punto inicial fijo.
 
Como ejemplo, para el 15 de mayo de 2013, a las 11:31 TU, la fecha juliana es 2456427.9798611. La parte entera (2456427) corresponde al día desde el mediodía pasado hasta el próximo mediodía y los decimales indican la fracción de día transcurrida desde el último mediodía (de forma que 0,5 sería la medianoche).
 
La fecha Juliana 2451545.0 corresponde al día 1 de enero de 2000, mediodía TT. (Tiempo Terrestre)
 
Los días julianos también sirven para indicar la hora, expresándose esta como una fracción de un día entero, siendo las 12 del mediodía el punto cero. Así, las tres de la tarde del 1 de enero de 1970 es DJ 2440588,125 (ya que las tres de la tarde son tres horas después de mediodía, y 3/24 = 0,125 días). El día juliano viene siempre determinado por el tiempo universal y no por el local.
 
Para información más completa sobre la Fecha Juliana, referíos a Google.
 
La Pascua, festividad principal de la Semana Santa, tiene su origen en el judaísmo. Lla pascua judía, Pésaj, celebra la salida del pueblo judío de Egipto, que tenía lugar el día 14 de Nisán, el primer mes del calendario judío. El calendario judío, como muchos otros, era un calendario lunar y el año comenzaba con el equinoccio de primavera, por lo que el día 14 de Nisán se correspondía con la primera luna llena después del equinoccio de primavera.
 
El cristianismo, mantuvo esta celebración en sus órigenes, pero ya el papa Sixto I, en torno al año 120, movió esta celebración para que tuviera lugar el primer domingo después de Pésaj, estableciendo de este modo una diferencia. Así mismo, este día pasaría a celebrar la resurrección de Jesucristo en vez de la liberación del pueblo judío.
 
Esta decisión no tuvo carácter oficial hasta que en el año 314 en el Concilio de Arlés se declaró como obligatoria la celebración de la Pascua el mismo día en toda la cristiandad, siendo ese día elegido por el Papa de Roma. Once años más tarde, en el Concilio de Nicea del 325, se establecieron las primeras normas de cálculo de la Pascua, que debido a las discrepancias entre la Iglesia de Roma y la Iglesia de Alejandría, fueron reformadas en el 525 por Dionisio el Exiguo, consiguiendo por primera vez un consenso global, que se ha extendido hasta el día de hoy en todo occidente.
 
Las reglas de cálculo son:
1) La Pascua cae en domingo.
2) El domingo elegido es el primer domingo después de la primera luna llena de la primavera boreal. En caso de que esta fecha fuese domingo, la Pascua se trasladaría al domingo siguiente para no coincidir con Pésaj.
3) La primavera comienza con el equinoccio de primavera, que tiene lugar el 21 de Marzo.
 
Computus, es el cálculo de la fecha de Pascua.
 
Una vez más, para profundizar en la información, navegad por vuestros buscadores favoritos.
 
Y ahora, al código.
 
Para hacer uso de estas funciones debéis referenciar las siguientes URLS:
 
 
#include <conio.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <dos.h>
#include <windows.h>
#include <iostream.h>
#include <Wincon.h>
#include <mem.h>
#include <stdlib.h>
#include <sys\timeb.h>
#include <tchar.h>
#include <math.h>
 
//Algunos includes no son necesarios pero tampoco estorban...
 
struct rHora  { int Hor; int Min; int Sec; };
struct rFecha  { int Ano; int Mes; int Dia; };
struct rFechaExt { int Ano; int Mes; int Dia; int Hor; int Min; int
Seg; double DiaJul; int Bissto; int PscDia; int PscMes; int AnoSem; int AnoDia; int DiaSem; char DiaStr[10]; char MesStr[11];};
 
//==============================================================================
//Declaracion de variables GLOBALES
//==============================================================================
char Meses[12][11] = {"Enero","Febrero","Marzo","Abril","Mayo","Junio","Julio","Agosto","Septiembre","Octubre","Noviembre","Diciembre"};
int Mdias[12]  = {31,28,31,30,31,30,31,31,30,31,30,31};
char Dias [ 7][10] = {"Lunes","Martes","Miercoles","Jueves","Viernes","Sabado","Domingo"};
//==============================================================================
int Bisiesto(int A)
{
 if (((A % 4)==0) && ((A % 100)!=0 || (A % 400)==0)) return 1; //Si Bisiesto
 else return 0;                 //No Bisiesto
}
//==============================================================================
int DiaJuliano (int A, int M, int D)
{
 //Funciona entre 1801 y 2099
   return D-32075+1461*(A+4800+(M-14)/12)/4+367*(M-2-(M-14)/12*12)/12-3*((A+4900+(M-14)/12)/100)/4;
}
//==============================================================================
int DiaSemana(double DiaJuliano)
{
   double Total  = DiaJuliano + 0.5;
   return int( (Total/7 - int(Total/7))*7 + 0.000000000317 ) + 1;
}
//==============================================================================
void FechaSemDia (rFechaExt &Fec)
{
 int AuxAno = Fec.Ano;
 int FaseB, FaseC, FaseS, FaseE, FaseG, FaseN;
 int DiaSec, DiaSem, NumSem;
 
 if (Fec.Mes < 3) AuxAno = AuxAno - 1;
 
 FaseB = AuxAno / 4 - AuxAno / 100 + AuxAno / 400;
 FaseC = (AuxAno - 1) / 4 - (AuxAno - 1) / 100 + (AuxAno - 1) / 400;
 FaseS = FaseB - FaseC;
 
 if (Fec.Mes < 3)
 {  FaseE = 0;    DiaSec = Fec.Dia - 1 + 31 * (Fec.Mes - 1); }
 else
 { FaseE = FaseS + 1; DiaSec = Fec.Dia + ((Fec.Mes - 3) * 153 + 2) / 5 + 58 + FaseS; }
 
 FaseG  = (AuxAno + FaseB) % 7;
 DiaSem = (DiaSec + FaseG - FaseE) % 7;
 FaseN  = DiaSec + 3 - DiaSem;
 NumSem = FaseN / 7 + 1;
 
 if (FaseN < 0)     NumSem = 53 - (FaseG - FaseS) / 5;
 if (FaseN > 364 + FaseS) NumSem = 1;
 
 DiaSem  = DiaSem + 1;
 DiaSec  = DiaSec + 1;
 Fec.DiaSem = DiaSem;        //Dia de la Semana
 Fec.AnoDia = DiaSec;        //Dia secuencial en el año
 Fec.AnoSem = NumSem;        //Semana del año
}
//==============================================================================
void FechJul (rFecha Fecha, int &DiasJul)
{
 int DiasMes;
 int Dato[12] = {0,31,59,90,120,151,181,212,243,273,304,334};
 DiasJul = (4712 + Fecha.Ano) * 365.25;
 if (DiasJul == int(DiasJul)) DiasJul = DiasJul - 1;
 else         DiasJul = int(DiasJul);
 if (((Fecha.Ano >= 1583 || Fecha.Ano == 1582  && (Fecha.Mes > 10 || (Fecha.Mes == 10 && Fecha.Dia >= 15)))) && Fecha.Ano <= 1700) DiasJul = DiasJul - 10;
 if (1701 <= Fecha.Ano && Fecha.Ano <= 1800) DiasJul = DiasJul - 11;
 if (1801 <= Fecha.Ano && Fecha.Ano <= 1900) DiasJul = DiasJul - 12;
 if (1901 <= Fecha.Ano && Fecha.Ano <= 2100) DiasJul = DiasJul - 13;
 if (2101 <= Fecha.Ano && Fecha.Ano <= 2200) DiasJul = DiasJul - 14; //etc...
 DiasMes = Dato[Fecha.Mes - 1];    //Días transcurridos hasta el mes de la fecha
 //*****************************
 //Miramos si el año es bisiesto
 //*****************************
 if (Fecha.Ano < 1582) goto SALTO ;    //Si el año es del periodo Juliano
 if ( Fecha.Ano / 4   != int(Fecha.Ano / 4)) goto CALC;
 if ((Fecha.Ano / 100 == int(Fecha.Ano / 100)) && (Fecha.Ano / 400 != int(Fecha.Ano / 400))) goto CALC;
SALTO:
 if (Fecha.Mes <= 2) goto CALC;    //Si es Enero o Febrero no influye el bisiesto
 DiasMes = DiasMes + 1;       //El año es bisiesto, añadimos 1
CALC:
 DiasJul = DiasJul + DiasMes + Fecha.Dia;
}
//==============================================================================
void FechaPascua (rFechaExt &Fec)
{
 int constMes, constn;
   int VarA, VarB, VarC, VarD, VarE, DiaPascua, MesPascua;
 if (Fec.Ano >= 1583 && Fec.Ano <= 1699) constMes = 22; constn = 2;
   if (Fec.Ano >= 1700 && Fec.Ano <= 1799) constMes = 23; constn = 3;
   if (Fec.Ano >= 1800 && Fec.Ano <= 1899) constMes = 23; constn = 4;
   if (Fec.Ano >= 1900 && Fec.Ano <= 2099) constMes = 24; constn = 5;
   if (Fec.Ano >= 2100 && Fec.Ano <= 2199) constMes = 24; constn = 6;
   if (Fec.Ano >= 2200 && Fec.Ano <= 2299) constMes = 25; constn = 0;
 VarA = Fec.Ano % 19;
 VarB = Fec.Ano % 4;
 VarC = Fec.Ano % 7;
 VarD = (19 * VarA + constMes) % 30;
 VarE = ( 2 * VarB + 4 * VarC + 6 * VarD + constn) % 7;
 if (VarD + VarE < 10)
   { DiaPascua = VarD + VarE + 22; MesPascua = 3; }
 else
   { DiaPascua = VarD + VarE - 9; MesPascua = 4;
    if   (DiaPascua == 26) DiaPascua = 19;
  else if (DiaPascua == 25 && VarD == 28 && VarE == 6 && VarA > 10) DiaPascua = 18;
   }
 Fec.PscDia = DiaPascua;
 Fec.PscMes = MesPascua;
}
//==============================================================================
void FechazResto (rFechaExt &Fec)
{
 FechaPascua(Fec);
 FechaSemDia(Fec);
 Fec.Bissto = Bisiesto(Fec.Ano);
   strcpy (Fec.DiaStr, Dias [Fec.DiaSem-1]);
   strcpy (Fec.MesStr, Meses[Fec.Mes-1]);
}
//==============================================================================
void FechaGetJul (rFechaExt &Fec)
{
   double jd, fraccion, decimal;
   int  DiaSemana;
  
  jd = 367.0 * Fec.Ano - (7 * (Fec.Ano + ((Fec.Mes + 9) / 12)) / 4) + (275 * Fec.Mes / 9) + Fec.Dia + 1721013;
  
  fraccion = Fec.Hor / 24.0 - 0.5;
 
  if (fraccion >= 0) jd = jd + 1;
  if (fraccion < 0) fraccion = fraccion + 1;
  
  DiaSemana = fmod(jd, 7) + 1;
  decimal = fraccion + (Fec.Min + Fec.Seg / 60.0) / 60.0 / 24.0;
  jd = jd + decimal;
  Fec.DiaJul = jd;
  Fec.DiaSem = DiaSemana;
  FechazResto(Fec);
}
//==============================================================================
void FechaGetFec (rFechaExt &Fec)
{
 
int  intgr;
 int  tmp, j1, j2, j3, j4, j5;
 int  Dia, Mes, Ano, Hor, Min, Sec;
 double frac, dayfrac, F;
  
 intgr = int(Fec.DiaJul);
 frac  = Fec.DiaJul - intgr;
 
 if (intgr >= 2299161)     //Gregorian calendar correction
 {
  tmp = int(((intgr - 1867216) - .25) / 36524.25);
  j1 = intgr + 1 + tmp - int(.25 * tmp);
 }
 else j1 = intgr;
 
 dayfrac = frac + .5;      //correction for half day offset
 
 if (dayfrac >= 1)
 {
  dayfrac = dayfrac - 1;
  j1 = j1 + 1;
 }
 
 j2 = j1 + 1524;
 j3 = int(6680 + ((j2 - 2439870) - 122.1) / 365.25);
 j4 = int(j3 * 365.25);
 j5 = int((j2 - j4) / 30.6001);
 Dia = int(j2 - j4 - int(j5 * 30.6001));
 Mes = int(j5 - 1);
 Ano = int(j3 - 4715);
 if (Mes >  12) Mes = Mes - 12;
 if (Mes >  2 ) Ano = Ano - 1;
 if (Ano <= 0)  Ano = Ano - 1;
 Hor = int( dayfrac * 24);
 Min = int((dayfrac * 24 - Hor) * 60);
 F = ((dayfrac * 24 - Hor) * 60 - Min) * 60;
 Sec = int(F);
 F = F - Sec;
 if (  F > .5) Sec = Sec + 1;
 if (Ano <  0) Ano = -Ano;
 Fec.Ano = Ano;
 Fec.Mes = Mes;
 Fec.Dia = Dia;
 Fec.Hor = Hor;
 Fec.Min = Min;
 Fec.Seg = Sec;
 FechazResto(Fec);
}
//==============================================================================
int ValidaFechaExt ( rFechaExt Fec )
{
 int ErrorFecha = 0;
 if ( Fec.Ano >  9999 || Fec.Ano < 1 )       ErrorFecha = 8;
 if ( Fec.Mes <  1  || Fec.Mes > 12 )       ErrorFecha = 1;
 if ( Fec.Hor <  0  || Fec.Hor > 24 )       ErrorFecha = 2;
 if ( Fec.Min <  0  || Fec.Min > 60 )       ErrorFecha = 3;
 if ( Fec.Seg <  0  || Fec.Seg > 60 )       ErrorFecha = 4;
 if ( Fec.Hor == 24  && (Fec.Min > 0  || Fec.Seg > 0) ) ErrorFecha = 5;
 if ( Fec.Min == 60  && Fec.Seg > 0 )       ErrorFecha = 6;
 if ( Fec.Dia < 1 ) ErrorFecha = 7;
 switch ( Fec.Mes )
 {
  case 1, 3, 5, 7, 8, 10, 12: if ( Fec.Dia > 31 ) ErrorFecha = 7;
  case 4, 6, 9, 11:     if ( Fec.Dia > 30 ) ErrorFecha = 7;
  case 2:
   if (Bisiesto(Fec.Ano))
    if (Fec.Dia > 29) ErrorFecha = 7;
   else
    if (Fec.Dia > 28) ErrorFecha = 7;
 }
    return ErrorFecha;
}
 
//==============================================================================
//==============================================================================
void main()
{
   //---------------------------------------------------------------------------
   int D, M, Y;
   Y=2001;
   printf ("¿Es bisiesto el año %i ? = %i \n", Y, Bisiesto(Y));
   Y=1960;
   printf ("¿Es bisiesto el año %i ? = %i \n", Y, Bisiesto(Y));
   printf("\n");
   //---------------------------------------------------------------------------
 rFecha F;
   int  DiasJul;
 F.Ano=1960;
   F.Mes=8;
   F.Dia=31;
   FechJul(F, DiasJul);
   printf("   FechJul-> Para la Fecha %i-%i-%i, el dia Juliano es: %i \n", F.Ano, F.Mes, F.Dia, DiasJul);
   printf("\n");
   //---------------------------------------------------------------------------
   Y=F.Ano;
   M=F.Mes;
   D=F.Dia;
   printf("DiaJuliano-> Para la Fecha %i-%i-%i, el dia Juliano es: %i \n", Y,M,D,DiaJuliano(Y, M, D));
   printf("\n");
   //---------------------------------------------------------------------------
   printf(" DiaSemana-> Para el dia Juliano %i el dia de la semana es: %i \n", DiaJuliano(Y, M, D), DiaSemana(DiaJuliano(Y, M, D)));
   printf("\n");

   //---------------------------------------------------------------------------
   rFechaExt Fec;
   Fec.Ano=2000;
   Fec.Mes=1;
   Fec.Dia=1;
   Fec.Hor=12;
   Fec.Min=0;
   Fec.Seg=0;
   Fec.DiaJul=0;
   Fec.Bissto=-1;
   Fec.PscDia=0;
   Fec.PscMes=0;
   Fec.AnoSem=0;
   Fec.AnoDia=0;
   Fec.DiaSem=0;
   strcpy(Fec.DiaStr, "");
   strcpy(Fec.MesStr, "");
   printf("Para la Fecha/Hora: %i-%i-%i %i:%i:%i \n", Fec.Ano, Fec.Mes, Fec.Dia, Fec.Hor, Fec.Min, Fec.Seg);
   printf(" El dia Juliano es: %f \n", Fec.DiaJul);
   printf("          Bisiesto: %i \n", Fec.Bissto);
 printf(" Domingo de Pascua: Dia=%i Mes=%i \n",  Fec.PscDia, Fec.PscMes);
   printf("    Semana del ano: %i --> %s \n", Fec.AnoSem, Fec.MesStr);
   printf("       Dia del ano: %i \n", Fec.AnoDia);
   printf("  Dia de la semana: %i --> %s - %s\n", Fec.DiaSem, Fec.DiaStr, Fec.MesStr);
   printf("\n");
   FechaSemDia(Fec);
   printf("FechaSemDia \n");
   printf("Para la Fecha/Hora: %i-%i-%i %i:%i:%i \n", Fec.Ano, Fec.Mes, Fec.Dia, Fec.Hor, Fec.Min, Fec.Seg);
   printf(" El dia Juliano es: %f \n", Fec.DiaJul);
   printf("          Bisiesto: %i \n", Fec.Bissto);
 printf(" Domingo de Pascua: Dia=%i Mes=%i \n",  Fec.PscDia, Fec.PscMes);
   printf("    Semana del ano: %i \n", Fec.AnoSem);
   printf("       Dia del ano: %i \n", Fec.AnoDia);
   printf("  Dia de la semana: %i --> %s - %s\n", Fec.DiaSem, Fec.DiaStr, Fec.MesStr);
   printf("\n");
   FechaPascua(Fec);
   printf("FechaPascua \n");
   printf("Para la Fecha/Hora: %i-%i-%i %i:%i:%i \n", Fec.Ano, Fec.Mes, Fec.Dia, Fec.Hor, Fec.Min, Fec.Seg);
   printf(" El dia Juliano es: %f \n", Fec.DiaJul);
   printf("          Bisiesto: %i \n", Fec.Bissto);
 printf(" Domingo de Pascua: Dia=%i Mes=%i \n",  Fec.PscDia, Fec.PscMes);
   printf("    Semana del ano: %i \n", Fec.AnoSem);
   printf("       Dia del ano: %i \n", Fec.AnoDia);
   printf("  Dia de la semana: %i --> %s - %s\n", Fec.DiaSem, Fec.DiaStr, Fec.MesStr);
   printf("\n");
   FechazResto(Fec);
   printf("FechazResto \n");
   printf("Para la Fecha/Hora: %i-%i-%i %i:%i:%i \n", Fec.Ano, Fec.Mes, Fec.Dia, Fec.Hor, Fec.Min, Fec.Seg);
   printf(" El dia Juliano es: %f \n", Fec.DiaJul);
   printf("          Bisiesto: %i \n", Fec.Bissto);
 printf(" Domingo de Pascua: Dia=%i Mes=%i \n",  Fec.PscDia, Fec.PscMes);
   printf("    Semana del ano: %i \n", Fec.AnoSem);
   printf("       Dia del ano: %i \n", Fec.AnoDia);
   printf("  Dia de la semana: %i --> %s - %s\n", Fec.DiaSem, Fec.DiaStr, Fec.MesStr);
   printf("\n");
   FechaGetJul(Fec);
   printf("FechaGetJul \n");
   printf("Para la Fecha/Hora: %i-%i-%i %i:%i:%i \n", Fec.Ano, Fec.Mes, Fec.Dia, Fec.Hor, Fec.Min, Fec.Seg);
   printf(" El dia Juliano es: %f \n", Fec.DiaJul);
   printf("          Bisiesto: %i \n", Fec.Bissto);
 printf(" Domingo de Pascua: Dia=%i Mes=%i \n",  Fec.PscDia, Fec.PscMes);
   printf("    Semana del ano: %i \n", Fec.AnoSem);
   printf("       Dia del ano: %i \n", Fec.AnoDia);
   printf("  Dia de la semana: %i --> %s - %s\n", Fec.DiaSem, Fec.DiaStr, Fec.MesStr);
   printf("\n");
 Fec.Ano=0;
   Fec.Mes=0;
   Fec.Dia=0;
   Fec.Hor=0;
   Fec.Min=0;
   Fec.Seg=0;
   Fec.DiaJul=2437178;
   Fec.Bissto=-1;
   Fec.PscDia=0;
   Fec.PscMes=0;
   Fec.AnoSem=0;
   Fec.AnoDia=0;
   Fec.DiaSem=0;
   strcpy(Fec.DiaStr, "");
   strcpy(Fec.MesStr, "");
   printf("FechaGetJul \n");
   printf("Para la Fecha/Hora: %i-%i-%i %i:%i:%i \n", Fec.Ano, Fec.Mes, Fec.Dia, Fec.Hor, Fec.Min, Fec.Seg);
   printf(" El dia Juliano es: %f \n", Fec.DiaJul);
   printf("          Bisiesto: %i \n", Fec.Bissto);
 printf(" Domingo de Pascua: Dia=%i Mes=%i \n",  Fec.PscDia, Fec.PscMes);
   printf("    Semana del ano: %i \n", Fec.AnoSem);
   printf("       Dia del ano: %i \n", Fec.AnoDia);
   printf("  Dia de la semana: %i --> %s - %s\n", Fec.DiaSem, Fec.DiaStr, Fec.MesStr);
   printf("\n");

   FechaGetFec(Fec);
   printf("FechaGetJul \n");
   printf("Para la Fecha/Hora: %i-%i-%i %i:%i:%i \n", Fec.Ano, Fec.Mes, Fec.Dia, Fec.Hor, Fec.Min, Fec.Seg);
   printf(" El dia Juliano es: %f \n", Fec.DiaJul);
   printf("          Bisiesto: %i \n", Fec.Bissto);
 printf(" Domingo de Pascua: Dia=%i Mes=%i \n",  Fec.PscDia, Fec.PscMes);
   printf("    Semana del ano: %i \n", Fec.AnoSem);
   printf("       Dia del ano: %i \n", Fec.AnoDia);
   printf("  Dia de la semana: %i --> %s - %s\n", Fec.DiaSem, Fec.DiaStr, Fec.MesStr);
   printf("\n");
   float t  = Fec.DiaJul + 0.5;
   int wd = int( (t/7 - int(t/7))*7 + 0.000000000317 );
 printf("%s", Dias[wd]);

 getch();
}
//==============================================================================

 
De esta manera, si almacenáis la fecha en formato Juliano, en una variable "double" se guardará la fecha y la hora, con su consiguiente ahorro de espacio. También será más fácil su ordenación y el cálculo de sumas y restas entre fechas.
 
Hay funciones que están escritas con distintos algoritmos.
 
Espero que estas funciones os sirvan y os ayuden en vuestros programas.
 
Saludos y hasta la próxima.
 
Si os ha gustado suscribíos a mi canal y compartid esta entrada.

Gracias a todos.
 
/* lo que yo hago ___________________________*/ /*___________________________________________________________*/