Leading zeros for seconds coding

Hi,

I want the time to display a constant number of digits. Therefore I require a leading zero in front of the seconds.

The code I've written is as follows:

if (now.second() < 10) 
{String thisSecond("0" + now.second());}
String thisSecond = String(now.second(), DEC);

However, this always returns a value without the leading zero when the seconds are less then 10.
Any ideas how to sort out this problem?

I want to do the same for month, day, hour and minute as well but this should be easy once I've got it sorted out for the seconds.
Cheers,

Luc

You're naming two variables the same name. The one inside the braces is local to there and goes out of scope immediately. The second one is the only one avaialable anywhere else.

Why mess with String at all? Print is perfectly capable of printing numbers.

if(now.second() < 10){
    Serial.print("0");
}
Serial.print(now.second());

Replace Serial.print with whatever you are using for display.

Thank you very much Delta_G for the fast response and excellent explanation.

I should have given a bit more information. (My mistake).

I want to create a global date and time string which can then be called from other functions. Therefore I want to add the leading zero before I create the string.

Here is an extended version of the code:

Serial.print(now.second()); 
{String thisSecond("0" + now.second());}
String thisSecond = String(now.second(), DEC);
//Put all the time and date strings into one String
DateAndTimeString = String(thisYear + "-" + thisMonth + "-" + thisDay + " " + thisHour + ":" + thisMinute + ":" + thisSecond);
Serial.println(DateAndTimeString);

For this reason there I've to manipulate the thisSecond string so that a leading zero will appear when needed.
Cheers,

Luc

Don't use big-S strings. They're awfully bad for the Arduino. Here's an example using a small-s string.

#include <strings.h>
//Put this declaration at the top of your program outside every function so it's global
char DateAndTimeString[20]; //19 digits plus the null char
...

  sprintf(DateAndTimeString, "%4d-%02d-%02d %d:%02d:%02d", thisYear, thisMonth, thisDay, thisHour, thisMinute, thisSecond);

%d is a placeholder for a (decimal) integer of variable length. It can be modified to print a specific length by adding the number of characters in front of the "d". Then the padding for short numbers will be spaces unless you then add a zero in front of that to show you want it padded with zeros. %02d will print who digits, padded with a zero as required.

1 Like

Or even better:-

sprintf_P(DateAndTimeString, PSTR("%4d-%02d-%02d %d:%02d:%02d"), thisYear, thisMonth, thisDay, thisHour, thisMinute, thisSecond);

Edit: I should have added, this stores the format string in program memory instead of RAM.

Thanks for the tips MorganS and OldSteve! Much appreciated!

I'm actually more confused now for following reasons:

"Don't use big-S strings. They're awfully bad for the Arduino."; Why are they so bad for the Arduino?
Can they physically destroy the chip?

"#include <strings.h>" ; My compiler tells me: "fatal error: strings.h: No such file or directory"
A search on the internet tells me that such a library doesn't exists as it is already part of the IDE (I use 1.6.6) but that doesn't seems to be the case.
Where can I find this library?

sprintf_P(DateAndTimeString, PSTR("%4d-%02d-%02d %d:%02d:%02d"), thisYear, thisMonth, thisDay, thisHour, thisMinute, thisSecond);" This line of code has made me completely confused. My knowledge of programming is not up to this level and I have to copy as is. However it wasn't accepted by the compiler and have no idea how to correct this.
I can understand the mask but struggle with sprintf_P and the PSTR in front of the mask.
Could you point me in a direction where I can read more about these commands?

It that would be extremely helpful if you could elaborate on it .
Cheers!

Luc

sprintf_P(DateAndTimeString, PSTR("%4d-%02d-%02d %d:%02d:%02d"), thisYear, thisMonth, thisDay, thisHour, thisMinute, thisSecond);"

What error do you get when you compile the code ?
Have you actually got quotation marks on the end of the statement or is that a copy/paste error ?

Hi UKHeliBob,

I'm not in front of Arduino work station but the compiler throws a fault about the strings.h library. Something in the order that Strings is not recognized.
The quotation marks are not part of the code. I just used them to differentiate between code and explanatory text.
Cheers,

Luc

LRAT:
Hi UKHeliBob,

I'm not in front of Arduino work station but the compiler throws a fault about the strings.h library. Something in the order that Strings is not recognized.
The quotation marks are not part of the code. I just used them to differentiate between code and explanatory text.
Cheers,

Luc

  1. The "String" class can cause memory issues, fragmentation in particular, and is not recommended.
    It's much better to use C strings, (char arrays), with the standard C library functions for manipulation.

  2. You don't need to include any libraries. It should compile fine without. As Bob asked, what error did you get?
    I compiled that example using your variables before I posted it - it definitely works. And just did it again - see below.

  3. 'sprintf_P()' does exactly the same as 'sprintf()', but the format string is stored in program memory rather than in RAM, conserving precious RAM. Much like using the 'F' macro for string literals. The PSTR() just casts the char array to a Pointer to STRing, as required when using the _P version of the library functions.
    Nick Gammon has kindly provided some explanations and examples of F() and ..._P(), along with 'PROGMEM' here:-PROGMEM

Load, compile and run this. (Tested on UNO with IDE V1.6.5):-
Edit: You might want to change the baud rate, but it works fine for me at 115200.

char DateAndTimeString[20]; //19 digits plus the null char
int thisYear = 2016;
int thisMonth = 1;
int thisDay = 11;
int thisHour = 9;
int thisMinute = 9;
int thisSecond = 30;

void setup()
{
    Serial.begin(115200);
    sprintf_P(DateAndTimeString, PSTR("%4d-%02d-%02d %d:%02d:%02d"), thisYear, thisMonth, thisDay, thisHour, thisMinute, thisSecond);
    Serial.println(DateAndTimeString);
}

void loop() {}

Edit2: There's a bit more info on format strings here:- sprintf_P formating questions. - #6 by system - Programming Questions - Arduino Forum

When people say "little s string" they mean "character array", not a "string" class. So, there is no "string.h".

String objects simply take up more memory, and are slow to append, so for low memory systems it is generally better to avoid them.

LRAT:
Hi,

I want the time to display a constant number of digits. Therefore I require a leading zero in front of the seconds.

The code I've written is as follows:

if (now.second() < 10) 

{String thisSecond("0" + now.second());}
String thisSecond = String(now.second(), DEC);

Don't use String at all. Do it the right way (example assumes you are printing the full time):

char buffer [16];
uint8_t sec, min, hour;
sec = now.second();
min = now.minute();
hour = now.hour();
sprintf (buffer, "Time: %02u:%02u:%02u\n", hour, min, sec);
Serial.print (buffer);

The "%02u" means "print an unsigned integer with 2 places, fill with leading zero if necessary". So, the code above would print something like this:

[b]"Time: 07:41:03"[/b]

--or--

[b]"Time: 15:24:07"
[/b]

If you leave off the zero in the hours place format string (i.e. use "%2u"), then means "print with two places" and the result would then be this:

[b]"Time:  7:41:03"[/b]

--or--

[b]"Time: 15:24:07"[/b]

Now, "buffer" has to be declared large enough to hold your string, and it doesn't hurt to add a few more just in case. For example, the strings above take up 6 (for "Time: ") plus 8 (for XX:XX:XX) plus 1 for the newline character plus 1 for the ending null (0) character which is 6 + 8 + 1 + 1 = 16 which is why I chose "buffer[16]" and maybe "buffer[24]" would have been even safer (unless you are short on RAM).

Hope this helps.

(edit): Sorry OldSteve basically gave you the same info. Sorry for the duplicate.

I will add though that using PROGMEM strings is more complicated and only really needed if you are dealing with a LOT of string data and running out of SRAM. For small strings and/or just a few strings to print, just use standard "sprintf". For a large number of strings, use OldSteve's example of PROGMEM strings.

So, there is no "string.h".

Well, there is, but it is included automatically, as part of Arduino.h. It contains all the function prototypes for the string handling functions like strcmp, strtok, etc.

arduinodlb:
When people say "little s string" they mean "character array", not a "string" class. So, there is no "string.h".

String objects simply take up more memory, and are slow to append, so for low memory systems it is generally better to avoid them.

May I also suggest trying out my "Stdinout" Arduino library which adds the ability to easily use standard input, standard output and standard error directly in Arduino.

For example, to print the time, ALL that would be needed is this:

Serial.begin (115200); // same as always
STDIO.open (Serial); // connect serial port to stdin/stdout/stderr
printf ("Time: %02u:%02u:%02u\n", hour, min, sec);

Get it here: GitHub - krupski/Stdinout: Standard input/output/error support for Arduino

Simply unzip the master file into "libraries", then at the top of a sketch use "[b]include <Stdinout.h>[/b]" or better yet, add it directly to the Arduino.h master header so it will always be available. It takes NO memory unless actually used, so there's no reason not to include it directly in Arduino.h.

PaulS:
Well, there is, but it is included automatically, as part of Arduino.h. It contains all the function prototypes for the string handling functions like strcmp, strtok, etc.

Actually, that stuff is provided by stdio.h.

PaulS:
Well, there is, but it is included automatically, as part of Arduino.h. It contains all the function prototypes for the string handling functions like strcmp, strtok, etc.

Well, :slight_smile:

PaulS:
Well, there is, but it is included automatically, as part of Arduino.h. It contains all the function prototypes for the string handling functions like strcmp, strtok, etc.

Krupski:
Actually, that stuff is provided by stdio.h.

Not so. As Paul said, 'strcmp()', 'strtok()' etc are in "string.h", not "stdio.h", as are 'strcat()', 'strlen()' etc.
But 'sprintf()', 'sprintf_P()', 'scanf()', 'scanf_P()' etc are in "stdio.h".

Confusing, I know, (or at least it is to me). But at least they're included automatically. :slight_smile:

Edit: All can be found here, (on my system at least):-
"C:\Program Files\Arduino\hardware\tools\avr\avr\include"

OldSteve:
Not so. As Paul said, 'strcmp()', 'strtok()' etc are in "string.h", not "stdio.h", as are 'strcat()', 'strlen()' etc.
But 'sprintf()', 'sprintf_P()', 'scanf()', 'scanf_P()' etc are in "stdio.h".

... and the strxxx_P() versions are in <avr/pgmspace.h>.

oqibidipo:
... and the strxxx_P() versions are in <avr/pgmspace.h>.

Thanks for that. I was wondering where they were hidden. Only the versions without _P are in "string.h".

And the winner is..... Krupski!
Thank you Krupski, your code was exactly what I was after but I also used some parts of OldSteve's code.
Many thanks for all the excellent replies.

For all other readers:
Krupski's code was showing the code to generate a time string. As I wanted to extend it to a date as well I ran into a problem.
My code was designed to show the year-month-day hour:minute:second. Most worked well but the year 2016 showed as 224. It took me a while to work it out but eventually the penny dropped. The year contained 4 digits and therefore I had to increase the data allocation from 8 bits to 16 bits.
The code produces three strings. The longest string doesn't fit on a single line on an LCD display. That's why I generated two shorter strings which can be placed on two lines of the LCD-display.
This is my code snippet as is:

char DateAndTimeString[21]; //20 digits plus the null char
char DateAndTimeDate [10];
char DateAndTimeTime [10];

void RealTimeClock()
{
DateTime now = RTC.now();  // Read data from the RTC Chip
uint16_t ThisYear;
uint8_t ThisMonth, ThisDay, ThisHour, ThisMin, ThisSecond;
ThisYear = now.year();
ThisMonth = now.month();
ThisDay = now.day();
ThisHour = now.hour();
ThisMin = now.minute();
ThisSecond = now.second();
sprintf_P(DateAndTimeString, PSTR("%4u-%02u-%02u %02u:%02u:%02u"), ThisYear, ThisMonth, ThisDay, ThisHour, ThisMin, ThisSecond);
sprintf_P(DateAndTimeDate, PSTR("%4u-%02u-%02u"), ThisYear, ThisMonth, ThisDay);
sprintf_P(DateAndTimeTime, PSTR("%02u:%02u:%02u"), ThisHour, ThisMin, ThisSecond);
Serial.println (DateAndTimeString);
}

I hope this could be useful to others.
Thanks to all contributors. This thread is now closed.
Cheers,

Luc

sprintf_P(DateAndTimeDate, PSTR("%4u-%02u-%02u"), ThisYear, ThisMonth, ThisDay);

4 + 1 + 2 + 1 + 2 + 1 is NOT 10.

DateAndTimeDate will not contain time information, so the name is stupid.

DateAndTimeTime will not contain date information, do the name is stupid.