Odd problem with NTP time and ESP32

Odd problem with NTP time and ESP32

Can you help? I have an odd bug. Code too long to show, so I'll summarise. This is a battery powered project with intermittent sensing and MQTT reporting every 2.5 minutes. Option a) works as expected.

Power on or reset...
Setup
Establish WiFi and timezone background info.
Call NTP getlocaltime until it reports true. Make GotTime = true.
Time is demonstrated to be accuate.
(all is well)

Loop Start
Measure sensor(s)
Form a String to send sensor data by MQTT, the string includes a time stamp.
Post String via MQTT.

Now consider either option...
a) Wait in a loop for ~2.5 minutes and I can pick up OTA updates here. Uses ~20 ma. (but all is well.)

or option

b) Turn off WiFi. Make the variable GotTime = false. Enter light sleep for ~2.5 minutes, current consumption is negligible here which is great. Then wake up and reconnect to WiFi.

Both options rejoin now.

Using NTP and WiFi, call getlocaltime // To resynchronise ESP32 RTC. Using "GotTime = getLocalTime(&timeinfo)" N.B. GotTime now reports true.
return to top of loop.

The code works as expected with option a) but current consumption is not ideal for battery power. The processing in the loop is much less than a second. But all timestamps match time expected from time of remote MQTT data receipt.

With option b) the MQTT sensor data time string creeps forwards! Overnight the time string can be in advance by over a minute into the future from when each time stamped MQTT string is received remotely!

The exact loop frequency is not critical to me. However, I really don't understand how the RTC can drift infront of the sleep timed loops in b) AND why the time does not resynchronise immediately, despite the repeated calls to getlocaltime after each sleep state.

I think the cause might be an ESP32 background attempt to SLOWLY resynchonise the RTC but this is thwarted by the loop entering yet another sleep state? If this is the problem, how do I verifiably force an immediate update of the RTC by using a NTP call?

Has anyone else noted similar behaviour?

12TA.

Really ?

The forum can take postings up to 120.000 characters.
So give it a try.

To exclude other reasons if you have syncronised time print the actual time to the serial monitor with time-stamp of serial monitor activated.
If your computer is snycronised to internettime too the time of the timestamp and the rpinted time should have the same second.
Create a MQTT message that has as its content the actual time of the ESP32 and a counter-number that counts up

each time you send this message print the MQTT-message (the content/variable that you really send over MQTT to the serial monitor. The upcounting number will make it easy to identify the messages

by the way The ESP32 has its own RTC which keeps running even in deep-sleep mode

best regards Stefan

I have tried to post a screenshot of the received MQTT data stream as picked up by an app on my phone. See the phone time (I have checked it is exactly correct with seconds checked independently) top left and the time stamp each message comes in faint on the right with the data time stamp formed when running option b).

It shows data stamps which are ahead of the phone time and message time stamp. It only does this with option b).

(Please ignore the 'error flag'. That was only generated by my MQTT loop when the phone WiFi hotspot WAS connected, but the phone was out of Internet signal, as I was briefly in a shop.)

When running option a) the time stamps all are congruent and make sense.
12TA

So the question remains, why does the GotTime = getLocalTime(&timeinfo) work perfectly with an empty virgin time variable initially, but not update it ASAP, if the RTC has drifted off after a light sleep state and then GotTime = getLocalTime(&timeinfo) is called subsequently.

Of course, I don't really need to know why, but I would like to know how to verifiably immediately fully resynchonise the ESP32 RTC to a NTP message.
12TA

I don't understand what you mean by this.
How can two timestamps be ahead of a timestamp where one of these two time-stamps is the reference???
could you please explain in all detail
what is the time-reference ? ESP32 or your phone? or the MQTT-server?

what is this timestamp that has date and time ? and where does this timestamp came from? is it:

  • ESP32 generated?
    or
  • phone-generated?
    or
    MQTT-server-generated ?

As I suggested to create MQTT-messages that contain time-information:

  1. the ESP32 generated time and a ESP32-software generated number that increases by 1 with each sending of a MQTT-message

  2. keeping the ESP32 connected to a time-synced computer
    and the ESP32-software will - each time you send the ESP32-timestamp-MQTT-message

exact this MQTT-message to the serial monitor

maybe this website gives more information how to solve this
https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/system_time.html

How long did this light sleep-state endure?

As a test:
modify your code to go one time into light-sleep and then stay awake for
you could print the ESP32 time each second to the serial monitor for a few minutes
to check if it gets synced by simply beeing connected to WiFi without any NTP-time-syncing

As correspondence to @UKHeliBob and @StefanL38 response

you have still not provided the code

The data strings form the MQTT data generated by the Adruino IDE uploaded program running on the ESP32 and is displayed just before the battery measurements in volts on each loop of 1 minute duration. This is shown in the image for loop #433 today. The phone time IS correct. The MQTT faint time stamps correlate exactly as expected with the program MQTT posting (as shown by a brief LED flash), with relaying by my raspberry pi MQTT mosqitto server and reception on my phone (this seems to be instantaneous). The time server and the RasberryPi are correctly synchronised to the second when tested independently against a radio synchronised time as an independent reference.
When rebooted all time signals make sense. The drift off is gradual, then the generated MQTT data time stamps start to show a time in the future e.g. 14:59:18 of when they are received e.g. 14:57:54 (this time of reception does match the actual time when the data came in i.e. just after the LED flash).

Your style of trying to explain is hard to understand for me.

I rephrase in my own words

Your MQTT-server is a MQTT-mosquite-server running on a raspberry pi
If your ESP32 sends a MQTT-message

Your ESP32 does a brief flash of an LED each time your ESP32-code executes the send-MQTT-message

Do you flash the LED just before sending the MQTT-mesage from ESP32 to raspberry pi
or
Do you flash the LED just after sending the MQTT-mesage from ESP32 to raspberry
??

to be 101% sure which message is what I again suggest that you send the ESP32-time as the message itself
and in parallel keep the ESP32 connected to the serial monitor to print the ESP32-time to the serial monitor

Yes to the server.
The MQTT data stream timestamp is generated immediately before posting.
The flash starts just as it starts to post and stops when it gets a success error code. It is very brief ~1/10 th of a second. The data arrives on my phone apparently instantly with a correct time stamp as faintly shown on the right.
The screen shot shows exactly what the serial port (as your suggestion which I had tried already) does BUT the time drifting is slow so the MQTT data stream screen shot shows it to you much more conveniently after in this case #433 * 1 minute loop iterations .
12TA

I setup a demo-code that does sync with NTP on first boot
then goes into deepsleep and then does a

Wifi.reconnect()
#define uS_TO_S_FACTOR 1000000  /* Conversion factor for micro seconds to seconds */
#define TIME_TO_SLEEP  60        /* Time ESP32 will go to sleep (in seconds) */

RTC_DATA_ATTR int bootCount = 0;

#include <WiFi.h>

unsigned long MyTestTimer = 0;                   // variables MUST be of type unsigned long
const byte    OnBoard_LED = 2;

unsigned long myGotoDeepSleepTimer;

const char *ssid     = "";
const char *password = "";

const char* ntpServer = "fritz.box";
const long  gmtOffset_sec = 0;
const int   daylightOffset_sec = 7200;

#include <time.h>                   // time() ctime()
time_t now;                         // this is the epoch
tm myTimeInfo;                      // the structure tm holds time information in a more convient way

void print_wakeup_reason() {
  esp_sleep_wakeup_cause_t wakeup_reason;
  wakeup_reason = esp_sleep_get_wakeup_cause();
  switch (wakeup_reason)
  {
    case ESP_SLEEP_WAKEUP_EXT0 : Serial.println("Wakeup caused by external signal using RTC_IO"); break;
    case ESP_SLEEP_WAKEUP_EXT1 : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
    case ESP_SLEEP_WAKEUP_TIMER : Serial.println("Wakeup caused by timer"); break;
    case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial.println("Wakeup caused by touchpad"); break;
    case ESP_SLEEP_WAKEUP_ULP : Serial.println("Wakeup caused by ULP program"); break;
    default : Serial.printf("Wakeup was not caused by deep sleep: %d\n", wakeup_reason); break;
  }
}

void showTime() {
  time(&now);                       // read the current time
  localtime_r(&now, &myTimeInfo);           // update the structure tm with the current time
  Serial.print("year:");
  Serial.print(myTimeInfo.tm_year + 1900);  // years since 1900
  Serial.print("\tmonth:");
  Serial.print(myTimeInfo.tm_mon + 1);      // January = 0 (!)
  Serial.print("\tday:");
  Serial.print(myTimeInfo.tm_mday);         // day of month
  Serial.print("\thour:");
  Serial.print(myTimeInfo.tm_hour);         // hours since midnight  0-23
  Serial.print("\tmin:");
  Serial.print(myTimeInfo.tm_min);          // minutes after the hour  0-59
  Serial.print("\tsec:");
  Serial.print(myTimeInfo.tm_sec);          // seconds after the minute  0-61*
  Serial.print("\twday");
  Serial.print(myTimeInfo.tm_wday);         // days since Sunday 0-6
  if (myTimeInfo.tm_isdst == 1)             // Daylight Saving Time flag
    Serial.print("\tDST");
  else
    Serial.print("\tstandard");

  Serial.println();
}

void scanWiFis() {
  Serial.println("scan start");

  // WiFi.scanNetworks will return the number of networks found
  int n = WiFi.scanNetworks();
  Serial.println("scan done");
  if (n == 0) {
    Serial.println("no networks found");
  } else {
    Serial.print(n);
    Serial.println(" networks found");
    for (int i = 0; i < n; ++i) {
      // Print SSID and RSSI for each network found
      Serial.print(i + 1);
      Serial.print(": #");
      Serial.print(WiFi.SSID(i));
      Serial.print("# (");
      Serial.print(WiFi.RSSI(i));
      Serial.print(")");
      Serial.println((WiFi.encryptionType(i) == WIFI_AUTH_OPEN) ? " " : "*");
      delay(10);
    }
  }
  Serial.println("");
}

void connectToWifi() {
  Serial.print("Connecting to #");
  Serial.print(ssid);
  Serial.println("#");

  WiFi.persistent(false);
  WiFi.mode(WIFI_STA);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    yield();
    BlinkHeartBeatLED(OnBoard_LED, 333);
    delay(332);
    Serial.print(".");
  }
  Serial.print("\n connected.");
  Serial.println(WiFi.localIP() );

}

void synchroniseWith_NTP_Time() {
  Serial.print("synchroniseWith_NTP_Time configTime uses ntpServer ");
  Serial.println(ntpServer);
  configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
  Serial.print("synchronising time");

  while (myTimeInfo.tm_year + 1900 < 2000 ) {
    yield();
    time(&now);                       // read the current time
    localtime_r(&now, &myTimeInfo);
    BlinkHeartBeatLED(OnBoard_LED, 100);
    delay(100);
    showTime();
    Serial.print(".");
  }
  Serial.print("\n time synchronsized \n");
  showTime();
}


void PrintFileNameDateTime() {
  Serial.println( F("Code running comes from file ") );
  Serial.println(__FILE__);
  Serial.print( F("  compiled ") );
  Serial.print(__DATE__);
  Serial.print( F(" ") );
  Serial.println(__TIME__);
}

boolean TimePeriodIsOver (unsigned long &periodStartTime, unsigned long TimePeriod) {
  unsigned long currentMillis  = millis();
  if ( currentMillis - periodStartTime >= TimePeriod )
  {
    periodStartTime = currentMillis; // set new expireTime
    return true;                // more time than TimePeriod) has elapsed since last time if-condition was true
  }
  else return false;            // not expired
}


void BlinkHeartBeatLED(int IO_Pin, int BlinkPeriod) {
  static unsigned long MyBlinkTimer;
  pinMode(IO_Pin, OUTPUT);

  if ( TimePeriodIsOver(MyBlinkTimer, BlinkPeriod) ) {
    digitalWrite(IO_Pin, !digitalRead(IO_Pin) );
  }
}


void setup() {
  Serial.begin(115200);
  delay(1000);
  Serial.println("\n Setup-Start \n");
  PrintFileNameDateTime();
  //scanWiFis();
  if (bootCount == 0) {
    connectToWifi();
  }
  else {
    Serial.print("bootcount=");
    Serial.print(bootCount);
    Serial.println(" reconnect() to WiFi");
    WiFi.reconnect();
    Serial.println(" reconnect() done");
  }
  
  synchroniseWith_NTP_Time();

  ++bootCount;
  Serial.println("Boot number: " + String(bootCount));
  //Print the wakeup reason for ESP32
  print_wakeup_reason();
  esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
  Serial.println("Setup ESP32 to sleep for every " + String(TIME_TO_SLEEP) +  " Seconds");
  Serial.println("Going to sleep in 10 seconds");
  myGotoDeepSleepTimer = millis();
}


void loop() {
  BlinkHeartBeatLED(OnBoard_LED, 100);

  if ( TimePeriodIsOver(MyTestTimer, 1000) ) {
    showTime();
  }

  if ( TimePeriodIsOver(myGotoDeepSleepTimer, 10000) ) {
    Serial.print("sleeping now for ");
    Serial.print(TIME_TO_SLEEP);
    Serial.println(" seconds");
    esp_deep_sleep_start();
    Serial.println("This will never be printed");
  }

}

And this is what I get in the serial monitor.
The reconnect is very fast and the time is still in sync.

I use my own router as the NTP-server

20:26:35.816 -> 
20:26:35.816 ->  Setup-Start 
20:26:35.816 -> 
20:26:35.816 -> Code running comes from file 
20:26:35.816 -> F:\myData\Arduino\Sketchbook\ESP32-Get-NTP-Time-Deep-Sleep-001\ESP32-Get-NTP-Time-Deep-Sleep-001.ino
20:26:35.816 ->   compiled Apr 16 2023 20:25:59
20:26:35.816 -> Connecting to #FRITZ!Box 4060 TR#
20:26:36.306 -> ....
20:26:37.285 ->  connected.192.168.178.51
20:26:37.285 -> synchroniseWith_NTP_Time configTime uses ntpServer fritz.box
20:26:37.319 -> synchronising timeyear:1970	month:1	day:1	hour:0	min:0	sec:2	wday4	standard
20:26:37.390 -> .year:1970	month:1	day:1	hour:0	min:0	sec:2	wday4	standard
20:26:37.495 -> .year:1970	month:1	day:1	hour:0	min:0	sec:2	wday4	standard
20:26:37.600 -> .year:1970	month:1	day:1	hour:0	min:0	sec:2	wday4	standard
20:26:37.705 -> .year:1970	month:1	day:1	hour:0	min:0	sec:2	wday4	standard
20:26:37.811 -> .year:1970	month:1	day:1	hour:0	min:0	sec:3	wday4	standard
20:26:37.914 -> .year:1970	month:1	day:1	hour:0	min:0	sec:3	wday4	standard
20:26:37.986 -> .year:1970	month:1	day:1	hour:0	min:0	sec:3	wday4	standard
20:26:38.091 -> .year:1970	month:1	day:1	hour:0	min:0	sec:3	wday4	standard
20:26:38.197 -> .year:1970	month:1	day:1	hour:0	min:0	sec:3	wday4	standard
20:26:38.302 -> .year:1970	month:1	day:1	hour:0	min:0	sec:3	wday4	standard
20:26:38.406 -> .year:1970	month:1	day:1	hour:0	min:0	sec:3	wday4	standard
20:26:38.510 -> .year:1970	month:1	day:1	hour:0	min:0	sec:3	wday4	standard
20:26:38.617 -> .year:1970	month:1	day:1	hour:0	min:0	sec:3	wday4	standard
20:26:38.688 -> .year:1970	month:1	day:1	hour:0	min:0	sec:3	wday4	standard
20:26:38.793 -> .year:1970	month:1	day:1	hour:0	min:0	sec:4	wday4	standard
20:26:38.895 -> .year:1970	month:1	day:1	hour:0	min:0	sec:4	wday4	standard
20:26:39.000 -> .year:1970	month:1	day:1	hour:0	min:0	sec:4	wday4	standard
20:26:39.105 -> .year:1970	month:1	day:1	hour:0	min:0	sec:4	wday4	standard
20:26:39.208 -> .year:1970	month:1	day:1	hour:0	min:0	sec:4	wday4	standard
20:26:39.313 -> .year:1970	month:1	day:1	hour:0	min:0	sec:4	wday4	standard
20:26:39.416 -> .year:1970	month:1	day:1	hour:0	min:0	sec:4	wday4	standard
20:26:39.487 -> .year:2023	month:4	day:16	hour:20	min:26	sec:38	wday0	DST
20:26:39.593 -> .
20:26:39.593 ->  time synchronsized 
20:26:39.593 -> year:2023	month:4	day:16	hour:20	min:26	sec:38	wday0	DST
20:26:39.593 -> Boot number: 1
20:26:39.629 -> Wakeup was not caused by deep sleep: 0
20:26:39.629 -> Setup ESP32 to sleep for every 60 Seconds
20:26:39.629 -> Going to sleep in 10 seconds
20:26:39.629 -> year:2023	month:4	day:16	hour:20	min:26	sec:38	wday0	DST
20:26:40.605 -> year:2023	month:4	day:16	hour:20	min:26	sec:39	wday0	DST
20:26:41.619 -> year:2023	month:4	day:16	hour:20	min:26	sec:40	wday0	DST
20:26:42.600 -> year:2023	month:4	day:16	hour:20	min:26	sec:41	wday0	DST
20:26:43.625 -> year:2023	month:4	day:16	hour:20	min:26	sec:42	wday0	DST
20:26:44.607 -> year:2023	month:4	day:16	hour:20	min:26	sec:43	wday0	DST
20:26:45.615 -> year:2023	month:4	day:16	hour:20	min:26	sec:44	wday0	DST
20:26:46.629 -> year:2023	month:4	day:16	hour:20	min:26	sec:45	wday0	DST
20:26:47.609 -> year:2023	month:4	day:16	hour:20	min:26	sec:46	wday0	DST
20:26:48.621 -> year:2023	month:4	day:16	hour:20	min:26	sec:47	wday0	DST
20:26:49.603 -> year:2023	month:4	day:16	hour:20	min:26	sec:48	wday0	DST
20:26:49.638 -> sleeping now for 60 seconds
20:27:49.173 -> ets Jul 29 2019 12:21:46
20:27:49.173 -> 
20:27:49.173 -> rst:0x5 (DEEPSLEEP_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
20:27:49.173 -> configsip: 0, SPIWP:0xee
20:27:49.173 -> clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
20:27:49.173 -> mode:DIO, clock div:1
20:27:49.173 -> load:0x3fff0030,len:1344
20:27:49.173 -> load:0x40078000,len:13924
20:27:49.173 -> ho 0 tail 12 room 4
20:27:49.173 -> load:0x40080400,len:3600
20:27:49.173 -> entry 0x400805f0
20:27:50.234 -> 
20:27:50.234 ->  Setup-Start 
20:27:50.234 -> 
20:27:50.234 -> Code running comes from file 
20:27:50.234 -> F:\myData\Arduino\Sketchbook\ESP32-Get-NTP-Time-Deep-Sleep-001\ESP32-Get-NTP-Time-Deep-Sleep-001.ino
20:27:50.234 ->   compiled Apr 16 2023 20:25:59
20:27:50.234 -> bootcount=1 reconnect() to WiFi
20:27:50.234 ->  reconnect() done
20:27:50.234 -> synchroniseWith_NTP_Time configTime uses ntpServer fritz.box
20:27:50.234 -> synchronising timeyear:2023	month:4	day:16	hour:20	min:27	sec:49	wday0	DST
20:27:50.341 -> .
20:27:50.341 ->  time synchronsized 
20:27:50.341 -> year:2023	month:4	day:16	hour:20	min:27	sec:49	wday0	DST
20:27:50.376 -> Boot number: 2
20:27:50.376 -> Wakeup caused by timer
20:27:50.376 -> Setup ESP32 to sleep for every 60 Seconds
20:27:50.376 -> Going to sleep in 10 seconds
20:27:50.376 -> year:2023	month:4	day:16	hour:20	min:27	sec:49	wday0	DST
20:27:51.358 -> year:2023	month:4	day:16	hour:20	min:27	sec:50	wday0	DST
20:27:52.342 -> year:2023	month:4	day:16	hour:20	min:27	sec:51	wday0	DST
20:27:53.363 -> year:2023	month:4	day:16	hour:20	min:27	sec:52	wday0	DST
20:27:54.348 -> year:2023	month:4	day:16	hour:20	min:27	sec:53	wday0	DST
20:27:55.363 -> year:2023	month:4	day:16	hour:20	min:27	sec:54	wday0	DST
20:27:56.341 -> year:2023	month:4	day:16	hour:20	min:27	sec:55	wday0	DST
20:27:57.361 -> year:2023	month:4	day:16	hour:20	min:27	sec:56	wday0	DST
20:27:58.372 -> year:2023	month:4	day:16	hour:20	min:27	sec:57	wday0	DST
20:27:59.350 -> year:2023	month:4	day:16	hour:20	min:27	sec:58	wday0	DST
20:28:00.361 -> year:2023	month:4	day:16	hour:20	min:27	sec:59	wday0	DST
20:28:00.361 -> sleeping now for 60 seconds
20:29:00.019 -> ets Jul 29 2019 12:21:46
20:29:00.019 -> 
20:29:00.019 -> rst:0x5 (DEEPSLEEP_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
20:29:00.019 -> configsip: 0, SPIWP:0xee
20:29:00.019 -> clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
20:29:00.055 -> mode:DIO, clock div:1
20:29:00.055 -> load:0x3fff0030,len:1344
20:29:00.055 -> load:0x40078000,len:13924
20:29:00.055 -> ho 0 tail 12 room 4
20:29:00.055 -> load:0x40080400,len:3600
20:29:00.055 -> entry 0x400805f0
20:29:01.097 -> 
20:29:01.097 ->  Setup-Start 
20:29:01.097 -> 
20:29:01.097 -> Code running comes from file 
20:29:01.097 -> F:\myData\Arduino\Sketchbook\ESP32-Get-NTP-Time-Deep-Sleep-001\ESP32-Get-NTP-Time-Deep-Sleep-001.ino
20:29:01.097 ->   compiled Apr 16 2023 20:25:59
20:29:01.097 -> bootcount=2 reconnect() to WiFi
20:29:01.097 ->  reconnect() done
20:29:01.097 -> synchroniseWith_NTP_Time configTime uses ntpServer fritz.box
20:29:01.097 -> synchronising timeyear:2023	month:4	day:16	hour:20	min:29	sec:1	wday0	DST
20:29:01.200 -> .
20:29:01.200 ->  time synchronsized 
20:29:01.200 -> year:2023	month:4	day:16	hour:20	min:29	sec:1	wday0	DST
20:29:01.235 -> Boot number: 3
20:29:01.235 -> Wakeup caused by timer
20:29:01.235 -> Setup ESP32 to sleep for every 60 Seconds
20:29:01.235 -> Going to sleep in 10 seconds
20:29:01.235 -> year:2023	month:4	day:16	hour:20	min:29	sec:1	wday0	DST
20:29:02.216 -> year:2023	month:4	day:16	hour:20	min:29	sec:2	wday0	DST
20:29:03.228 -> year:2023	month:4	day:16	hour:20	min:29	sec:3	wday0	DST
20:29:04.212 -> year:2023	month:4	day:16	hour:20	min:29	sec:4	wday0	DST
20:29:05.233 -> year:2023	month:4	day:16	hour:20	min:29	sec:5	wday0	DST
20:29:06.214 -> year:2023	month:4	day:16	hour:20	min:29	sec:6	wday0	DST
20:29:07.225 -> year:2023	month:4	day:16	hour:20	min:29	sec:7	wday0	DST
20:29:08.205 -> year:2023	month:4	day:16	hour:20	min:29	sec:8	wday0	DST
20:29:09.223 -> year:2023	month:4	day:16	hour:20	min:29	sec:9	wday0	DST
20:29:10.202 -> year:2023	month:4	day:16	hour:20	min:29	sec:10	wday0	DST
20:29:11.221 -> year:2023	month:4	day:16	hour:20	min:29	sec:11	wday0	DST
20:29:11.221 -> sleeping now for 60 seconds

best regards Stefan

Thanks for your great interest! I use light sleep to maintain the RAM in my sketch and so the program running state. I then called the NTP after each loop because the RTC time WAS drifting. But to no avail. Mine really starts fine too, but after 433 minutes the screenshot I posted shows the drift in the RTC time into the future. Can you try your sketch over a period of several hours, preferably with light sleep and an ESP32?
12TA

If you post the modification for light sleep I can do this.
have you really read what is explained about RTC-precision on this website?
https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/system_time.html

After ten minutes I can see already a significant timedrift
code

#define uS_TO_S_FACTOR 1000000  /* Conversion factor for micro seconds to seconds */
#define TIME_TO_SLEEP  20        /* Time ESP32 will go to sleep (in seconds) */

RTC_DATA_ATTR int bootCount = 0;

#include <WiFi.h>

unsigned long MyTestTimer = 0;                   // variables MUST be of type unsigned long
const byte    OnBoard_LED = 2;

unsigned long myGotoDeepSleepTimer;

const char *ssid     = "";
const char *password = "";

const char* ntpServer = "fritz.box";
const long  gmtOffset_sec = 0;
const int   daylightOffset_sec = 7200;

#include <time.h>                   // time() ctime()
time_t now;                         // this is the epoch
tm myTimeInfo;                      // the structure tm holds time information in a more convient way

void print_wakeup_reason() {
  esp_sleep_wakeup_cause_t wakeup_reason;
  wakeup_reason = esp_sleep_get_wakeup_cause();
  switch (wakeup_reason)
  {
    case ESP_SLEEP_WAKEUP_EXT0 : Serial.println("Wakeup caused by external signal using RTC_IO"); break;
    case ESP_SLEEP_WAKEUP_EXT1 : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
    case ESP_SLEEP_WAKEUP_TIMER : Serial.println("Wakeup caused by timer"); break;
    case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial.println("Wakeup caused by touchpad"); break;
    case ESP_SLEEP_WAKEUP_ULP : Serial.println("Wakeup caused by ULP program"); break;
    default : Serial.printf("Wakeup was not caused by deep sleep: %d\n", wakeup_reason); break;
  }
}

void showTime() {
  time(&now);                       // read the current time
  localtime_r(&now, &myTimeInfo);           // update the structure tm with the current time
  Serial.print("year:");
  Serial.print(myTimeInfo.tm_year + 1900);  // years since 1900
  Serial.print("\tmonth:");
  Serial.print(myTimeInfo.tm_mon + 1);      // January = 0 (!)
  Serial.print("\tday:");
  Serial.print(myTimeInfo.tm_mday);         // day of month
  Serial.print("\thour:");
  Serial.print(myTimeInfo.tm_hour);         // hours since midnight  0-23
  Serial.print("\tmin:");
  Serial.print(myTimeInfo.tm_min);          // minutes after the hour  0-59
  Serial.print("\tsec:");
  Serial.print(myTimeInfo.tm_sec);          // seconds after the minute  0-61*
  Serial.print("\twday");
  Serial.print(myTimeInfo.tm_wday);         // days since Sunday 0-6
  if (myTimeInfo.tm_isdst == 1)             // Daylight Saving Time flag
    Serial.print("\tDST");
  else
    Serial.print("\tstandard");

  Serial.println();
}

void scanWiFis() {
  Serial.println("scan start");

  // WiFi.scanNetworks will return the number of networks found
  int n = WiFi.scanNetworks();
  Serial.println("scan done");
  if (n == 0) {
    Serial.println("no networks found");
  } else {
    Serial.print(n);
    Serial.println(" networks found");
    for (int i = 0; i < n; ++i) {
      // Print SSID and RSSI for each network found
      Serial.print(i + 1);
      Serial.print(": #");
      Serial.print(WiFi.SSID(i));
      Serial.print("# (");
      Serial.print(WiFi.RSSI(i));
      Serial.print(")");
      Serial.println((WiFi.encryptionType(i) == WIFI_AUTH_OPEN) ? " " : "*");
      delay(10);
    }
  }
  Serial.println("");
}

void connectToWifi() {
  Serial.print("Connecting to #");
  Serial.print(ssid);
  Serial.println("#");

  WiFi.persistent(false);
  WiFi.mode(WIFI_STA);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    yield();
    BlinkHeartBeatLED(OnBoard_LED, 333);
    delay(332);
    Serial.print(".");
  }
  Serial.print("\n connected.");
  Serial.println(WiFi.localIP() );

}

void synchroniseWith_NTP_Time() {
  Serial.print("synchroniseWith_NTP_Time configTime uses ntpServer ");
  Serial.println(ntpServer);
  configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
  Serial.print("synchronising time");

  while (myTimeInfo.tm_year + 1900 < 2000 ) {
    yield();
    time(&now);                       // read the current time
    localtime_r(&now, &myTimeInfo);
    BlinkHeartBeatLED(OnBoard_LED, 100);
    delay(100);
    showTime();
    Serial.print(".");
  }
  Serial.print("\n time synchronsized \n");
  showTime();
}


void PrintFileNameDateTime() {
  Serial.println( F("Code running comes from file ") );
  Serial.println(__FILE__);
  Serial.print( F("  compiled ") );
  Serial.print(__DATE__);
  Serial.print( F(" ") );
  Serial.println(__TIME__);
}

boolean TimePeriodIsOver (unsigned long &periodStartTime, unsigned long TimePeriod) {
  unsigned long currentMillis  = millis();
  if ( currentMillis - periodStartTime >= TimePeriod )
  {
    periodStartTime = currentMillis; // set new expireTime
    return true;                // more time than TimePeriod) has elapsed since last time if-condition was true
  }
  else return false;            // not expired
}


void BlinkHeartBeatLED(int IO_Pin, int BlinkPeriod) {
  static unsigned long MyBlinkTimer;
  pinMode(IO_Pin, OUTPUT);

  if ( TimePeriodIsOver(MyBlinkTimer, BlinkPeriod) ) {
    digitalWrite(IO_Pin, !digitalRead(IO_Pin) );
  }
}


void setup() {
  Serial.begin(115200);
  delay(1000);
  Serial.println("\n Setup-Start \n");
  PrintFileNameDateTime();
  //scanWiFis();
  if (bootCount == 0) {
    connectToWifi();
  }
  else {
    Serial.print("bootcount=");
    Serial.print(bootCount);
    Serial.println(" reconnect() to WiFi");
    WiFi.reconnect();
    Serial.println(" reconnect() done");
  }
  
  synchroniseWith_NTP_Time();

  ++bootCount;
  Serial.println("Boot number: " + String(bootCount));
  //Print the wakeup reason for ESP32
  print_wakeup_reason();
  esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
  Serial.println("Setup ESP32 to sleep for every " + String(TIME_TO_SLEEP) +  " Seconds");
  Serial.println("Going to sleep in 10 seconds");
  myGotoDeepSleepTimer = millis();
}


void loop() {
  BlinkHeartBeatLED(OnBoard_LED, 100);

  if ( TimePeriodIsOver(MyTestTimer, 1000) ) {
    showTime();
  }

  if ( TimePeriodIsOver(myGotoDeepSleepTimer, 10000) ) {
    Serial.print("light sleeping now for ");
    Serial.print(TIME_TO_SLEEP);
    Serial.println(" seconds");
    //esp_deep_sleep_start();
    esp_light_sleep_start();
    myGotoDeepSleepTimer = millis();
    Serial.println("woke up from light sleeping");
  }
}

serial monitor

21:09:57.717 -> Boot number: 1
21:09:57.717 -> Wakeup was not caused by deep sleep: 0
21:09:57.717 -> Setup ESP32 to sleep for every 20 Seconds
21:09:57.717 -> Going to sleep in 10 seconds
21:09:57.717 -> year:2023	month:4	day:16	hour:21	min:9	sec:56	wday0	DST
21:09:58.727 -> year:2023	month:4	day:16	hour:21	min:9	sec:57	wday0	DST
21:09:59.702 -> year:2023	month:4	day:16	hour:21	min:9	sec:58	wday0	DST
21:10:00.717 -> year:2023	month:4	day:16	hour:21	min:9	sec:59	wday0	DST
21:10:01.724 -> year:2023	month:4	day:16	hour:21	min:10	sec:0	wday0	DST
21:10:02.703 -> year:2023	month:4	day:16	hour:21	min:10	sec:1	wday0	DST
21:10:03.714 -> year:2023	month:4	day:16	hour:21	min:10	sec:2	wday0	DST
21:10:04.725 -> year:2023	month:4	day:16	hour:21	min:10	sec:3	wday0	DST
21:10:05.710 -> year:2023	month:4	day:16	hour:21	min:10	sec:4	wday0	DST
21:10:06.726 -> year:2023	month:4	day:16	hour:21	min:10	sec:5	wday0	DST
21:10:07.712 -> year:2023	month:4	day:16	hour:21	min:10	sec:6	wday0	DST
21:10:27.556 -> light sleeping now for 20 seconds
21:10:27.556 -> woke up from light sleeping
21:10:27.556 -> year:2023	month:4	day:16	hour:21	min:10	sec:26	wday0	DST
21:10:28.550 -> year:2023	month:4	day:16	hour:21	min:10	sec:27	wday0	DST
21:10:29.567 -> year:2023	month:4	day:16	hour:21	min:10	sec:28	wday0	DST
21:10:30.553 -> year:2023	month:4	day:16	hour:21	min:10	sec:29	wday0	DST
21:10:31.567 -> year:2023	month:4	day:16	hour:21	min:10	sec:30	wday0	DST
21:10:32.549 -> year:2023	month:4	day:16	hour:21	min:10	sec:31	wday0	DST
21:10:33.561 -> year:2023	month:4	day:16	hour:21	min:10	sec:32	wday0	DST
21:10:34.543 -> year:2023	month:4	day:16	hour:21	min:10	sec:33	wday0	DST
21:10:35.559 -> year:2023	month:4	day:16	hour:21	min:10	sec:34	wday0	DST
21:10:36.542 -> year:2023	month:4	day:16	hour:21	min:10	sec:35	wday0	DST
21:10:37.551 -> year:2023	month:4	day:16	hour:21	min:10	sec:36	wday0	DST
21:10:57.381 -> light sleeping now for 20 seconds
...
21:23:31.601 -> year:2023	month:4	day:16	hour:21	min:23	sec:36	wday0	DST
21:23:32.611 -> year:2023	month:4	day:16	hour:21	min:23	sec:37	wday0	DST
21:23:52.427 -> light sleeping now for 20 seconds
21:23:52.427 -> woke up from light sleeping
21:23:52.427 -> year:2023	month:4	day:16	hour:21	min:23	sec:57	wday0	DST
21:23:53.411 -> year:2023	month:4	day:16	hour:21	min:23	sec:58	wday0	DST
21:23:54.424 -> year:2023	month:4	day:16	hour:21	min:23	sec:59	wday0	DST
21:23:55.412 -> year:2023	month:4	day:16	hour:21	min:24	sec:0	wday0	DST
21:23:56.421 -> year:2023	month:4	day:16	hour:21	min:24	sec:1	wday0	DST
21:23:57.403 -> year:2023	month:4	day:16	hour:21	min:24	sec:2	wday0	DST
21:23:58.424 -> year:2023	month:4	day:16	hour:21	min:24	sec:3	wday0	DST
21:23:59.398 -> year:2023	month:4	day:16	hour:21	min:24	sec:4	wday0	DST
21:24:00.426 -> year:2023	month:4	day:16	hour:21	min:24	sec:5	wday0	DST

I had seen that page but it is too complex for me and I could not find the word "precision" within it. It does not seem to refer clearly to the Arduino IDE commands and code snippets like yours.
My code fragment for light_sleep is

WiFi.disconnect(true);  // Disconnect from the network
GotTime = false; // Seems to loose accuracy when it goes to sleep.
Serial.print ("Light sleep started for "); 
Serial.print(min(LoopFrequency, (LoopFrequency - (millis() - LoopTimer))) / 1000.0); 
Serial.print(" seconds ... "); // Serial.flush();
esp_sleep_enable_timer_wakeup ((LoopFrequency - (millis() - LoopTimer)) * 1000) ;
esp_light_sleep_start(); // USB measured current on battery module = 0 mA! versus ~10mA in modem sleep.
LoopTimer = millis();

Light sleep looses WiFi so when awake, I reconnect to WiFi and when connected

GotTime = getLocalTime(&timeinfo); // Must update the clock variable.
} 

Final bracket is end of the loop() so each subsequent loop should start with a newly synchronised RTC and with WiFi connected. BUT the time drifts off gradually as described.
12TA

for sending your MQTT-messages you have to reconnect to WiFi anyway
I tested light sleeping in combination with calling

   configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);

after each wakeup

#define uS_TO_S_FACTOR 1000000  /* Conversion factor for micro seconds to seconds */
#define TIME_TO_SLEEP  20        /* Time ESP32 will go to sleep (in seconds) */

RTC_DATA_ATTR int bootCount = 0;

#include <WiFi.h>

unsigned long MyTestTimer = 0;                   // variables MUST be of type unsigned long
const byte    OnBoard_LED = 2;

unsigned long myGotoDeepSleepTimer;

const char *ssid     = "";
const char *password = "";

const char* ntpServer = "fritz.box";
const long  gmtOffset_sec = 0;
const int   daylightOffset_sec = 7200;

#include <time.h>                   // time() ctime()
time_t now;                         // this is the epoch
tm myTimeInfo;                      // the structure tm holds time information in a more convient way

void print_wakeup_reason() {
  esp_sleep_wakeup_cause_t wakeup_reason;
  wakeup_reason = esp_sleep_get_wakeup_cause();
  switch (wakeup_reason)
  {
    case ESP_SLEEP_WAKEUP_EXT0 : Serial.println("Wakeup caused by external signal using RTC_IO"); break;
    case ESP_SLEEP_WAKEUP_EXT1 : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
    case ESP_SLEEP_WAKEUP_TIMER : Serial.println("Wakeup caused by timer"); break;
    case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial.println("Wakeup caused by touchpad"); break;
    case ESP_SLEEP_WAKEUP_ULP : Serial.println("Wakeup caused by ULP program"); break;
    default : Serial.printf("Wakeup was not caused by deep sleep: %d\n", wakeup_reason); break;
  }
}

void showTime() {
  time(&now);                       // read the current time
  localtime_r(&now, &myTimeInfo);           // update the structure tm with the current time
  Serial.print("year:");
  Serial.print(myTimeInfo.tm_year + 1900);  // years since 1900
  Serial.print("\tmonth:");
  Serial.print(myTimeInfo.tm_mon + 1);      // January = 0 (!)
  Serial.print("\tday:");
  Serial.print(myTimeInfo.tm_mday);         // day of month
  Serial.print("\thour:");
  Serial.print(myTimeInfo.tm_hour);         // hours since midnight  0-23
  Serial.print("\tmin:");
  Serial.print(myTimeInfo.tm_min);          // minutes after the hour  0-59
  Serial.print("\tsec:");
  Serial.print(myTimeInfo.tm_sec);          // seconds after the minute  0-61*
  Serial.print("\twday");
  Serial.print(myTimeInfo.tm_wday);         // days since Sunday 0-6
  if (myTimeInfo.tm_isdst == 1)             // Daylight Saving Time flag
    Serial.print("\tDST");
  else
    Serial.print("\tstandard");

  Serial.println();
}

void scanWiFis() {
  Serial.println("scan start");

  // WiFi.scanNetworks will return the number of networks found
  int n = WiFi.scanNetworks();
  Serial.println("scan done");
  if (n == 0) {
    Serial.println("no networks found");
  } else {
    Serial.print(n);
    Serial.println(" networks found");
    for (int i = 0; i < n; ++i) {
      // Print SSID and RSSI for each network found
      Serial.print(i + 1);
      Serial.print(": #");
      Serial.print(WiFi.SSID(i));
      Serial.print("# (");
      Serial.print(WiFi.RSSI(i));
      Serial.print(")");
      Serial.println((WiFi.encryptionType(i) == WIFI_AUTH_OPEN) ? " " : "*");
      delay(10);
    }
  }
  Serial.println("");
}

void connectToWifi() {
  Serial.print("Connecting to #");
  Serial.print(ssid);
  Serial.println("#");

  WiFi.persistent(false);
  WiFi.mode(WIFI_STA);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    yield();
    BlinkHeartBeatLED(OnBoard_LED, 333);
    delay(332);
    Serial.print(".");
  }
  Serial.print("\n connected.");
  Serial.println(WiFi.localIP() );

}

void synchroniseWith_NTP_Time() {
  Serial.print("synchroniseWith_NTP_Time configTime uses ntpServer ");
  Serial.println(ntpServer);
  configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
  Serial.print("synchronising time");

  while (myTimeInfo.tm_year + 1900 < 2000 ) {
    yield();
    time(&now);                       // read the current time
    localtime_r(&now, &myTimeInfo);
    BlinkHeartBeatLED(OnBoard_LED, 100);
    delay(100);
    showTime();
    Serial.print(".");
  }
  Serial.print("\n time synchronsized \n");
  showTime();
}


void PrintFileNameDateTime() {
  Serial.println( F("Code running comes from file ") );
  Serial.println(__FILE__);
  Serial.print( F("  compiled ") );
  Serial.print(__DATE__);
  Serial.print( F(" ") );
  Serial.println(__TIME__);
}

boolean TimePeriodIsOver (unsigned long &periodStartTime, unsigned long TimePeriod) {
  unsigned long currentMillis  = millis();
  if ( currentMillis - periodStartTime >= TimePeriod )
  {
    periodStartTime = currentMillis; // set new expireTime
    return true;                // more time than TimePeriod) has elapsed since last time if-condition was true
  }
  else return false;            // not expired
}


void BlinkHeartBeatLED(int IO_Pin, int BlinkPeriod) {
  static unsigned long MyBlinkTimer;
  pinMode(IO_Pin, OUTPUT);

  if ( TimePeriodIsOver(MyBlinkTimer, BlinkPeriod) ) {
    digitalWrite(IO_Pin, !digitalRead(IO_Pin) );
  }
}


void setup() {
  Serial.begin(115200);
  delay(1000);
  Serial.println("\n Setup-Start \n");
  PrintFileNameDateTime();
  //scanWiFis();
  if (bootCount == 0) {
    connectToWifi();
  }
  else {
    Serial.print("bootcount=");
    Serial.print(bootCount);
    Serial.println(" reconnect() to WiFi");
    WiFi.reconnect();
    Serial.println(" reconnect() done");
  }

  synchroniseWith_NTP_Time();

  ++bootCount;
  Serial.println("Boot number: " + String(bootCount));
  //Print the wakeup reason for ESP32
  print_wakeup_reason();
  esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
  Serial.println("Setup ESP32 to sleep for every " + String(TIME_TO_SLEEP) +  " Seconds");
  Serial.println("Going to sleep in 10 seconds");
  myGotoDeepSleepTimer = millis();
}


void loop() {
  BlinkHeartBeatLED(OnBoard_LED, 100);

  if ( TimePeriodIsOver(MyTestTimer, 1000) ) {
    showTime();
  }

  if ( TimePeriodIsOver(myGotoDeepSleepTimer, 10000) ) {
    Serial.print("light sleeping now for ");
    Serial.print(TIME_TO_SLEEP);
    Serial.println(" seconds");
    //esp_deep_sleep_start();
    esp_light_sleep_start();
    myGotoDeepSleepTimer = millis();
    Serial.println("woke up from light sleeping");
    
    configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
    Serial.println("configTime() done");
    showTime();
  }
}

and this keeps time in sync

21:44:46.599 -> 
21:44:46.599 ->  Setup-Start 
21:44:46.599 -> 
21:44:46.599 -> Code running comes from file 
21:44:46.599 -> F:\myData\Arduino\Sketchbook\ESP32-Get-NTP-Time-Light-Sleep-002\ESP32-Get-NTP-Time-Light-Sleep-002.ino
21:44:46.634 ->   compiled Apr 16 2023 21:43:56
21:44:46.634 -> Connecting to #FRITZ!Box 4060 TR#
21:44:47.019 -> ....
21:44:48.034 ->  connected.192.168.178.51
21:44:48.034 -> synchroniseWith_NTP_Time configTime uses ntpServer fritz.box
21:44:48.034 -> synchronising timeyear:1970	month:1	day:1	hour:0	min:0	sec:2	wday4	standard
21:44:48.140 -> .year:1970	month:1	day:1	hour:0	min:0	sec:2	wday4	standard
21:44:52.431 -> .year:2023	month:4	day:16	hour:21	min:44	sec:51	wday0	DST
21:44:52.535 -> .
21:44:52.535 ->  time synchronsized 
21:44:52.535 -> year:2023	month:4	day:16	hour:21	min:44	sec:51	wday0	DST
21:44:52.535 -> Boot number: 1
21:44:52.535 -> Wakeup was not caused by deep sleep: 0
21:44:52.535 -> Setup ESP32 to sleep for every 20 Seconds
21:44:52.570 -> Going to sleep in 10 seconds
21:44:52.570 -> year:2023	month:4	day:16	hour:21	min:44	sec:51	wday0	DST
21:44:53.549 -> year:2023	month:4	day:16	hour:21	min:44	sec:52	wday0	DST
21:44:54.565 -> year:2023	month:4	day:16	hour:21	min:44	sec:53	wday0	DST
21:44:55.553 -> year:2023	month:4	day:16	hour:21	min:44	sec:54	wday0	DST
21:44:56.566 -> year:2023	month:4	day:16	hour:21	min:44	sec:55	wday0	DST
21:44:57.543 -> year:2023	month:4	day:16	hour:21	min:44	sec:56	wday0	DST
21:44:58.550 -> year:2023	month:4	day:16	hour:21	min:44	sec:57	wday0	DST
21:44:59.565 -> year:2023	month:4	day:16	hour:21	min:44	sec:58	wday0	DST
21:45:00.570 -> year:2023	month:4	day:16	hour:21	min:44	sec:59	wday0	DST
21:45:01.554 -> year:2023	month:4	day:16	hour:21	min:45	sec:0	wday0	DST
21:45:02.569 -> year:2023	month:4	day:16	hour:21	min:45	sec:1	wday0	DST
21:45:22.414 -> light sleeping now for 20 seconds
21:45:22.414 -> woke up from light sleeping
21:45:22.414 -> year:2023	month:4	day:16	hour:21	min:45	sec:21	wday0	DST
21:45:23.397 -> year:2023	month:4	day:16	hour:21	min:45	sec:22	wday0	DST
21:45:24.410 -> year:2023	month:4	day:16	hour:21	min:45	sec:23	wday0	DST
...

21:59:36.330 -> light sleeping now for 20 seconds
21:59:56.155 -> woke up from light sleeping
21:59:56.155 -> configTime() done
21:59:56.155 -> year:2023	month:4	day:16	hour:21	min:59	sec:56	wday0	DST
21:59:56.155 -> year:2023	month:4	day:16	hour:21	min:59	sec:56	wday0	DST
21:59:57.168 -> year:2023	month:4	day:16	hour:21	min:59	sec:57	wday0	DST
21:59:58.177 -> year:2023	month:4	day:16	hour:21	min:59	sec:58	wday0	DST
21:59:59.153 -> year:2023	month:4	day:16	hour:21	min:59	sec:59	wday0	DST
22:00:00.165 -> year:2023	month:4	day:16	hour:22	min:0	sec:0	wday0	DST
22:00:01.148 -> year:2023	month:4	day:16	hour:22	min:0	sec:1	wday0	DST
22:00:02.169 -> year:2023	month:4	day:16	hour:22	min:0	sec:2	wday0	DST
22:00:03.148 -> year:2023	month:4	day:16	hour:22	min:0	sec:3	wday0	DST
22:00:04.156 -> year:2023	month:4	day:16	hour:22	min:0	sec:4	wday0	DST
22:00:05.172 -> year:2023	month:4	day:16	hour:22	min:0	sec:5	wday0	DST
22:00:06.132 -> lig

This webiste

has a paragraph

SNTP Time Synchronization

which describe automatic time-synchronisation in a definable intervall.

If you don't understand how to do it with arduino-IDE you could ask this in the forum.

If you do not use your local WiFi-router as the NTP-server
you should keep the time-interval for NTP-request at 10 minutes or higher.
Otherwise you create a huge traffic to the NTP-server

If I remember right you are sleeping for 1 hour?

I'm now using my RaspberryPi as NTP source (problem was revealed with a public server though) and loops are currently 1 minute while I'm developing.
12TA

if the name of the function-call

getLocalTime (&myTimeInfo)

is program

it does nothing else like reading out the local RTC which is drifting away
I replaced the

getLocalTime(&myTimeInfo)

with

   configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);

and the time drifts away

22:15:08.450 -> 
22:15:08.450 ->  Setup-Start 
22:15:08.450 -> 
22:15:08.485 -> Code running comes from file 
22:15:08.485 -> F:\myData\Arduino\Sketchbook\ESP32-Get-NTP-Time-Light-Sleep-003\ESP32-Get-NTP-Time-Light-Sleep-003.ino
22:15:08.485 ->   compiled Apr 16 2023 22:14:43
22:15:08.485 -> Connecting to #FRITZ!Box 4060 TR#
22:15:08.904 -> ....
22:15:09.882 ->  connected.192.168.178.51
22:15:09.882 -> synchroniseWith_NTP_Time configTime uses ntpServer fritz.box
22:15:09.917 -> synchronising timeyear:1970	month:1	day:1	hour:0	min:0	sec:2	wday4	standard
22:15:14.408 -> .
22:15:14.408 ->  time synchronsized 
22:15:14.408 -> year:2023	month:4	day:16	hour:22	min:15	sec:13	wday0	DST
22:15:14.408 -> Boot number: 1
22:15:14.408 -> Wakeup was not caused by deep sleep: 0
22:15:14.408 -> Setup ESP32 to sleep for every 60 Seconds
22:15:14.408 -> Going to sleep in 10 seconds
22:15:14.408 -> year:2023	month:4	day:16	hour:22	min:15	sec:13	wday0	DST
22:15:15.425 -> year:2023	month:4	day:16	hour:22	min:15	sec:14	wday0	DST
22:15:16.434 -> year:2023	month:4	day:16	hour:22	min:15	sec:15	wday0	DST
22:15:17.410 -> year:2023	month:4	day:16	hour:22	min:15	sec:16	wday0	DST
22:15:18.429 -> year:2023	month:4	day:16	hour:22	min:15	sec:17	wday0	DST
22:15:19.414 -> year:2023	month:4	day:16	hour:22	min:15	sec:18	wday0	DST
22:15:20.429 -> year:2023	month:4	day:16	hour:22	min:15	sec:19	wday0	DST
22:15:21.404 -> year:2023	month:4	day:16	hour:22	min:15	sec:20	wday0	DST
22:15:22.426 -> year:2023	month:4	day:16	hour:22	min:15	sec:21	wday0	DST
22:15:23.405 -> year:2023	month:4	day:16	hour:22	min:15	sec:22	wday0	DST
22:15:24.423 -> light sleeping now for 60 seconds
22:16:23.755 -> woke up from light sleeping
...

22:33:45.560 -> year:2023	month:4	day:16	hour:22	min:33	sec:53	wday0	DST
22:33:45.560 -> year:2023	month:4	day:16	hour:22	min:33	sec:53	wday0	DST
22:33:46.538 -> year:2023	month:4	day:16	hour:22	min:33	sec:54	wday0	DST
22:33:47.555 -> year:2023	month:4	day:16	hour:22	min:33	sec:55	wday0	DST
22:33:48.566 -> year:2023	month:4	day:16	hour:22	min:33	sec:56	wday0	DST
22:33:49.543 -> year:2023	month:4	day:16	hour:22	min:33	sec:57	wday0	DST
22:33:50.564 -> year:2023	month:4	day:16	hour:22	min:33	sec:58	wday0	DST
22:33:51.539 -> year:2023	month:4	day:16	hour:22	min:33	sec:59	wday0	DST
22:33:52.559 -> year:2023	month:4	day:16	hour:22	min:34	sec:0	wday0	DST
22:33:53.541 -> year:2023	month:4	day:16	hour:22	min:34	sec:1	wday0	DST
22:33:54.560 -> year:2023	month:4	day:16	hour:22	min:34	sec:2	wday0	DST
22:33:55.538 -> lig

Well then I would call the ESP32 "RTC" not a RTC and not an "AI" (artificial intelligence)
I called this "clock" an
"EI" (estimation-iron) that does a rough estimation of how much time has passed by

best regards Stefan

I'm sorry I just did not understand your last post at all. Can you simplify or rephrase it?
12TA

replace your function-call

with the function-call

  configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
  GotTime = true;

and the RTC will be resynced to internettime
=> the timedrift should go away.