How can I convert date and time to POSIX

I could solve my problem as the following but I still have a small problem

Here is the code. I opted for that code because there is no need of an additonally library.

First I initiate a variabl

uint32_t posix

I used that code, (thank Jurs)

void get_posix(char * buff)
{
  // gsm_time format: "16/12/21,00:01:23+08";
  char format[23]="%d/%d/%d,%d:%d:%d+%d"; 
  int year,month,day,hour,minute,second,timezone;
  sscanf(buff,format,&year,&month,&day,&hour,&minute,&second,&timezone);
  if (year<100) year+=2000;

  long epoch=0;
  for (int yr=1970;yr<year;yr++)
  if (isLeapYear(yr)) epoch+=366*86400L;
  else epoch+=365*86400L;
  for(int m=1;m<month;m++) epoch+=daysInMonth(year,m)*86400L;
  epoch +=(day-1)*86400L;
  epoch +=hour*3600L;
  epoch +=minute*60;
  epoch +=second;
 // epoch-=timezone*3600L; // That seams to be wrong
 // epoch -=timezone*900L;  
  posix = (uint32_t)epoch;
}
byte daysInMonth(int yr,int m)
{
  byte days[12]={31,28,31,30,31,30,31,31,30,31,30,31};
  if (m==2 && isLeapYear(yr)) return 29;
  else return days[m-1];
}
bool isLeapYear(int yr)
{
  if (yr % 4 == 0 && yr % 100 != 0 || yr % 400 == 0) return true;
  else return false;
}

I get the posix time as the following

void get_posix()
{
  char buff[23];
  if(fona.getTime(buff, 23))
  {
    
     // Remove first " and last " (it is not charmly)
    buff[0] = buff[1];// " 1
    buff[1] = buff[2];// 1 6
    buff[2] = buff[3];// 6 /
    buff[3] = buff[4];// / 1
    buff[4] = buff[5];// 1 2
    buff[5] = buff[6];// 2 /
    buff[6] = buff[7];// / 2
    buff[7] = buff[8];// 2 2
    buff[8] = buff[9];// 2 ,
    buff[9] = buff[10];// , 0
    buff[10] = buff[11];// 0 1
    buff[11] = buff[12];// 1 :
    buff[12] = buff[13];// : 1
    buff[13] = buff[14];// 1 1
    buff[14] = buff[15];// 1 :
    buff[15] = buff[16];// : 0
    buff[16] = buff[17];// 0 0
    buff[17] = buff[18];// 0 +
    buff[18] = buff[19];// + 0
    buff[19] = buff[20];// 0 4
    buff[20] = buff[21];// 4 \0

    buff[20]='\0';
    buff[21]='\0';
    buff[22]='\0';

    Serial.print(F("DEBUG buff:")); Serial.println(buff);
    get_posix(buff);
    Serial.print(F("DEBUG posix:")); Serial.println(posix);
  }
  else
  {
    sprintln(F("Error getting posix time"),2);
  }

  /*
   * Another way to get posix time, but need #include <time.h>
   */
/*
  Serial.println(buff);
  char posixe[]="16/12/22,00:01:23+04";
  struct tm tm;
  time_t epochUTC;
  if ( strptime(posixe, "%y/%m/%d,%T", &tm) != NULL ) {
    epochUTC = mktime(&tm); // I ignore the +04 piece may be you want to take this into account?
  } else {
  Serial.println(F("you have a bug with POSIX"));
  }
  Serial.print(F("POSIX time1:")); Serial.println(epochUTC);
*/
}

Serial.print(F("DEBUG posix:")); display that

1482494931

Regarding my problem with ajson. ajson accpeted only int ou double. For posix with need a uint32_t.
I modified the ajson.cpp file and I add a new fonction. I also addapted ajson.h

aJsonObject*
aJsonClass::createItem(uint32_t num)
{
  aJsonObject *item = newItem();
  if (item)
    {
      item->type = aJson_Int;
      item->valueint = (uint32_t) num;
    }
  return item;
}
void
aJsonClass::addNumberToObject(aJsonObject* object, const char* name, uint32_t n)
{
  addItemToObject(object, name, createItem(n));
}

Now the last problem is the following and I think it because I commented

// epoch -=timezone*3600L;

I commented it because it gave a wrong a time. 2 hour more than the reality. I timezone is a quarter of an hour, it should be?

// epoch -=timezone*900L;

Any way, I want to have UTC.

The problem is the following. As I wrote, the returned posix time is

1464661369

and Ubidots want to have

1464661369000

I supposed it because the timezone is not added.

I supposed to solve my problem, I could do this

  epoch += 000; // I want to have UTC time
void get_posix(char * buff)
{
  // gsm_time format: "16/12/21,00:01:23+08";
  char format[23]="%d/%d/%d,%d:%d:%d+%d"; 
  int year,month,day,hour,minute,second,timezone;
  sscanf(buff,format,&year,&month,&day,&hour,&minute,&second,&timezone);
  if (year<100) year+=2000;


  long epoch=0;
  for (int yr=1970;yr<year;yr++)
  if (isLeapYear(yr)) epoch+=366*86400L;
  else epoch+=365*86400L;
  for(int m=1;m<month;m++) epoch+=daysInMonth(year,m)*86400L;
  epoch +=(day-1)*86400L;
  epoch +=hour*3600L;
  epoch +=minute*60;
  epoch +=second;
  // epoch -=timezone*900L;
  epoch += 000; // I want to have UTC time
  posix = (uint32_t)epoch;
}

what do you suggest me, for the best?

Thank a lot!

Clearly, adding 0 (or 000) to any number will only give you the original number.

epoch += 000; // I want to have UTC time

Multiplying by 1000 ( I think to set your posix time = milliseconds since 1 January 1970) is what you want to do but you will exceed 32 bit (uint32_t).

Don't do long epoch=0; ==> use directly an unsigned long uint32_t epoch=0;

Instead of messing around with your buffer to get rid of the first and last ", just call get_posix(buff+1);... that will skip the first " and you don't care having the last one in the string it won't get parsed (or you could add them in the sscanf format.

The part you commented out

 // epoch-=timezone*3600L; // That seams to be wrong

Well if the string was returned in the right way, the you would have after the seconds th3 delta in minutes with UTC... but I'm not aware of a delta of 8 minutes existing, so I suppose this returns indeed a number of hours, so which are represented in 3600 seconds... so that was marketing sense if you are at +08 to add 8x3600 seconds to the calculated unix time

pierrot10:
and Ubidots want to have
Quote
1464661369000

Unfortunately your posixtime seems to be 1000 times unixtime.
It's a very big number, milliseconds since 1970.

The resulting number1464661369000 will NOT fit into an int32_t ('long') on Arduino 8-bit Atmegas.

The number will also NOT fit into an uint32_t

The number will only fit into 64-bit integer tpyes.

These 64-bit integer types are supported on 8-bit Arduino Atmega platform:

  • int64_t (signed 64-bit int)
  • uint64_t (unsigned 64-bit int)
  • long long (signed 64-bit int)

These three can hold number 1464661369000 easily.

If you are able to calculate unixtime 1464661369 correctly, then you could get a resulting number which is 1000 times as much like that;

long epoch=1464661369; // epoch of type 'long' is a 32-bit integer type

long long posix=epoch; // define posix is now a 64-bit integer type

posix*=1000; // multiplication by 1000 is possible without overflow

As easy as that you calculate milliseconds from seconds.

But most likely you then will run into the next problem;

While the 8-bit Arduino platform can define 'long long' variables and do integer math with them,
there isNO WAY TO PRINT such high numbers using built-in functions of AVR-GCC.

Do you need to print a number as high as 1464661369000 for formatted output?

If yes, then it would be up to you to write function which can print 'long long' numbers.

Otherwise you can take the 8 bytes of a long long and transfer them to a 64-bit platform which can do better handling of such large integer types.

Until now, this thread has quite a couple of messages, but until now I don't know whether you want to do the timestamp conversion for an 8-bit platform like Arduino UNO or for a 64-bit platform with a 64-bit compiler. Only 64-bit platforms might define an "int" to be 64 bits wide.

Thank for your help, but I become creasy, it does not work.

As I need to send the value
1482529805000
and not
1482529805

I can not use uint32_t. I could use uint64_t but my Serial.print() but, then I abadon uint32_t.

As my ajson funtion allow only int or double, I am concentrate on double.
However, I still have problem with decimal and to multiplace it by 1000.

Here is my try

get_posix(); // posix has the value of 1482529805
        double posi = (double)posix; // I convert to double
        posi = posi*1000; // I mulitplace by 100
        Serial.print(F(">>"));
        Serial.println(posi); // BUG, it display: >>ovf
        Serial.println("");
        printFloat(posi,0); // Of course the print is wrong, as the previous is wrong
        aJson.addNumberToObject(jobject1, "timestamp", posi); // Here posi must be 1482529805000 without . and decimal

Pls , I need a help :confused:

Here is my code:

// buff has the value of : 16/12/23,21:50:05+04
printPosix(buff);
void printPosix(char * buff)
{
  char format[23]="%d/%d/%d,%d:%d:%d+%d"; 
  int year,month,day,hour,minute,second,timezone;
  sscanf(buff,format,&year,&month,&day,&hour,&minute,&second,&timezone);
  if (year<100) year+=2000;

  // Here the prints are correct
  Serial.println(year);
  Serial.println(month);
  Serial.println(day);
  Serial.println(hour);
  Serial.println(minute);
  Serial.println(second);
  Serial.println(timezone);
  
  

  long epoch=0;
  for (int yr=1970;yr<year;yr++)
  if (isLeapYear(yr)) epoch+=366*86400L;
  else epoch+=365*86400L;
  for(int m=1;m<month;m++) epoch+=daysInMonth(year,m)*86400L;
  epoch +=(day-1)*86400L;
  epoch +=hour*3600L;
  epoch +=minute*60;
  epoch +=second;
  // epoch -=timezone*3600L; // It's semans to be wrong
  // epoch -=timezone*900L;

  Serial.print(F("POSIX time:"));
  Serial.println(epoch); 
  posix = (float)epoch;
}

POSIX time:1482529805
POSIX:1482529792.00

Thank a lot

@J-M-L
You gave me that code

Serial.println(buff);
  char posixe[]="16/12/22,00:01:23+04";
  struct tm tm;
  time_t epochUTC;
  if ( strptime(posixe, "%y/%m/%d,%T", &tm) != NULL ) {
    epochUTC = mktime(&tm); // I ignore the +04 piece may be you want to take this into account?
  } else {
  Serial.println(F("you have a bug with POSIX"));
  }
  Serial.print(F("POSIX time1:")); Serial.println(epochUTC);

epochUTC is a time_t. Can it be converted to double without decimal? (and with the 3 time 000 :slight_smile: )

Unix time (also known as POSIX time or Epoch time) is a system for describing instants in time, defined as the number of seconds that have elapsed since 00:00:00 Coordinated Universal Time (UTC), Thursday, 1 January 1970, not counting leap seconds.

==> So it's not milliseconds. It's usually represented as a long

Seems you json String needs 000 after the timestamp, so actually ms. You might want to explore GitHub - bblanchon/ArduinoJson: 📟 JSON library for Arduino and embedded C++. Simple and efficient. (see release notes for your architecture) or just build up your json manually with strcat() as it is most likely pretty simple

In fact, it's not y ajson you want to have 000, it's Ubidots (where the data is send), but I am using ajson to format the data.

My problem si to remove the decimal of a double and mutliply a double by 1000. :slight_smile:

I already had a look on ArduinoJson and may be I will look for it again, but I have first to find the way how to work around double anf format my value before sending it

store it in a long long and multiply by 1000 will add 3 zeros. in your architecture double are stored on 64 bits, a signed long long will represent from -9 223 372 036 854 775 808 to 9 223 372 036 854 775 807 so should be plenty... but probably won't print... What you want to build is really a char buffer with the right json format

Please don't cross post even in other languages.

pierrot10:
My problem si to remove the decimal of a double and mutliply a double by 1000. :slight_smile:

I think different. "'double" in 8-bit AVR/Atmega platform is not accurate enough to multiplicate such high number by 1000 and get an accurate result.

I think you better use 'long', and then do "decimal formatting with three trailing zeros for output.

Something like this (with epoch being a 'long'):

epoch=1464661369;
char posixbuf[21];
sprintf(posixbuf,"%ld000",epoch);
Serial.println(posixbuf);

Posixbuf will then be formatted as a "nullterminated string", containing the number in decimal formatting with three trailing zeros. Can be printed easily to Serial, lcd or where you want it.

Hello
Thank,

But i convert it to char.

At the end I have to covert it to double without . and decimal

@Jurs - he is using an ATSAMD21G18 ARM Cortex M0 processor - so native support for 64 bit

Pierrot - look at the big picture. Your json at the end of the day is sent as a char buffer to the server for decoding. So build the buffer and send it over.

Something simple like this {"temperature": 10, "humidity": 50}

Why do you think your timestamp is needed in that format by the way? (The doc says it's optional)

Ok, my problem is solved even if it's not :slight_smile:

I explain.

I need to send data to ubidots. The data must be in Json format.
I can fomrat all of the data excepted the date and time. The date and time must be sent in POSI format.

To answer to J-M-L question. Yes I saw that is optional, but all my program worj with UTC time and I think it's important to work with once time reference. First all if you are not in EU.
If you do not specify a time to Ubidots, the automaticaly save a date/time, but local time and not UTC

Secondly, the time is time when the localisation is save and sent.
If there is an error with the network and data is sent 2 hours or more later, the time must be the time when the localisation has been measured and not when it has been save to Ubidots. If I do not specify a time, Ubidots will save time when Ubidots record it and when it has been measured.

It the reasin why I need to send the POSIX time.

Now, I become really creasy, because I was sure the POSIX time must be a double for UBIDOTS.
Here is the Ubidots exemple:

{"temperature": {"value":10, "timestamp": 1464661369000, "context":{"lat":-6.2, "lng":75.4, "my-key":"hello there"}}, "humidity": 50}

As you see, it's

"timestamp": 1464661369000

the string format is for exemple

"Qality": "Good"

I jsut tried to save in json format as the following

aJson.addStringToObject(jobject1, "timestamp", "1482590461000");

Which will give me that result
"position":{"value":0,"timestamp":"1482590461000","context":

{"lat":46.21984,"lng":6.14123,"IMEI":"865067020750000","Battery":97,"Quality":"GSM","Tower":"228,03,1771,2d6f,45,37"}},"battery":97}

I check the Ubidots interface and the data has been saved with the good time!!!!!!!!

So at the end. I spent a lot of time to work around double of int32, while String was fully enough! (GRRRRRRRRRRRRRRRRRRR).

I may be badly read to Ubidots doc, but I have been confuse with

"timestamp": 1464661369000

I have to leave now, but I will provide my full code, in case it can help some one who want to work with Ubidots.

I also will try my result more later.

Thank a lot to all of you for your help!

Here is my code

I have a function get_time() wich will send a AT command to get the UTC time.
The time is save in a buff char varaiable. I add the following to the function to save the POSIX time in a glocal varail

#define POSIXTIMESIZE 15
char posix_time[POSIXTIMESIZE];

I set my posix time as the following

void printPosix(char * buff)
{
  // gsm_time format: "16/12/21,00:01:23-08";
  char format[23]="%d/%d/%d,%d:%d:%d+%d"; 
  int year,month,day,hour,minute,second,timezone;
  sscanf(buff,format,&year,&month,&day,&hour,&minute,&second,&timezone);
  if (year<100) year+=2000;

/*
  Serial.println(year);
  Serial.println(month);
  Serial.println(day);
  Serial.println(hour);
  Serial.println(minute);
  Serial.println(second);
  Serial.println(timezone);  
*/
  long epoch=0;
  for (int yr=1970;yr<year;yr++)
  if (isLeapYear(yr)) epoch+=366*86400L;
  else epoch+=365*86400L;
  for(int m=1;m<month;m++) epoch+=daysInMonth(year,m)*86400L;
  epoch +=(day-1)*86400L;
  epoch +=hour*3600L;
  epoch +=minute*60;
  epoch +=second;

  // epoch -=timezone*3600L; // It's semans to be wrong
  // epoch -=timezone*900L;

  //Serial.print(F("POSIX time:"));
  //Serial.println(epoch); 

  memset(posix_time,'\0',POSIXTIMESIZE);
  sprintf(posix_time,"%ld000",epoch);
  //Serial.print(F("POSIX time char:"));
  //Serial.println(posix_time);
}

byte daysInMonth(int yr,int m)
{
  byte days[12]={31,28,31,30,31,30,31,31,30,31,30,31};
  if (m==2 && isLeapYear(yr)) return 29;
  else return days[m-1];
}
bool isLeapYear(int yr)
{
  if (yr % 4 == 0 && yr % 100 != 0 || yr % 400 == 0) return true;
  else return false;
}

the printPosix() function will ave the POSIX time in posix_time variable.
then I format the dat in json format:

aJson.addStringToObject(jobject1, "timestamp", posix_time);

and here the full json string:

{"position":{"value":0,"timestamp":"1482589698000","context":{"lat":46.21984,"lng":6.14123,"IMEI":"865067020750000","Battery":99,"Quality":"GSM","Tower":"228,03,1771,2d6f,45,38"}},"battery":99}

It works fine.

I am relly sorry to have take so much of your time, but in any case, you helped me a lot.

I wish you a very good Christmas time with your family and friends!

NB: If someone would like to know how I used MQTT protocol to send data to Ubidots, feel you free to ask, because there is no doc.

Cheers

Merry Christmas - glad you solved it! (Make sur it's interpreted server side as a number and not a string though). Also we would recommend not using the String class on your arduino (or carefully)

Hello
Sorry to come back but I have to adapt my code and there is a part I can not explain.

For some case, I have to do it

sprintf(posix_time,"%ld000",epoch);

(It's add 000)

For soem case, I do not have to have the 000.

I suppose I can siimply do it

#ifdef BIPME
    sprintf(posix_time,"%ld",epoch);
  #else
    sprintf(posix_time,"%ld000",epoch);
  #endif

I just wundering what is the '%ld' (ld)

I checked the doc for sprintl, I can not find info regardin ld

Thank a lot

I just wundering what is the '%ld' (ld)

You can read the specification for the format string

l is the length sub-specifier-> modifies the length of the data type
d --> Signed decimal integer

the 0s after %ld are not part of the format. They are just printed as part of the output, so you add 3 zero after printing a signed long int

Ok, thank JML. Have a nice day!!

Cheers

Even though I #include <time.h> library, I dont get following function: strptime
'strptime' was not declared in this scope

I can however use the mktime.
Was that feature removed from the library? It's weird to see old posts working with it fine.
I am using Arduino 1.8.5

mangelozzi:
Even though I #include <time.h> library, I dont get following function: strptime
'strptime' was not declared in this scope

I can however use the mktime.
Was that feature removed from the library? It's weird to see old posts working with it fine.
I am using Arduino 1.8.5

I have the same problem.