Issue with sprintf when formatting a date string

Using Arduino 1.6.5 with Uno board I have set the time (Time library) and am able to see that it is set properly. I am trying to format a date/time string with the following code:

char dateString[32];

sprintf(dateString, "%s %s %d, %d ", dayShortStr(weekday()), monthShortStr(month()), day(), year());

but the output from Serial.println(dateString);

is:

Fri Fri 25, 2015

If I change the order of dayShortStr and monthShortStr the output becomes

Dec Dec 25, 2015

Anyone have a hint as to why this is happening?

swrocks253: Using Arduino 1.6.5 with Uno board I have set the time (Time library) and am able to see that it is set properly. I am trying to format a date/time string with the following code:

char dateString[32];

sprintf(dateString, "%s %s %d, %d ", dayShortStr(weekday()), monthShortStr(month()), day(), year());

but the output from Serial.println(dateString);

is:

Fri Fri 25, 2015

If I change the order of dayShortStr and monthShortStr the output becomes

Dec Dec 25, 2015

Anyone have a hint as to why this is happening?

Post all of your code, not just those snippets.

And please post it within code tags, not inline as you've done. See item #7 here:- How to use this forum

1 Like

dayShortStr() and monthShortStr() return a pointer to the same internal buffer, so you get the result of the function that was called last in duplicate.

#define dt_MAX_STRING_LEN 9
#define dt_SHORT_STR_LEN  3

static char buffer[dt_MAX_STRING_LEN+1];

const char monthShortNames_P[] PROGMEM = "ErrJanFebMarAprMayJunJulAugSepOctNovDec";
const char dayShortNames_P[] PROGMEM = "ErrSunMonTueWedThuFriSat";

char* monthShortStr(uint8_t month)
{
   for (int i=0; i < dt_SHORT_STR_LEN; i++)
      buffer[i] = pgm_read_byte(&(monthShortNames_P[i+ (month*dt_SHORT_STR_LEN)]));
   buffer[dt_SHORT_STR_LEN] = 0;
   return buffer;
}

char* dayShortStr(uint8_t day)
{
   uint8_t index = day*dt_SHORT_STR_LEN;
   for (int i=0; i < dt_SHORT_STR_LEN; i++)
      buffer[i] = pgm_read_byte(&(dayShortNames_P[index + i]));
   buffer[dt_SHORT_STR_LEN] = 0;
   return buffer;
}

Edit: oqibidipo was faster ;)

In my opinion it's a bad coding practice.

You can solve this by first copying the result of each function into two different char arrays, and use these char arrays in the sprintf call.

You shouldn’t use sprintf . . . if you must use C strings at least use snprintf.

if you must use C strings

Which you must unless you are a lazy, clueless idiot...

You shouldn't use sprintf . . . if you must use C strings at least use snprintf.

If you're going to use any flavour of sprintf, it should have a "_P" suffix.

You can build the string in two pieces.

   sprintf(dateString, "%s ", dayShortStr(weekday()));
    sprintf(dateString[strlen(dateString)], "%s %d, %d ", monthShortStr(month()), day(), year());

And add a _P suffix as, and when, necessary :)

Pete

PaulS: Which you must unless you are a lazy, clueless idiot...

That is so wrong!

No professional C++ programmer would ever use C strings in a desktop application, and most high integrity coding standards prohibit C string functions in embedded applications too. It's safer, faster and easier to use string classes. C strings are a major source of software reliability issues and security vulnerabilities.

I cannot understand why C strings are so strongly advocated, not when there's viable alternatives.

The thing is, there aren't too many professional C++ programmers working on RAM-deficient architectures, like AVRs.

AWOL: The thing is, there aren't too many professional C++ programmers working on RAM-deficient architectures, like AVRs.

I'm not sure what you mean by that. Are you suggesting string classes are too RAM intensive for AVRs? StaticString uses only the number of byte specified by the template parameter plus another 4 bytes. There are no dynamic allocations. A 100 character long string will always consume 104 bytes (on all architectures, too). The benefit, of course, is that you get clean easy syntax and immunity to buffer overruns. That's great for both professionals and n00bs provided they can live with the extra 4 bytes.

I cannot understand why C strings are so strongly advocated, not when there's viable alternatives.

Obviously, you have not looked at the String class. EVERYTHING it does is based on C string handling. What it does that is so abhor ant is the way that it deals with memory allocation. Every time a character is appended to a String, memory is allocated, copied, and freed.

Other String classes at least allocate additional memory in larger chunks, resulting in less memory fragmentation.

Thanks for the help guys! Got it working correctly by creating a local copy of the returned data.

PaulS: Which you must unless you are a lazy, clueless idiot...

Lighten up PaulS! It's a small personal project, not intended for production release!

PaulS: Obviously, you have not looked at the String class. EVERYTHING it does is based on C string handling. What it does that is so abhor ant is the way that it deals with memory allocation. Every time a character is appended to a String, memory is allocated, copied, and freed.

Other String classes at least allocate additional memory in larger chunks, resulting in less memory fragmentation.

I see, so it's the Arduino String class in particular that you dislike and for reasons I understand and agree with. That's a relief - I didn't like being a clueless idiot. :)