Update: 2024-03-06

ESP32 SNTP Zeitsynchronisation per WLAN mit Automatischer Sommer- und Winterzeit Umstellung.

Esp32 NTP Lokalzeit als Arduino Tab.

Bare Minimum Version
Lokalzeit.ino

// ****************************************************************
// Arduino IDE Tab Esp32 SNTP Lokalzeit Mini Modular
// created: Jens Fleischer, 2024-03-04
// last mod: Jens Fleischer, 2024-03-06
// ****************************************************************
// Hardware: Esp32
// Software: Esp32 Arduino Core 1.0.0 - 2.0.14
// Getestet auf: ESP32 NodeMCU-32s
/******************************************************************
  Copyright (c) 2024 Jens Fleischer. All rights reserved.

  This file is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.
  This file is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.
*******************************************************************/
// Diese Version von Lokalzeit sollte als Tab eingebunden werden.
// #include <WebServer.h> muss im Haupttab aufgerufen werden.
// Funktion "setupTime();" muss im setup() nach dem Verbindungsaufbau aufgerufen werden.
/**************************************************************************************/

#include "time.h"

void setupTime() {
  configTzTime("CET-1CEST,M3.5.0,M10.5.0/3", "fritz.box", "de.pool.ntp.org");
  server.on("/time", []() {
    struct tm tm;
    getLocalTime(&tm);
    static char buf[22];
    strftime (buf, sizeof(buf), "\"%d.%m.%Y %T\"", &tm);   // http://www.cplusplus.com/reference/ctime/strftime/
    server.send(200, "application/json", buf);
  });
}

Esp32 Lokalzeit als Arduino Tab.

Intervall der Abfrage einstellbar.
Lokalzeit.ino

// ****************************************************************
// Arduino IDE Tab Esp32 Lokalzeit Intervall Modular
// created: Jens Fleischer, 2024-03-06
// last mod: Jens Fleischer, 2024-03-06
// ****************************************************************
// Hardware: Esp32
// Software: Esp32 Arduino Core 2.0.0 - 2.0.14
// Getestet auf: ESP32 NodeMCU-32s
/******************************************************************
  Copyright (c) 2024 Jens Fleischer. All rights reserved.

  This file is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.
  This file is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.
*******************************************************************/
// Diese Version von Lokalzeit sollte als Tab eingebunden werden.
// #include <WebServer.h> oder #include <WiFi.h> muss im Haupttab aufgerufen werden
// Funktion "setupTime();" muss im setup() nach dem Verbindungsaufbau aufgerufen werden.
/**************************************************************************************/

#include "time.h"
#include "esp_sntp.h"

struct tm tm;

const char* const PROGMEM ntpServer[] = {"fritz.box", "de.pool.ntp.org", "at.pool.ntp.org", "ch.pool.ntp.org", "ptbtime1.ptb.de", "europe.pool.ntp.org"};
const char* const PROGMEM dayNames[] = {"Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"};
const char* const PROGMEM dayShortNames[] = {"So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"};
const char* const PROGMEM monthNames[] = {"Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"};
const char* const PROGMEM monthShortNames[] = {"Jan", "Feb", "Mrz", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez"};


void setupTime() {
  /**
    Optional für den Individuellen SNTP Update Intervall. Standart ist aller 3 Stunden.
    Der Synchronisierungsintervall in ms. ES darf nicht kleiner als 15 Sekunden sein, andernfalls werden 15 Sekunden eingestellt.
  */
   // sntp_set_sync_interval(60000);

  sntp_set_time_sync_notification_cb([](struct timeval * t) {       // Rückruffunktion - wird aufgerufen, wenn SNTP Aktualisierung erfolgte.
    DEBUG_P("********* Zeitstempel vom NTP Server erhalten! *********");
  });

  // Serielle Ausgabe des NTP Update Intervall
  DEBUG_F("SNTP Sync Interval: %02d:%02d:%02d\n", sntp_get_sync_interval() / 3600000 % 24, sntp_get_sync_interval() / 60000 % 60, sntp_get_sync_interval() / 1000 % 60);

  // Zeitzone einstellen https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv
  configTzTime("CET-1CEST,M3.5.0/02,M10.5.0/03", ntpServer[1]);     // Es können durch Komma getrennt bis zu 3 NTP Server eingegeben werden.

  server.on("/time", []() {
    server.send(200, "application/json",  localTime());
  });
}

char* localTime() {
  static char buf[22];                                              // je nach Format von "strftime" eventuell die Größe anpassen
  getLocalTime(&tm, 500);

  /** Beispiele
    DEBUG_P(dayNames[tm.tm_wday]);               // druckt den aktuellen Tag
    DEBUG_P(monthNames[tm.tm_mon]);              // druckt den aktuellen Monat
    DEBUG_P(dayShortNames[tm.tm_wday]);          // druckt den aktuellen Tag (Abk.)
    DEBUG_P(monthShortNames[tm.tm_mon]);         // druckt den aktuellen Monat (Abk.)
    DEBUG_P(tm.tm_isdst ? "Sommerzeit" : "Normalzeit");
  */
  
  strftime (buf, sizeof(buf), "\"%d.%m.%Y %T\"", &tm);              // http://www.cplusplus.com/reference/ctime/strftime/
  return buf;
}

Die "struct tm" enthält die Kalenderzeit.
Wenn du in deinem gesamten Sketch auf die Komponenten der Struktur zugreifen willst, verschiebe das includieren der "time.h" und deklarieren der "struct tm" vom Lokalzeit Tab in den Webserver Tab.

Für CoreVersion > 2.0.0
Lokalzeit.ino

// ****************************************************************
// Sketch Esp32 Lokalzeit Modular(Tab)
// created: Jens Fleischer, 2018-07-15
// last mod: Jens Fleischer, 2024-03-6
// ****************************************************************
// Hardware: Esp32
// Software: Esp32 Arduino Core 1.0.0 - 2.0.14
// Getestet auf: ESP32 NodeMCU-32s
/******************************************************************
  Copyright (c) 2018 Jens Fleischer. All rights reserved.

  This file is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.
  This file is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.
*******************************************************************/
// Diese Version von Lokalzeit sollte als Tab eingebunden werden.
// #include <WebServer.h> oder #include <WiFi.h> muss im Haupttab aufgerufen werden
// Funktion "setupTime();" muss im setup() nach dem Verbindungsaufbau aufgerufen werden.
/**************************************************************************************/

#include "time.h"

struct tm tm;

const char* const PROGMEM ntpServer[] = {"fritz.box", "de.pool.ntp.org", "at.pool.ntp.org", "ch.pool.ntp.org", "ptbtime1.ptb.de", "europe.pool.ntp.org"};
const char* const PROGMEM dayNames[] = {"Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"};
const char* const PROGMEM dayShortNames[] = {"So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"};
const char* const PROGMEM monthNames[] = {"Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"};
const char* const PROGMEM monthShortNames[] = {"Jan", "Feb", "Mrz", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez"};

bool getTime() {                                                   // Zeitzone einstellen https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv
  configTzTime("CET-1CEST,M3.5.0/02,M10.5.0/03", ntpServer[1]);    // deinen NTP Server einstellen (von 0 - 5 aus obiger Liste)
  if (!getLocalTime(&tm)) return false;
  return true;
}

void setupTime() {
  if (!getTime()) {
    DEBUG_P("Zeit konnte nicht geholt werden\n");
  } else {
    getLocalTime(&tm);
    DEBUG_P(&tm, "Programmstart: %A, %B %d %Y %H:%M:%S");
    //DEBUG_P(dayNames[tm.tm_wday]);               // druckt den aktuellen Tag
    //DEBUG_P(monthNames[tm.tm_mon]);              // druckt den aktuellen Monat
    //DEBUG_P(dayShortNames[tm.tm_wday]);          // druckt den aktuellen Tag (Abk.)
    //DEBUG_P(monthShortNames[tm.tm_mon]);         // druckt den aktuellen Monat (Abk.)
    //DEBUG_P(tm.tm_isdst ? "Sommerzeit" : "Normalzeit");
  }
  server.on("/time", []() {
    server.send(200, "application/json",  "\"" + (String)localTime() + "\"");
  });
}

char* localTime() {
  static char buf[20];                                  // je nach Format von "strftime" eventuell die Größe anpassen
  static time_t lastsec {0};
  getLocalTime(&tm, 50);
  if (tm.tm_sec != lastsec) {
    lastsec = tm.tm_sec;
    strftime (buf, sizeof(buf), "%d.%m.%Y %T ", &tm);   // http://www.cplusplus.com/reference/ctime/strftime/
    time_t now;
    if (!(time(&now) % 86400)) getTime();               // einmal am Tag die Zeit vom NTP Server holen o. jede Stunde "% 3600" aller zwei "% 7200"
  }
  return buf;
}

Der Aufruf der Funktion localTime ist nach ausführen von "setupTime();" möglich.
Du kannst "localTime();" überall in deinem Sketch einbinden.

Beispiel:

************** Lokalzeit im Setup ******************

void setup() {
 ......
 .........
  setupTime();
Serial.println(localTime());

 ......
}
Beispiel:

*************** Lokalzeit Seriell ******************

void loop() {
 ......
 .........
  static auto letzteMillis = 0;
  auto aktuelleMillis = millis();
  if (aktuelleMillis - letzteMillis >= 1000) {
    Serial.println(localTime());
    letzteMillis = aktuelleMillis;
  }
 ......
}
Beispiel:

************* Logdatei mit Lokalzeit ***************

File f = SPIFFS.open("/logdatei.txt", "a");
if (f && freeSpace(100)) {      // Anpassen an die zu schreibende Anzahl Byte
  f.printf("%s Event ausgelöst\n", localTime());
}
f.close();

Die Webseite zur Esp32 Lokalzeit mit Uhrzeit.

zeit32.html

<!DOCTYPE HTML> <!-- For more information visit: https://fipsok.de -->
<html lang="de">
  <head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<link rel="stylesheet" href="style32.css">
	<title>Uhrzeit</title>
	<style>
	  body {
		padding: .5em;
		font-size: 3.2em;
	  }
	  main {
		background-color: black;
		padding: .5em;
		border: .15em solid #909294;
		box-shadow: .3rem .4rem .4rem #5a5a5b;
		border-radius: .2em;
	  }
	  span {
		color: #00ff05;
		letter-spacing: .1em;
		font-weight: bold
	  }
	</style>
	<script>
	  async function renew() {
		let resp = await fetch('/time');
		let json = await resp.json();
		let result = json.split(/\s/);
		document.querySelector('#time').innerHTML = result[1];
	  }
	  document.addEventListener('DOMContentLoaded', renew);
	  setInterval(renew, 1000);
	</script>
  </head>
  <body>
	<main>
	  <span id="time"></span>
	</main>
  </body>
</html>

Die Webseite zur Esp32 Lokalzeit mit Uhrzeit mit Datum.

zeitdatum32.html

<!DOCTYPE HTML> <!-- For more information visit: https://fipsok.de -->
<html lang="de">
  <head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<link rel="stylesheet" href="style32.css">
	<title>Uhrzeit Datum</title>
	<script>
	  function renew() {
		fetch('/time').then(function (response) {
		  return response.json();
		}).then(function (text) {
		  var result = text.split(/\s/);
		  document.querySelector('#datum').innerHTML = result[0];
		  document.querySelector('#zeit').innerHTML = result[1];
		});
	  }
	  document.addEventListener('DOMContentLoaded', renew);
	  setInterval(renew, 1000);
	</script>
	<style>
	  body {
		padding: .5em;
		font-size: 3.2em;
	  }
	  main {
		display: flex;
		flex-direction: column;
		align-items: center;
		background-color: black;
		padding: .5em;
		border: .15em solid #909294;
		box-shadow: .3rem .4rem .4rem #5a5a5b;
		border-radius: .2em;
	  }
	  span {
		color: #00ff05;
		letter-spacing: .1em;
		font-weight: bold
	  }
	  #datum {
		font-size: .7em;
		margin-top: .5em;
	  }
	</style>
  </head>
  <body>
	<main>
	  <span id='zeit'></span>
	  <span id='datum'></span>
	</main>
  </body>
</html>