Simple TimeLib formatting (HH:MM:SS) and subtract hours question

From my below test sketch, the output is:
New Time: 7:30:0 on 2/23/2025

I would like to format the time as HH:MM:SS, or at least H:MM:SS, and subtracting 6 hours from setTime(1, 30, 0, 23, 2, 2025) should land on 22, 2, 2025 right?
"format" is not allowed, "fread" suggested by compiler doesn't work. Seems like TimeLib isn't subtracting Day based on the number of hours subtracted.

My searches are not finding the solution or example, any ideas for the correct method/syntax appreciated?

#include <TimeLib.h>

void setup() {
  Serial.begin(9600);
  // Set the current time (e.g., 22nd February 2025, 19:20:00)
  setTime(1, 30, 0, 23, 2, 2025);

  // Number of hours to subtract
  int qtrs = -24; // CST difference from GMT
  //int hrs = qtrs/4; 
  int hoursToSubtract = qtrs/4;
  

  // Calculate the new time
  time_t newTime = now() - (hoursToSubtract * SECS_PER_HOUR);

   // Print the new time
  Serial.print("New Time: ");
  Serial.print(hour(newTime));
  Serial.print(":");
  Serial.print(minute(newTime));
  Serial.print(":");
  Serial.print(second(newTime));
  //Serial.print(fread("%02d", second(newTime)));  //(second(newTime));
//String formattedTime = String(format("%02d:%02d:%02d", hour, minute, second));
  Serial.print(" on ");
  Serial.print(month(newTime));
  Serial.print("/");
  Serial.print(day(newTime));
  Serial.print("/");
  Serial.println(year(newTime));
}

void loop() {
  // Nothing to do here
}

Look at some of the time libraries; they will have examples that will put you on the right track.

Use sprintf(). Here is an example I put together:

//time_make_and_add
#include <TimeLib.h>

tmElements_t te;  //Time elements structure
time_t unixTime; // a time stamp

void setup() {
  Serial.begin(115200);
   // new internal clock setting.
  // convert a date and time into unix time, offset 1970
  te.Second = 0;
  te.Hour = 23; //11 pm
  te.Minute = 0;
  te.Day = 1;
  te.Month = 1;
  te.Year = 2017-1970; //Y2K, in seconds = 946684800UL
  unixTime =  makeTime(te);
  Serial.print("Example 1/1/2017 23:00 unixTime = ");
  Serial.println(unixTime);
  setTime(unixTime); //set the current time to the above entered
  Serial.print("now() = ");
  Serial.println(now());
  // print as date_time
  print_date_time();
  // add
  unixTime += 7200UL; //add 2 hours
  setTime(unixTime);
  Serial.println("After adding 2 hours");
  Serial.print("now() = ");
  Serial.println(now());
  print_date_time();
}
void print_date_time() { //easy way to print date and time
  char buf[40];
  sprintf(buf, "%02d/%02d/%4d %02d:%02d:%02d", day(), month(), year(), hour(), minute(), second());
  Serial.println(buf);
}

void loop() {}

Safer, use snprintf() which won't overflow the output buffer:

 snprintf(buf, sizeof(buf), "%02d/%02d/%4d %02d:%02d:%02d", day(), month(), year(), hour(), minute(), second());

So neither this:

snprintf(buf, sizeof(buf), "%02d/%02d/%4d %02d:%02d:%02d", day(), month(), year(), hour(), minute(), second());

or this

snprintf(buf, sizeof(buf), "%02d/%02d/%4d %02d:%02d:%02d", day(newTime), month(newTime), year(newTime), hour(newTime), minute(newTime), second(newTime));

will not work with my existing code, correct?

With an argument and the snprintf you can do the offset on the fly:

//time_make_and_add
#include <TimeLib.h>

tmElements_t te;  //Time elements structure
time_t unixTime; // a time stamp

void setup() {
  Serial.begin(115200);
   // new internal clock setting.
  // convert a date and time into unix time, offset 1970
  te.Second = 0;
  te.Hour = 23; //11 pm
  te.Minute = 0;
  te.Day = 1;
  te.Month = 1;
  te.Year = 2017-1970; //Y2K, in seconds = 946684800UL
  unixTime =  makeTime(te);
  Serial.print("Example 1/1/2017 23:00 unixTime = ");
  Serial.println(unixTime);
  setTime(unixTime); //set the current time to the above entered
  Serial.print("now() = ");
  Serial.println(now());
  // print as date_time
  print_date_time();
  // add
  unixTime += 7200UL; //add 2 hours
  setTime(unixTime);
  Serial.println("After adding 2 hours");
  Serial.print("now() = ");
  Serial.println(now());
  print_date_time();
  print_date_time(now()+3600);
  print_date_time(now()+7200);
  print_date_time(now()+3600UL*48);
}

void print_date_time() { //easy way to print date and time
  char buf[40];
  sprintf(buf, "%02d/%02d/%4d %02d:%02d:%02d", day(), month(), year(), hour(), minute(), second());
  Serial.println(buf);
}
void print_date_time(time_t t) { //easy way to print date and time
  char buf[40];
  snprintf(buf,sizeof(buf), "%02d/%02d/%4d %02d:%02d:%02d", day(t), month(t), year(t), hour(t), minute(t), second(t));
  Serial.println(buf);
}

void loop() {}

gives:

Example 1/1/2017 23:00 unixTime = 1483311600
now() = 1483311600
01/01/2017 23:00:00
After adding 2 hours
now() = 1483318800
02/01/2017 01:00:00
02/01/2017 02:00:00
02/01/2017 03:00:00
04/01/2017 01:00:00

Sorry, I have no idea what you are asking. Did you run and understand the example I posted?

Thanks all,
I'll use the recommendation.
I was hoping to use my initial code code because it was so compact without the Serial.print commands. I'm just trying to convert GSM modem time ( with timezone +/-quarters) to local time. The SIM7600/7670 modules no longer have the (CLTS) local time stamp AT command. I'm just getting GMT time with -24(6 Hr) from the CCLK command.

The non-printf scheme is very awkward for single digit numbers.

Nice addition! Thanks.

The major problem with the code you posted is that you are subtracting -6 hours (that is NEGATIVE 6 hours), which in effects ADDS 6 hours to the GMT time.

The non-printf method is not that complicated, just print a leading zero if the value is less than 10. Most useful when you are low on program memory and don't want to include all the code needed for sprintf().

#include <TimeLib.h>

void setup() {
  Serial.begin(9600);
  // Set the current time (e.g., 22nd February 2025, 19:20:00)
  setTime(1, 30, 0, 23, 2, 2025);

  // Number of hours to subtract
  int qtrs = 24; // CST difference from GMT
  //int hrs = qtrs/4; 
  int hoursToSubtract = qtrs/4;
  

  // Calculate the new time
  time_t newTime = now() - (hoursToSubtract * SECS_PER_HOUR);

   // Print the new time
  Serial.print("New Time: ");
  if (hour(newTime) < 10) Serial.print('0');
  Serial.print(hour(newTime));
  Serial.print(":");
  if (minute(newTime) < 10) Serial.print('0');
  Serial.print(minute(newTime));
  Serial.print(":");
  if (second(newTime) < 10) Serial.print('0');
  Serial.print(second(newTime));
  //Serial.print(fread("%02d", second(newTime)));  //(second(newTime));
//String formattedTime = String(format("%02d:%02d:%02d", hour, minute, second));
  Serial.print(" on ");
  Serial.print(month(newTime));
  Serial.print("/");
  if (day(newTime) < 10) Serial.print('0');
  Serial.print(day(newTime));
  Serial.print("/");
  Serial.println(year(newTime));
}

void loop() {
}

If your location has daylight savings time, you might want to use the Timezone library by Jack Christensen, which will handle the changes between standard and daylight savings time.

I’ve owned some devices that handle daylight savings time with a toggle switch: DstOn?

That would be the simple approach, otherwise there needs to be a method of telling the device which time zone you are in. Not to mention the date the time changes is subject to political whims.

I had an alarm clock that tried to do it automatically (I assume with its built in timezone library code) but the political whim changed, and I then had to reset the time 4x per year.