Leading zeros for seconds coding

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.

PaulS,

I've got no idea what you're on about!
To call things stupid on this forum is not the most constructive advice one can give.

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

The number of characters in the formatted string compared with the size of the array you are putting them in.

Thanks UKHeliBob,

That's a proper explanation. Yes, you're right. I've forgotten the null and therfore it should be char [11].
Cheers!

LRAT:
PaulS,

I've got no idea what you're on about!
To call things stupid on this forum is not the most constructive advice one can give.

Whilst I don't always agree with PaulS', ahem, forceful language, his approach is, IMO, impeccable.
He wrote the sum out very clearly after highlighting the problem area. The numbers in the sum were clearly visible.

Debugging very rarely carries an "X-marks-the-spot" label, so if you want to succeed, get used to hints and pointers and a little bit of looking sideways at the problem.

if you want to succeed, get used to hints and pointers and a little bit of looking sideways at the problem.

Think about maintainability, too. 6 months from now, you'll look at that code and wonder just what the heck you were smoking when you named those variables.

OP: I did NOT say that you were stupid, I said the name of the variable was stupid. Big difference, IMHO.

hi there... a bit of a newbie. I want to do the same thing - ensure leading zero's. I've copied this code which works fine to display day/date and time but no leading zeros looks ugly! What can I do to modify this code?

/*

  • Connections
  • connect SDA of the RTC with A4
  • connect SCL of the RTC with A5
    */

#include <LiquidCrystal.h>
#include <Wire.h>
#include "RTClib.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

RTC_DS3231 rtc;

char daysOfTheWeek[7][4] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};

int Day;
int Month;
int Year;
int Secs;
int Minutes;
int Hours;

String dofweek; // day of week

String myDate;
String myTime;

// for the 16x2 LCD

#define rs 9
#define en 8
#define d4 7
#define d5 6
#define d6 5
#define d7 4
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

void setup ()
{

Serial.begin(9600);
lcd.begin(16, 2);
delay(3000); // wait for console opening

if (! rtc.begin()) {
Serial.println("Couldn't find RTC");
while (1);
}

if (rtc.lostPower()) {
Serial.println("RTC lost power, lets set the time!");

// Comment out below lines once you set the date & time.
// Following line sets the RTC to the date & time this sketch was compiled
rtc.adjust(DateTime(F(DATE), F(TIME)));

// Following line sets the RTC with an explicit date & time
// for example to set January 27 2017 at 12:56 you would call:
// rtc.adjust(DateTime(2017, 1, 27, 12, 56, 0));

}

void loop() {}

}
}

void loop ()
{
DateTime now = rtc.now();

//char buf[50];
//sprintf(buf, "%2d:%2d:%2d %2d:%2d:%2d", now.day(), now.month(), now.year() % 10, now.hour(), now.minute(), now.second());
//Serial.println(buf);

lcd.clear();

char buf[16];

Day = now.day();
Month = now.month();
Year = now.year();
Secs = now.second();
Hours = now.hour();
Minutes = now.minute();
dofweek = daysOfTheWeek[now.dayOfTheWeek()];
myDate = myDate +dofweek+ " "+ Day + "/" + Month + "/" + Year ;
myTime = myTime + Hours +":"+ Minutes +":" + Secs ;

// send to serial monitor

Serial.println(dofweek);
Serial.println(myDate);
Serial.println(myTime);
//Print on lcd
lcd.setCursor(0,0);
lcd.print(myDate);
lcd.setCursor(0,1);
lcd.print(myTime);
myDate = "";
myTime = "";
delay(1000);
}

@loma888

Please ask ‘your’ questions in ‘your’ own thread, click the ‘NEW TOPIC’ button in the appropriate forum.

You can change this for your LCD.

 void printDigits(byte digits)
  {
  // prints a leading 0
  if (digits < 10)
  {
    Serial.print('0');
  }
  Serial.print(digits);
  }