Time format issues

Hi All,

I am in the process of converting all my String formats, which I use for publish strings, to snprintf in an attempt to optimise my code. I have a function that sends up some variables using publish, one of these variables is the time stamp.

I create the timestamp like below.

const char* timeStamp = Time.format(Time.now(), "%Y-%m-%d %H:%M:%S");

Then using the following snprintf to create a publish payload.

snprintf(s, sizeof(s), "{ \"f\": \"%.2f\", \"b\": \"%.2f\", \"t\": \"%s\", \"s\": \"%d\", \"Em\": \"%s\", \"r\": \"%d\", \"sd\": \"%d\"}", Freq, batt, timeStamp, bars, Em,reset,SD);

Now the weird thing is that when this code runs just after startup I get 3 garbage symbols as output, whereas when the same code runs 10 mins later it creates the correct Timestamp.

So I figured maybe I am calling the Time.now() to soon after connecting, so I tried the following:

if (Particle.connected()) CLOUD_HAS_CONNECTED = TRUE;
	Particle.syncTime();
	if(waitFor(Particle.syncTimeDone,10000)){
		storeSysReadings(!useSD,resetLocation); // this is the function that creates my publish payload and publishes
	}

The storeSysReadings function creates the publish payload and publishes. So it should be connected with the time synced prior to sending up troublesome event. Does anyone have any idea what could be causing this? Thanks

EDIT:
I have also tried casting the Time.format with no success

const char* timeStamp = (const char*)Time.format(Time.now(), "%Y-%m-%d %H:%M:%S");

@StngBo ,

A simpler approach might be to use the Time Format API:

https://docs.particle.io/reference/device-os/firmware/#format-

My first guess with the issue would have been the syncTime but you have resolved that.

Chip

1 Like

Could you try this instead

  snprintf(s, sizeof(s)
          , "{ \"f\": \"%.2f\", \"b\": \"%.2f\", \"t\": \"%s\", \"s\": \"%d\", \"Em\": \"%s\", \"r\": \"%d\", \"sd\": \"%d\"}"
          , Freq
          , batt
          , (const char*)Time.format("%F %T")
          , bars
          , Em
          , reset 
          , SD);

This seems to fix it, any idea why, just out of interest.

I believe the reason why is that Time.format() returns a temporary String object, but objects returned from functions or methods go out of scope immediately after the value is returned.

This should work:

String timeStamp = Time.format(Time.now(), "%Y-%m-%d %H:%M:%S");

if you also use (const char *)timeStamp as the parameter to snprintf.

The reason why this works is that String timeStamp allocates storage for the copy with a lifetime of its current scope which lasts until the outer function returns, well past its use in sprintf.

What you did originally is take a pointer to the temporary string, which is then deallocated. Sometimes it works because nothing has overwritten it yet, but other times the memory pointed to by const char *timeStamp gets overwritten and you get garbage characters.

3 Likes

Ok that makes sense. Thank you

Haha, thats the way I had it working originally, but trying to move away from String as much as possible.

Just as a side-note: When using the current time I’d rather use Time.xxx() methods without the Time.now() parameter as the omission of it will default to current time anyhow.
This will also remove the confusion of whether to use Time.now() of Time.local() which frequently trips up users :wink:

2 Likes

Hi,

there is also something that can be getting you that result. The time could be invalid at startup until the device syncs it with the cloud.
You could verify this is the case with something like this:

Log.info("Time.isValid(): %s ", Time.isValid() ? “yes” : “no”);

The docs mention you can also add this in setup():

void setup()
{
  // Wait for time to be synchronized with Particle Device Cloud (requires active connection)
  waitFor(Time.isValid, 60000);
}

Best of luck!

1 Like