[ Risolto ] Aiuto per l'uso della libreria time.h, now() e timestamp

Ciao a tutti,
ancora io che chiedo per la gestione del tempo:
ho bisogno di eseguire confronti tra il valore restituito da now() (i secondi trasforsi dal 1.1.1970 a now()) ed un timestamp futuro che quindi dovrei calcolarmi, solo che non riesco a capire come calcolarlo...
Da un bel po mi sbatto per capire come si calcola e creare una funzioncina, ma il valore che tiro fuori tenendo conto anche degli anni bisestili, non è mai affidabile, nel senso che ho cercato di raggiungere il risultato confrontandolo anche con quello restituito da due servizi on line:

che a loro volta restituiscono per la stessa data valori diversi, ottenedo a mia volta un terzo risultato :frowning:
Ho cercato invano anche su internet formule per il calcolo per poter a mia volta crearmi una funzioncina affidabile, ma non trovo nulla, quindi eccomi qui a chiedere aiuto...

Grazie in anticipo a tutti.

Riccardo

Lo UNIX Time è il numero di secondi trascorsi a partire dal 01/01/1970 e rappresenta un metodo rapido e semplice per calcolare il tempo nei calcolatori, grazie al fatto che si opera con numeri interi.

Il secondo link che hai fornito è sicuramente il più utile, in quanto l'ora che indica è riferita al GMT 0 (meridiano di Greenwich), da cui derivare tutti gli altri. Noi siamo in GMT +1 quindi lo UNIX Time "nostro" è quello indicato sul sito +2 ore espresse in secondi: una per il calcolo del fuso ed una per l'ora legale. Quindi X + (2 x 60 x 60).

L'altro sito fa la stessa cosa, ma considera un GMT -5 più l'eventuale ora legale (ecco il motivo dei diversi risultati).

Rimane il problema del calcolo dei giorni, complicato dal fatto che ogni 4 anni un anno è bisestile... ti ho dato un indizio ora prova a sviluppare un codice!

Ettore Massimo Albani

Allora, allora,
ho preso l'esempio della libreria time.h denominato "TimeRTC" e l'ho modificato
per vedere se riesco a calcolare il timestamp, il codice è quello che segue:

/*
 * TimeRTC.pde
 * example code illustrating Time library with Real Time Clock.
 * 
 */

#include <Time.h>  
#include <Wire.h>  
#include <DS1307RTC.h>  // a basic DS1307 library that returns time as a time_t

void setup()  {
  Serial.begin(9600);
  setSyncProvider(RTC.get);   // the function to get the time from the RTC
  if(timeStatus()!= timeSet) 
     Serial.println("Unable to sync with the RTC");
  else
     Serial.println("RTC has set the system time");      
}

unsigned long miotimestamp;
const unsigned long totmesiinsecondi [12]  = {0,2678400,5097600,7776000,10368000,13046400,15638400,18316800,20995200,23587200,26265600,28857600};
                    
const unsigned long annoinsec = 31536000;  // Un anno espresso in secondi
const unsigned long giornoinsec = 86400;   // Un giorno espresso in secondi
const int orainsec = 3600;                 // Un'ora spressa in secondi
const int announix = 1970;
int bisestile;

void loop()
{
  int indicetotmesi = month()-1; 
  miotimestamp = ((year() - announix) * annoinsec) + ((int((year() - 1968) / 4)) * giornoinsec) + totmesiinsecondi[indicetotmesi] + (day() * giornoinsec) + (hour() * orainsec) + (minute() * 60) + second();
//                (gli anni trascorsi da epoc    ) + (giorni aggiuntivi per gli anni bisestili) + (leggo nel vettorequanti sec.   + (giorni del mese in   + (ore att. in secondi)
//                                                                                                 sono passati dall' inizio anno    corso in secondi)
//                                                                                                 alla fine del mese precedente
//                                                                                                 tenedo conto della variabilità
//                                                                                                 dei mesi)  

   bisestile = (year() % 4);  
   
   if ((month() == 2) && (day() <= 29) && (bisestile = 0)) 
     {  miotimestamp = miotimestamp - giornoinsec; }
     // se l'anno rilevato è bisestile la formula sopra aggiunge un giorno anche se ancora non è passato il 29 febbraio quindi verifico le condizioni ed eventualmente sottraggo un giorno    
     
   digitalClockDisplay();  
   delay(1000);
}

void digitalClockDisplay(){
  // digital clock display of the time
  Serial.print(hour());
  printDigits(minute());
  printDigits(second());
  Serial.print(" ");
  Serial.print(day());
  Serial.print(" ");
  Serial.print(month());
  Serial.print(" ");
  Serial.print(year());
  Serial.print("    Timestamp = ");
  Serial.print(now());
  Serial.print("    MioTimestamp = ");
  Serial.print(miotimestamp);
  Serial.print("    Differenza = ");
  Serial.println(miotimestamp - now());
  
}

void printDigits(int digits){
  // utility function for digital clock display: prints preceding colon and leading 0
  Serial.print(":");
  if(digits < 10)
    Serial.print('0');
  Serial.print(digits);
}

Nel serial monitor, il mio timestamp è costantemente magggiore rispetto a quello di now() di 20864 secondi :(, ossia 5 ore 47 minuti e 44 secondi:

20:56:57 15 9 2012 Timestamp = 1347742617 MioTimestamp = 1347763481 Differenza = 20864

Da ore cerco di capire dove sta l'inghippo ma proprio non lo vedo =(,
Mi rendo conto che la domanda è impegnativa, ma qualcuno riesce a capire dove sbaglio... :cold_sweat:

Grazie Riccardo

cyberhs:
Lo UNIX Time è il numero di secondi trascorsi a partire dal 01/01/1970 e rappresenta un metodo rapido e semplice per calcolare il tempo nei calcolatori, grazie al fatto che si opera con numeri interi.

Il secondo link che hai fornito è sicuramente il più utile, in quanto l'ora che indica è riferita al GMT 0 (meridiano di Greenwich), da cui derivare tutti gli altri. Noi siamo in GMT +1 quindi lo UNIX Time "nostro" è quello indicato sul sito +2 ore espresse in secondi: una per il calcolo del fuso ed una per l'ora legale. Quindi X + (2 x 60 x 60).

L'altro sito fa la stessa cosa, ma considera un GMT -5 più l'eventuale ora legale (ecco il motivo dei diversi risultati).

Ettore Massimo Albani

Ciao,
scusami se nel post precedente ho dimenticato di ringraziarti, ero così preso dal risolvere il mio quesito che ho tralasciato le buone maniere.
Ti ringrazio ora scusa il ritardo.

Ad ogni modo il tuo post, ha risolto in parte il dubbio che avevo sul calcolo del timestamp, nel senso che una volta assunto che la differenza tra i risultati ottenuti via web dipendeva dal fuso orario ed eventualmente anche dall'ora legale, mi sono detto che la funzione now() aplicata all'orario catturato dal mio RTC (DS1307) non ne sarebbe stata influenzata e mi sono messo a scrivere le poche righe che ho postato,ottenedo appunto la differenza per eccesso che ho già scritto.

Oggi ho fatto un'altra prova ancora, ho attaccato un Mega 2560 che avevo da parte, ed ho applicato la mia formula anche all'esempio della libreria che riguarda la sincronizzazione attraverso la seriale "TimeSerial", il codice è quello che segue:

/* 
 * TimeSerial.pde
 * example code illustrating Time library set through serial port messages.
 *
 * Messages consist of the letter T followed by ten digit time (as seconds since Jan 1 1970)
 * you can send the text on the next line using Serial Monitor to set the clock to noon Jan 1 2010
 T1262347200  
 *
 * A Processing example sketch to automatically send the messages is inclided in the download
 */ 
 
#include <Time.h>  

#define TIME_MSG_LEN  11   // time sync to PC is HEADER followed by unix time_t as ten ascii digits
#define TIME_HEADER  'T'   // Header tag for serial time sync message
#define TIME_REQUEST  7    // ASCII bell character requests a time sync message 

unsigned long miotimestamp;
const unsigned long totmesiinsecondi [12]  = {0,2678400,5097600,7776000,10368000,13046400,15638400,18316800,20995200,23587200,26265600,28857600};
                    
const unsigned long annoinsec = 31536000;  // Un anno espresso in secondi
const unsigned long giornoinsec = 86400;   // Un giorno espresso in secondi
const int orainsec = 3600;                 // Un'ora spressa in secondi
const int announix = 1970;
int bisestile;


void setup()  {
  Serial.begin(9600);
  setSyncProvider( requestSync);  //set function to call when sync required
  Serial.println("Waiting for sync message");
}

void loop(){    
  
  if(Serial.available() ) 
  {
    processSyncMessage();
  }
  if(timeStatus()!= timeNotSet)   
  {
    digitalWrite(13,timeStatus() == timeSet); // on if synced, off if needs refresh  
    digitalClockDisplay();  
    int indicetotmesi = month()-1; 
    miotimestamp = ((year() - announix) * annoinsec) + ((int((year() - 1968) / 4)) * giornoinsec) + totmesiinsecondi[indicetotmesi] + (day() * giornoinsec) + (hour() * orainsec) + (minute() * 60) + second();
//                  (gli anni trascorsi da epoc    ) + (giorni aggiuntivi per gli anni bisestili) + (leggo nel vettorequanti sec.   + (giorni del mese in   + (ore att. in secondi)
//                                                                                                 sono passati dall' inizio anno    corso in secondi)
//                                                                                                 alla fine del mese precedente
//                                                                                                 tenedo conto della variabilità
//                                                                                                 dei mesi)  

   bisestile = (year() % 4);  
   
   if ((month() == 2) && (day() <= 29) && (bisestile = 0)) 
     {  miotimestamp = miotimestamp - giornoinsec; }
     // se l'anno rilevato è bisestile la formula sopra aggiunge un giorno anche se ancora non è passato il 29 febbraio quindi verifico le condizioni ed eventualmente sottraggo un giorno    
     
     
  }
  delay(1000);
}

void digitalClockDisplay(){
  // digital clock display of the time
  Serial.print(hour());
  printDigits(minute());
  printDigits(second());
  Serial.print(" ");
  Serial.print(day());
  Serial.print(" ");
  Serial.print(month());
  Serial.print(" ");
  Serial.print(year()); 
  Serial.print("    Timestamp = ");
  Serial.print(now());
  Serial.print("    MioTimestamp = ");
  Serial.print(miotimestamp);
  Serial.print("    Differenza = ");
  Serial.println(miotimestamp - now());
}

void printDigits(int digits){
  // utility function for digital clock display: prints preceding colon and leading 0
  Serial.print(":");
  if(digits < 10)
    Serial.print('0');
  Serial.print(digits);
}

void processSyncMessage() {
  // if time sync available from serial port, update time and return true
  while(Serial.available() >=  TIME_MSG_LEN ){  // time message consists of a header and ten ascii digits
    char c = Serial.read() ; 
    Serial.print(c);  
    if( c == TIME_HEADER ) {       
      time_t pctime = 0;
      for(int i=0; i < TIME_MSG_LEN -1; i++){   
        c = Serial.read();          
        if( c >= '0' && c <= '9'){   
          pctime = (10 * pctime) + (c - '0') ; // convert digits to a number    
        }
      }   
      setTime(pctime);   // Sync Arduino clock to the time received on the serial port
    }  
  }
}

time_t requestSync()
{
  Serial.write(TIME_REQUEST);  
  return 0; // the time will be sent later in response to serial mesg
}

Anche in questo caso la differenza è stata di 20863 sec (1 in meno rispetto all'ora presa dall'RTC):

12:00:01 1 1 2010 Timestamp = 1262347201 MioTimestamp = 1262368064 Differenza = 20863

Me lo aspettavo in parte, ma ho voluto provare ugualmente...

Potrei anche fermarmi qui e semplicemente sottrarre l'eccedenza, ma mi rimarrebbe il tarlo di sapere cosa sbaglio...

Con sintesi estrema, devo eseguire in modo regolare x operazioni all'interno di un intervallo di tempo che può accavallarsi alla mezzanotte, quindi con i timestamp eseguo semplici confronti ed Arduino fa o legge qualcosa, diversemente dovrei raffontare orari che a mezzanotte si azzerano e via dicendo, non che non si faccia, ma con i timestamp il codice sarebbe decisamente più snello e risparmierei un bel po' di memoria.

Grazie a chiunque vorrà aiutarmi.

Ancora grazie a cyberhs.

Riccardo

Ti posso dare un piccolo aiuto, nel senso che le funzioni di conversione di UNIX hanno fatto penare anche me.
Se ti prendi la mia lib swRTC, nel codice ci sono 2 algoritmi per passare da un timestamp ad un dato istante e viceversa. Le funzioni non sono legate al solo timestamp UNIX ma accettato una qualsiasi epoca.

Grazie Leo72,
ci guardo di sicuro, la tua libreria l'avevo già scaricata, perché come avrai capito mi interessa molto il controllo del tempo...
Spero prima o poi di svelare l'arcano...

Grazie.

Riccardo.

Ciao a tutti,
ho seguito il consiglio di Leo72,
e dalla sua libreria ho estrapolato la sua funzione "getTimestamp" per confrontarne/capirna il funzionamento, l'ho adattata all'esempio della libreria time che si chiama "TimeSerial" per fare delle prove:

/* 
 * TimeSerial.pde
 * example code illustrating Time library set through serial port messages.
 *
 * Messages consist of the letter T followed by ten digit time (as seconds since Jan 1 1970)
 * you can send the text on the next line using Serial Monitor to set the clock to noon Jan 1 2010
 T1262347200  
 *
 * A Processing example sketch to automatically send the messages is inclided in the download
 */ 
 
#include <Time.h>  

#define TIME_MSG_LEN  11   // time sync to PC is HEADER followed by unix time_t as ten ascii digits
#define TIME_HEADER  'T'   // Header tag for serial time sync message
#define TIME_REQUEST  7    // ASCII bell character requests a time sync message 

//////////  VARIABILI DI LEO72

byte daysPerMonth[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
unsigned long time=0;
unsigned long tmstp;

void setup()  {
  Serial.begin(9600);
  setSyncProvider( requestSync);  //set function to call when sync required
  Serial.println("Waiting for sync message");
}

void loop(){    
  time = 0;
  if(Serial.available() ) 
  {
    processSyncMessage();
  }
  if(timeStatus()!= timeNotSet)   
  {
    digitalWrite(13,timeStatus() == timeSet); // on if synced, off if needs refresh  
    tmstp = now();
    Leo72();
    digitalClockDisplay();  
  }
  //delay(1000);
}

void digitalClockDisplay(){
  // digital clock display of the time
  Serial.print(hour());
  printDigits(minute());
  printDigits(second());
  Serial.print(" ");
  Serial.print(day());
  Serial.print(" ");
  Serial.print(month());
  Serial.print(" ");
  Serial.print(year()); 
  Serial.print("    Timestamp = ");
  Serial.print(now());
  Serial.print("    LeoTimestamp = ");
  Serial.print(time);
  Serial.print("    LeoTimestamp-Timestamp = ");
  Serial.println(time - tmstp);
}

void printDigits(int digits){
  // utility function for digital clock display: prints preceding colon and leading 0
  Serial.print(":");
  if(digits < 10)
    Serial.print('0');
  Serial.print(digits);
}

void processSyncMessage() {
  // if time sync available from serial port, update time and return true
  while(Serial.available() >=  TIME_MSG_LEN ){  // time message consists of a header and ten ascii digits
    char c = Serial.read() ; 
    Serial.print(c);  
    if( c == TIME_HEADER ) {       
      time_t pctime = 0;
      for(int i=0; i < TIME_MSG_LEN -1; i++){   
        c = Serial.read();          
        if( c >= '0' && c <= '9'){   
          pctime = (10 * pctime) + (c - '0') ; // convert digits to a number    
        }
      }   
      setTime(pctime);   // Sync Arduino clock to the time received on the serial port
    }  
  }
}

time_t requestSync()
{
  Serial.write(TIME_REQUEST);  
  return 0; // the time will be sent later in response to serial mesg
}


void Leo72()
{ 	time += (year()- 1970)*365.2422;
	for (int i=0; i < month()-1; i++){
		time += daysPerMonth[i]; //find day from month
	}
	time = ( time + day() ) * 24; //find hour from day
	time = ( time + hour() ) * 60; //find minute from hours
	time = ( time + minute() ) * 60; //find seconds from minute
	time += second(); // add seconds
	if (time>951847199) { time +=86400; } //year 2000 is a special leap year, so 1 day must be added if date is greater than 29/02/2000
        time -=86400UL; //because years start at day 0.0, not day 1. 
      }

dal serial monitor, passando "T1347738804" che corrisponde come data 15/09/2012 ore 19:53:24 ecco la conferma:

aWaiting for sync message
T19:53:24 15 9 2012    Timestamp = 1347738804    LeoTimestamp = 1347738804    LeoTimestamp-Timestamp = 0
19:53:25 15 9 2012    Timestamp = 1347738805    LeoTimestamp = 1347738805    LeoTimestamp-Timestamp = 0
19:53:26 15 9 2012    Timestamp = 1347738806    LeoTimestamp = 1347738806    LeoTimestamp-Timestamp = 0
19:53:27 15 9 2012    Timestamp = 1347738807    LeoTimestamp = 1347738807    LeoTimestamp-Timestamp = 0
19:53:28 15 9 2012    Timestamp = 1347738808    LeoTimestamp = 1347738808    LeoTimestamp-Timestamp = 0

Ora non mi rimane che scrivere la procedurina alla quale passare i valori che voglio per calcolare i timestamp futuri, che schiappa che sono due giorni per far girare sto sketchino...

Grazie a tutti, ma soprattutto a Leo72.

Riccardo.

Bravo, mi fa piacere che tu abbia risolto, anche se ho potuto aiutarti il giusto dati i miei impegni.
Ah... ricordati: condividere condividere condividere :wink: