Sort time into hⓂs- how to make two digits?

Hi, I'm making a small apparatus to log the time each team holds a flag in paintball games. The time is logged in ms, but needs to be displayed in h:m:s. So I made this code:

unsigned long team1Time; //containers for the logged time of each team in ms
unsigned long team2Time;
unsigned long team3Time;

void setup(){
  Serial.begin(9600);
  Serial.println("Timesort code");
}

void loop(){
  team2Time = millis(); //added for trying out the code
  Serial.println(timeSort(team2Time));
  delay(1000); //to do: find a way to do this without delay()
}

String timeSort(unsigned long teamTimeX){
  int totalsec= teamTimeX/1000; //gives the total number of seconds
  int totalmin= totalsec/60;
  int totalhour= totalmin/60;

  String s = String(totalsec%60); //calculates the nr of minutes and shifts them up to h when they reach 60
  String m = String(totalmin%60); //calculates the nr of minutes and shifts them up to h when they reach 60
  String h = String(totalhour);
  String timeDisplay= String(h+":"+m+":"+s);
  return timeDisplay;
}

It works like a charm, but I'd really like the time to display in the format "00:00:00". The way it displays now, I get strings like "0:1:15" , that should be "00:01:15".

How do I achieve this?

I would suggest dropping Strings.

unsigned long team1Time; //containers for the logged time of each team in ms
unsigned long team2Time;
unsigned long team3Time;

void setup() {
  Serial.begin(115200);
  Serial.println(F("Timesort code"));
}
unsigned long lastPrint;

void loop() {
  if (millis() - lastPrint >= 1000) {
    lastPrint = millis();
    team2Time = millis(); //added for trying out the code
    Serial.println(timeSort(team2Time));
  }
}

void storeValue(char* to, int val, char behind) {
  *to++ = '0' + val / 10;
  *to++ = '0' + val % 10;
  *to++ = behind;
}
char* timeSort(unsigned long teamTimeX) {
  static char Buffer[10];
  int totalsec = teamTimeX / 1000; //gives the total number of seconds
  int totalmin = totalsec / 60;
  int totalhour = totalmin / 60;
  storeValue(Buffer, totalhour, ':');
  storeValue(Buffer + 3, totalmin % 60, ':');
  storeValue(Buffer + 6, totalsec % 60, 0);
  return Buffer;
}
Timesort code
00:00:01
00:00:02
00:00:03
00:00:04
00:00:05
00:00:06
00:00:07
00:00:08
00:00:09

Your version (which does not display what you want without adding some code)

Der Sketch verwendet 4.324 Bytes (14%) des Programmspeicherplatzes. Das Maximum sind 30.720 Bytes.
Globale Variablen verwenden 230 Bytes (11%) des dynamischen Speichers, 1.818 Bytes für lokale Variablen verbleiben. Das Maximum sind 2.048 Bytes.

My version that works and is more solid

Der Sketch verwendet 2.234 Bytes (7%) des Programmspeicherplatzes. Das Maximum sind 30.720 Bytes.
Globale Variablen verwenden 218 Bytes (10%) des dynamischen Speichers, 1.830 Bytes für lokale Variablen verbleiben. Das Maximum sind 2.048 Bytes.

How do I achieve this?

First piece of advice. Don't use Strings. You have perfectly good variables containing seconds, minutes and hours so you could do something like this

char buffer[10];
int hours;
int minutes;
int seconds;

void setup()
{
  Serial.begin(115200);
}

void loop()
{
  seconds = millis() / 1000;
  minutes = seconds / 60;
  hours = minutes / 60;
  sprintf(buffer, "%02d:%02d:%02d", hours, minutes % 60, seconds % 60);
  Serial.println(buffer);
}

There are several refinements that can be made but it may give you some ideas

Bob’s absolutely correct: the String class bloats your code. Bob’s example compiles to 3696 bytes which I’m sure is less than the String version. However, sprintf() is a very powerful and flexible function and most programs only use a small fraction of its usefulness. The code below does the same thing, but compiles to 2610 bytes:

char buffer[10];
int hours;
int minutes;
int seconds;

void setup()
{
  Serial.begin(115200);
}

void loop()
{
  char temp[5];
  seconds = millis() / 1000;
  minutes = seconds / 60;
  hours = minutes / 60;

  myFormat(hours, 0);
  myFormat(minutes % 60, 1);
  myFormat(seconds % 60, 2);
  
//  sprintf(buffer, "%02d:%02d:%02d", hours, minutes % 60, seconds % 60);
//  Serial.println(buffer);
}

void myFormat(int val, int place)
{
  if (val < 10)               // Need the padding?
    Serial.print("0");
  Serial.print(val);

  if (place < 2)              // Last field?
    Serial.print(":");
  else
    Serial.println();
}

Thanks, excellent replies!

However, some of you overestimates my knowledge of C++. I'm a beginner. I really don't get the sprintf function, and googling for tutorials doesn't help me much since they seem to be written for people who know a lot more code than I do. I would very much like to learn though, so if anyone think they can explain it in a comprehensible way to newbie, I would be so grateful.

I do get the code provided by econjack, and combined with the if lastprint- statement in Whandalls code it will work perfectly!

I also wonder about the use of the asterix in *to++. What does it do? And I dont get the use of the buffer array. Sorry for unspecific and basic questions.

*to++ = ':';

Means: take the pointer to, store a ‘:’ where it points to and then increment the pointer.

For only two digits, and especially if you always print a leading zero, it is easier to just write a routine to print it.

I like [u]this[/u] post on sprintf.

Hutkikz:
I like [u]this[/u] post on sprintf.

And so do I. Its EXACTLY what I was looking for, and through it I even found a good, comprehensible text about pointers, that I didn´t know about either:

http://home.netcom.com/~tjensen/ptr/ch1x.htm

This has been more than helpful, its been educational. Love this forum. Thanks everyone.

Just one more thing though... In the codes above and in every tutorial on sprint, there´s the expression %d. What does that mean? The only use for % I know is as the modulo operator, but this seems to be something else?

Have a look at vsprintf.

there´s the expression %d. What does that mean?

from the link I posted above.

A format string is just a string.
First I want to output integer (not float or else), so integer output is “%d”, or “%ld” for long integer.
Next I want 2 digit integer so “%2d”, or “%4d” if I wanted 4 digit integer.
Next I want to keep leading zero so my time looks right, so”%02d”. If I used “%2d” then leading spaces are provided so I get 13:(space)2:(space)0

Now I’m done with format string, it’s time to call the sprintf:

char[9] buffer=""; ///< This is the buffer for the string the sprintf outputs to

sprintf(buffer, “%02d:%02d:%02d”, hour, min, sec); ///< This has 3 2-digit integers with leading zeros, separated by “:” . The list of parameters, hour, min, sec, provides the numbers the sprintf prints out with.

lcd.print(buffer); ///< You will get “13:02:00”




This will get you:

13:02:00