Go Down

Topic: Resta de fechas (Read 4075 times) previous topic - next topic

barkalez

Me gustaría saber como restar fechas y saber los días y horas de diferencia de una fecha a otra en Processing.

por ejemplo:

del día:   2012/06/05    hora 13:00
                        le restamos
el día:     2012/05/18    hora 13:00

Resultado es:    18 días y 0 horas


Está claro que no se puede hacer una resta normal porque cuando cambia de mes ya no refleja el resultado....

Por ejemplo:         201206050000
                                              -
                           201205180000
                        ---------------------

                 Resultado:   870.000  ????

Si lo restas en formato fecha con un calendario en mano si que llegas a ver que son 18 días...


Los últimos 4 ceros en la resta son los minutos (00) y segundos(00)..


Gracias

yOPERO

Engineering is the art of
making what you want from
things you can get.

     

[SOLUCIONADO]

barkalez


http://forum.processing.org/


Gracias por el Link es otra fuente de información pero prefiero ésta, a ver si alguien me puede dar alguna idea...

jorgepl

Tanto en processing como en arduino, no existe un formato de dato "Fecha", por lo que lo primero que se me ocurre sería convertir las fechas a un valor numérico de días desde una fecha origen (como se hace en Excel), restar esos números y después deshacer la conversión del resultado.

En esta conversión, habría que tener en cuenta que los meses son de distinto número de días y que hay años bisiestos.

jorgepl

Tomando como origen 01/01/2000:

Code: [Select]

// Tabla que contiene los días que han pasado desde principio de año en cada mes
// (1 de Enero -> 0 días, 1 de Febrero -> 31 días, ...)
tablaMes[12] = {0,31,59,90,120,151,181,212,243,273,304,334};

long ConvierteFechaEnNumero( int year, int mes, int dia)
{
long diaNum;

diaNum = (year-2000)*365 + (year-2000)/4 + tablaMes[mes] + dia;

return diaNum;
}

barkalez


Tomando como origen 01/01/2000:

Code: [Select]

// Tabla que contiene los días que han pasado desde principio de año en cada mes
// (1 de Enero -> 0 días, 1 de Febrero -> 31 días, ...)
tablaMes[12] = {0,31,59,90,120,151,181,212,243,273,304,334};

long ConvierteFechaEnNumero( int year, int mes, int dia)
{
long diaNum;

diaNum = (year-2000)*365 + (year-2000)/4 + tablaMes[mes] + dia;

return diaNum;
}




Vas a perdonar mi ignorancia, pero no entiendo mucho lo que me quieres decir :(.

De todas formas he visto que hay un comando en C# timespan que lo hace, lo que no se es como incluirlo a arduino...

jorgepl

Lo que hace la función es contar los días que han pasado desde el día 1/1/2000. Con esa función conviertes las dos fechas, haces la resta con los valores que te devuelve la función y el resultado es el número de días que hay entre esas dos fechas. Por cierto, al revisarla veo que está mal el indice de tablaMes y que si estás en un año bisiesto antes del 29/02 también te suma ese día (te pongo la corrección al final, que espero que ya esté bien).

Ejemplo:
10/05/2012 --> ConvierteFechaEnNumero(2012,05,10) --> devuelve 4513 (=12*365+12/4+120+10)
31/12/2011 --> ConvierteFechaEnNumero(2011,12,31) --> devuelve 4382(=11*365+11/4+334+31)

10/05/2012 - 31/12/2011 = 4513 - 4382 = 131 días

Código corregido:
Code: [Select]

// Tabla que contiene los días que han pasado desde principio de año en cada mes
// (1 de Enero -> 0 días, 1 de Febrero -> 31 días, ...)
tablaMes[12] = {0,31,59,90,120,151,181,212,243,273,304,334};

long ConvierteFechaEnNumero( int year, int mes, int dia)
{
  long diaNum;
 
  diaNum = (year-2000)*365 + (year-2000)/4 + tablaMes[mes-1] + dia;
  if(((year-2000)%4==0) && (mes<3)) // Es bisiesto y no hemos pasado 29/02
    diaNum--;
 
  return diaNum;
}


barkalez

#7
May 10, 2012, 07:02 pm Last Edit: May 10, 2012, 07:11 pm by barkalez Reason: 1
Vale, muchas gracias, he corregido el código poniendo int en:

int tablaMes[12] = {0,31,59,90,120,151,181,212,243,273,304,334};


Code: [Select]
//            Tabla que contiene los días que han pasado desde principio de año en cada mes
//            (1 de Enero -> 0 días, 1 de Febrero -> 31 días, ...)
//     Ejemplo:
//              10/05/2012 --> ConvierteFechaEnNumero(2012,05,10) --> devuelve 4513 (=12*365+12/4+120+10)
//              31/12/2011 --> ConvierteFechaEnNumero(2011,12,31) --> devuelve 4382(=11*365+11/4+334+31)

//              10/05/2012 - 31/12/2011 = 4513 - 4382 = 131 días


int tablaMes[12] = {0,31,59,90,120,151,181,212,243,273,304,334};

long ConvierteFechaEnNumero( int year, int mes, int dia)
{
  long diaNum;
 
  diaNum = (year-2000)*365 + (year-2000)/4 + tablaMes[mes-1] + dia;
  if(((year-2000)%4==0) && (mes<3)) // Es bisiesto y no hemos pasado 29/02
    diaNum--;
 
  return diaNum;
}



Te digo si funciona o no... tiene buena pinta :)

jorgepl

Quote

Vale, muchas gracias, he corregido el código poniendo int en:

int tablaMes[12] = {0,31,59,90,120,151,181,212,243,273,304,334};


Uppppsss  :smiley-red:

Esto pasa por poner código a la brava sin compilar. Menos mal que se veia facilmente

Espero que te sirva

barkalez

Lo he cargado en el Arduino UNO y en el puerto serie me imprime el valor  0

Es el valor de diaNum    con la fecha leida del reloj 2012 05 10

por mas que busco no se porque.... :(

Te pongo el código entero:

El resto del código es para leer la fecha de un reloj DS1307 que le he integrado....

Code: [Select]
#include "Wire.h"                        //Incluye la libería "Wire.h"
#define DS1307_I2C_ADDRESS 0x68          // DS1307_I2C_ADDRESS le damos el valor 0x68 para iniciar comunicación I2C con DS1307

                  //_______________________________________________________
                  // Código para compatibilizar versiones del IDE Arduino
                  //_______________________________________________________
                 
                 
#if defined(ARDUINO) && ARDUINO >= 100   // Arduino v1.0 and newer
  #define I2C_WRITE Wire.write
  #define I2C_READ Wire.read
#else                                   // Arduino Prior to v1.0
  #define I2C_WRITE Wire.send
  #define I2C_READ Wire.receive
#endif

                  //_______________________________________________________
                  // Variables globales
                  //_______________________________________________________



int command = 0;       // This is the command char, in ascii form, sent from the serial port     
int i;
long previousMillis = 0;        // will store last time Temp was updated
byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
byte test;
byte zero;
char  *Day[] = {"","Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
char  *Mon[] = {"","01","02","03","04","05","06","07","08","09","10","11","12"};

                  //_______________________________________________________
                  // Convierte decimal a Binario BCD
                  //_______________________________________________________

byte decToBcd(byte val)
{
  return ( (val/10*16) + (val%10) );
}

                  //_______________________________________________________
                  // Convierte Binario BCD a Decimal
                  //_______________________________________________________
                 
                 
byte bcdToDec(byte val)
{
  return ( (val/16*10) + (val%16) );
}



                  //_____________________________________________________________
                  // Es la función getDateDs1307 que solo lee la hora y la fecha
                  //______________________________________________________________

// Lee la fecha y la hora y la formatea por ejemplo:  18:41:10  Wed, 10 05 2012
void getDateDs1307()
{
  // Coloca el cursor en el registro 0
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  I2C_WRITE(zero);
  Wire.endTransmission();

  Wire.requestFrom(DS1307_I2C_ADDRESS, 7);

  // A few of these need masks because certain bits are control bits
  second     = bcdToDec(I2C_READ() & 0x7f);
  minute     = bcdToDec(I2C_READ());
  hour       = bcdToDec(I2C_READ() & 0x3f);  // Need to change this if 12 hour am/pm
  dayOfWeek  = bcdToDec(I2C_READ());
  dayOfMonth = bcdToDec(I2C_READ());
  month      = bcdToDec(I2C_READ());
  year       = bcdToDec(I2C_READ());

   
 
}
                  //______________________________________________________________________________
                  // Tabla que contiene los días que han pasado desde principio de año en cada mes
                  //_______________________________________________________________________________
                 
//                                  (1 de Enero -> 0 días, 1 de Febrero -> 31 días, ...)
//     Ejemplo:
//              10/05/2012 --> ConvierteFechaEnNumero(2012,05,10) --> devuelve 4513 (=12*365+12/4+120+10)
//              31/12/2011 --> ConvierteFechaEnNumero(2011,12,31) --> devuelve 4382(=11*365+11/4+334+31)

//              10/05/2012 - 31/12/2011 = 4513 - 4382 = 131 días


int tablaMes[12] = {0,31,59,90,120,151,181,212,243,273,304,334};
  long diaNum;

long ConvierteFechaEnNumero( int year, int month, int dayofmonth)
{
 
 
  diaNum = (year-2000)*365 + (year-2000)/4 + tablaMes[month-1] + dayofmonth;
  if(((year-2000)%4==0) && (month<3)) // Es bisiesto y no hemos pasado 29/02
    dayofmonth--;
 
  return diaNum;

}



void setup() {
  Wire.begin();
  Serial.begin(57600);
  zero=0x00;
}

void loop() {
       
     
     
     
     
      Serial.println(diaNum);
                 
      delay(1000);
     
     
     
    }
//*****************************************************The End***********************

jorgepl

Lo primero de todo, te has confundido en la variable que se decrementa:
Code: [Select]

  if(((year-2000)%4==0) && (month<3)) // Es bisiesto y no hemos pasado 29/02
    dayofmonth--;

Code: [Select]

  if(((year-2000)%4==0) && (month<3)) // Es bisiesto y no hemos pasado 29/02
    diaNum--;


Segundo, para que no te confundas o te haga ninguna cosa rara trata de utilizar nombres distintos para las variables. Llamas igual a la variable pública donde guardas el mes leido del RTC y a al parámetro que pasas a la función de conversión de fecha a número.

Code: [Select]

long previousMillis = 0;        // will store last time Temp was updated
byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
byte test;

[....]

long ConvierteFechaEnNumero( int year, int month, int dayofmonth)
{
}


...Y lo tercero, no llamas a la función en ningún sitio!!!!!

Prueba a poner en el loop:
Code: [Select]

      diaNum = ConvierteFechaEnNumero( 2012,05,11); // Prueba de la función ConvierteFechaEnNumero()
      Serial.println(diaNum);


barkalez

Ya lo he corregido, solo me falta probarlo a ver que tal va....

En él código lee la fecha en el momento y saca el número de días desde el 2000 yo tengo que incluir

otra fecha proveniente de una EEPROM y con las dos fechas restarlas.

La verdad que es divertido pero es un destruye cerebros...

Te pongo el código para que veas que lo he corregido bien:

Code: [Select]


#include "Wire.h"                        //Incluye la libería "Wire.h"
#define DS1307_I2C_ADDRESS 0x68          // DS1307_I2C_ADDRESS le damos el valor 0x68 para iniciar comunicación I2C con DS1307

                  //_______________________________________________________
                  // Código para compatibilizar versiones del IDE Arduino
                  //_______________________________________________________


#if defined(ARDUINO) && ARDUINO >= 100   // Arduino v1.0 and newer
  #define I2C_WRITE Wire.write
  #define I2C_READ Wire.read
#else                                   // Arduino Prior to v1.0
  #define I2C_WRITE Wire.send
  #define I2C_READ Wire.receive
#endif

                  //_______________________________________________________
                  // Variables globales
                  //_______________________________________________________



int command = 0;       // This is the command char, in ascii form, sent from the serial port
int i;
long previousMillis = 0;        // will store last time Temp was updated
byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
byte test;
byte zero;
char  *Day[] = {"","Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
char  *Mon[] = {"","01","02","03","04","05","06","07","08","09","10","11","12"};

                  //_______________________________________________________
                  // Convierte decimal a Binario BCD
                  //_______________________________________________________

byte decToBcd(byte val)
{
  return ( (val/10*16) + (val%10) );
}

                  //_______________________________________________________
                  // Convierte Binario BCD a Decimal
                  //_______________________________________________________


byte bcdToDec(byte val)
{
  return ( (val/16*10) + (val%16) );
}



                  //_____________________________________________________________
                  // Es la función getDateDs1307 que solo lee la hora y la fecha
                  //______________________________________________________________

// Lee la fecha y la hora y la formatea por ejemplo:  18:41:10  Wed, 10 05 2012
void getDateDs1307()
{
  // Coloca el cursor en el registro 0
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  I2C_WRITE(zero);
  Wire.endTransmission();

  Wire.requestFrom(DS1307_I2C_ADDRESS, 7);

  // A few of these need masks because certain bits are control bits
  second     = bcdToDec(I2C_READ() & 0x7f);
  minute     = bcdToDec(I2C_READ());
  hour       = bcdToDec(I2C_READ() & 0x3f);  // Need to change this if 12 hour am/pm
  dayOfWeek  = bcdToDec(I2C_READ());
  dayOfMonth = bcdToDec(I2C_READ());
  month      = bcdToDec(I2C_READ());
  year       = bcdToDec(I2C_READ());



}
                  //______________________________________________________________________________
                  // Tabla que contiene los días que han pasado desde principio de año en cada mes
                  //_______________________________________________________________________________

//                                  (1 de Enero -> 0 días, 1 de Febrero -> 31 días, ...)
//     Ejemplo:
//              10/05/2012 --> ConvierteFechaEnNumero(2012,05,10) --> devuelve 4513 (=12*365+12/4+120+10)
//              31/12/2011 --> ConvierteFechaEnNumero(2011,12,31) --> devuelve 4382(=11*365+11/4+334+31)

//              10/05/2012 - 31/12/2011 = 4513 - 4382 = 131 días


int tablaMes[12] = {0,31,59,90,120,151,181,212,243,273,304,334};



long ConvierteFechaEnNumero( int anio, int mes, int diademes)
{
  long dia;

  dia = (anio-2000)*365 + (anio-2000)/4 + tablaMes[mes-1] + diademes;
  if(((anio-2000)%4==0) && (mes<3)) // Es bisiesto y no hemos pasado 29/02
    dia--;

  return dia;

}



void setup() {
  Wire.begin();
  Serial.begin(57600);
  zero=0x00;
}

void loop() {


      long diaNum;

      diaNum = ConvierteFechaEnNumero( year,month,dayofmonth); // Prueba de la función ConvierteFechaEnNumero()




      Serial.println(diaNum);

      delay(1000);



    }
//*****************************************************The End***********************

jorgepl

En la llamada a la función en el loop, le estás pasando unas variables que no has inicializado ni les has dado ningún valor. Por defecto, puede que se inicialicen a cero así que el resultado de la función va a ser cero otra vez.

En el ejemplo que te había puesto yo, la llamada a la función era con los valores de la fecha directamente, para que probases la función.

Una vez que veas que la función está bien, ya puedes dedicarte al resto: leer el RTC, leer la EEPROM, restar fechas,....lo que quieras. Pero primero prueba que la función es correcta.

Code: [Select]

void loop() {
      long diaNum;

      year = 2012;
      month = 5;
      dayofmonth = 11;

      diaNum = ConvierteFechaEnNumero( year,month,dayofmonth); // Prueba de la función ConvierteFechaEnNumero()
      Serial.println(diaNum);
      delay(1000);
    }

barkalez

Funciona :D

Buen calculador

dia = (anio-2000)*365 + (anio-2000)/4 + tablaMes[mes-1] + diademes;
  if(((anio-2000)%4==0) && (mes<3)) // Es bisiesto y no hemos pasado 29/02
    dia--;

Ahora voy a intentarlo que en vez de días me dé minutos para que sea mas preciso el programa.

A ver si lo puedo calcular... Muchas gracias

barkalez

Despues de toda un día entero probando y probando el código e aquí el resultado final.

Falta que lea la fecha guardada de la eeprom. Yo lo puse para probarlo....

Cuando lo tenga lo subo...

El código lo que hace es saber cuantos días hay de una fecha a otra. Mas adelante os explicaré porque quiero esto.

Agradecerle a jorge toda su ayuda, por cierto cambié un poco tu función ya que no podía poner 2012.

Code: [Select]
#include "Wire.h"                        //Incluye la libería "Wire.h"
#define DS1307_I2C_ADDRESS 0x68          // DS1307_I2C_ADDRESS le damos el valor 0x68 para iniciar comunicación I2C con DS1307

                  //_______________________________________________________
                  // Código para compatibilizar versiones del IDE Arduino
                  //_______________________________________________________
                 
                 
#if defined(ARDUINO) && ARDUINO >= 100   // Arduino v1.0 and newer
  #define I2C_WRITE Wire.write
  #define I2C_READ Wire.read
#else                                   // Arduino Prior to v1.0
  #define I2C_WRITE Wire.send
  #define I2C_READ Wire.receive
#endif

                  //_______________________________________________________
                  // Variables globales
                  //_______________________________________________________



int command = 0;       // This is the command char, in ascii form, sent from the serial port     
int i;
long previousMillis = 0;        // will store last time Temp was updated
byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
byte test;
byte zero;
char  *Day[] = {"","Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
char  *Mon[] = {"","01","02","03","04","05","06","07","08","09","10","11","12"};

                  //_______________________________________________________
                  // Convierte decimal a Binario BCD
                  //_______________________________________________________

byte decToBcd(byte val)
{
  return ( (val/10*16) + (val%10) );
}

                  //_______________________________________________________
                  // Convierte Binario BCD a Decimal
                  //_______________________________________________________
                 
                 
byte bcdToDec(byte val)
{
  return ( (val/16*10) + (val%16) );
}



                  //_____________________________________________________________
                  // Es la función getDateDs1307 que solo lee la hora y la fecha
                  //______________________________________________________________

                  // Lee la fecha y la hora e imprime el resultado
                 
                 
            void getDateDs1307()
                     {
                                   // Coloca el cursor en el registro 0
                                   Wire.beginTransmission(DS1307_I2C_ADDRESS);
                                   I2C_WRITE(zero);
                                   Wire.endTransmission();
                                   Wire.requestFrom(DS1307_I2C_ADDRESS, 7);
                                   // A few of these need masks because certain bits are control bits
                               second     = bcdToDec(I2C_READ() & 0x7f);
                               minute     = bcdToDec(I2C_READ());
                               hour       = bcdToDec(I2C_READ() & 0x3f);  // Need to change this if 12 hour am/pm
                               dayOfWeek  = bcdToDec(I2C_READ());
                               dayOfMonth = bcdToDec(I2C_READ());
                               month      = bcdToDec(I2C_READ());
                               year       = bcdToDec(I2C_READ());
                               
                               
             
                   }


                  //______________________________________________________________________________
                  // Tabla que contiene los días que han pasado desde principio de año en cada mes
                  //_______________________________________________________________________________

//                                  (1 de Enero -> 0 días, 1 de Febrero -> 31 días, ...)
//     Ejemplo:
//              10/05/2012 --> ConvierteFechaEnNumero(2012,05,10) --> devuelve 4513 (=12*365+12/4+120+10)
//              31/12/2011 --> ConvierteFechaEnNumero(2011,12,31) --> devuelve 4382(=11*365+11/4+334+31)

//              10/05/2012 - 31/12/2011 = 4513 - 4382 = 131 días


int tablaMes[12] = {0,31,59,90,120,151,181,212,243,273,304,334};



long ConvierteFechaEnNumero( int anio, int mes, int diademes)
{
  long dia;

  dia = (anio)*365 + (anio)/4 + tablaMes[mes-1] + diademes;
  if(((anio)%4==0) && (mes<3)) // Es bisiesto y no hemos pasado 29/02
    dia--;

  return dia;

}

void setup() {
  Wire.begin();
  Serial.begin(57600);
  zero=0x00;
 
}

void loop() {   
     
      getDateDs1307();
      Serial.println(" ");
      delay(1000);
      Serial.println(year);
      delay(1000);
      Serial.println(month);
      delay(1000);
      Serial.println(dayOfMonth);           
      delay(1000);
     
      long FechaActual;
      FechaActual = ConvierteFechaEnNumero( year,month,dayOfMonth); // Prueba de la función ConvierteFechaEnNumero()
      Serial.println("FechaActual");
      Serial.println(FechaActual);
      delay(1000);
     
      long FechaGuardada;
      long AnioGuardado = 12;
      long MesGuardado  = 5;
      long DiaGuardado  = 5;
      FechaGuardada = ConvierteFechaEnNumero( AnioGuardado,MesGuardado,DiaGuardado); // Prueba de la función ConvierteFechaEnNumero()
      Serial.println("FechaGuardada");
      Serial.println(FechaGuardada);
      delay(1000);
     
     
      long Resultado;
      Resultado = FechaActual - FechaGuardada;
      Serial.println("Resultado");     
      Serial.println(Resultado);
    }
//*****************************************************The End***********************

Go Up