Update: 2023-01-08

ESP8266 NTP Zeitsynchronisation per WLAN mit Automatischer Sommer- und Winterzeit Umstellung.

Ab EspCoreVersion 2.6.0

Esp8266 NTP Lokalzeit als Arduino Tab.

Bare Minimum Version Lokalzeit.ino

// ****************************************************************
// Sketch Esp8266 NTP Lokalzeit Mini Modular(Tab)
// created: Jens Fleischer, 2020-12-25
// last mod: Jens Fleischer, 2020-12-25
// For more information visit: https://fipsok.de
// ****************************************************************
// Hardware: Esp8266
// Software: Esp8266 Arduino Core 2.6.0 - 3.0.0
// Getestet auf: Nodemcu, Wemos D1 Mini Pro, Sonoff Switch, Sonoff Dual
/******************************************************************
  Copyright (c) 2020 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 <ESP8266WebServer.h> muss im Haupttab aufgerufen werden.
// Funktion "setupTime();" muss im setup() nach dem Verbindungsaufbau aufgerufen werden.
// Der Interne Zeitstempel wird automatisch jede Stunde mit dem NTP Server synchronisiert.
// Automatische Umstellung zwischen Sommer- und Normalzeit anhand der Zeitzone.
/**************************************************************************************/

#include <time.h>

void setupTime() {
  // Zeitzone einstellen https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv
  // Es können durch Komma getrennt bis zu 3 NTP Server eingegeben werden.
  configTime("CET-1CEST,M3.5.0,M10.5.0/3", "fritz.box", "de.pool.ntp.org");
  server.on("/time", []() {
    server.send(200, "application/json", localTime());
  });
}

char* localTime() {
  struct tm tm;
  static char buf[26];
  time_t now = time(&now);
  localtime_r(&now, &tm);
  strftime (buf, sizeof(buf), R"(["%T","%d.%m.%Y"])", &tm);   // http://www.cplusplus.com/reference/ctime/strftime/
  return buf;
}

Esp8266 NTP Lokalzeit mit einstellbarem Intervall für die Synchronisation.

Lokalzeit.ino

// ****************************************************************
// Sketch Esp8266 SNTP Lokalzeit Modular(Tab)
// created: Jens Fleischer, 2020-10-10
// last mod: Jens Fleischer, 2020-12-25
// For more information visit: https://fipsok.de
// ****************************************************************
// Hardware: Esp8266
// Software: Esp8266 Arduino Core 2.6.0 - 3.0.0
// Getestet auf: Nodemcu, Wemos D1 Mini Pro, Sonoff Switch, Sonoff Dual
/******************************************************************
  Copyright (c) 2020 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 <ESP8266WebServer.h> muss im Haupttab aufgerufen werden.
// Funktion "setupTime();" muss im setup() nach dem Verbindungsaufbau aufgerufen werden.
// Automatische Umstellung zwischen Sommer- und Normalzeit anhand der Zeitzone.
/**************************************************************************************/

#include <time.h>

const uint32_t SYNC_INTERVAL = 12;                              // NTP Sync Interval in Stunden einstellen

struct tm tm;

const char* const PROGMEM NTP_SERVER[] = {"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 DAY_NAMES[] = {"Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"};
const char* const PROGMEM DAY_SHORT[] = {"So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"};
const char* const PROGMEM MONTH_NAMES[] = {"Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"};
const char* const PROGMEM MONTH_SHORT[] = {"Jan", "Feb", "Mrz", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez"};

void setupTime() {      // deinen NTP Server einstellen (von 0 - 5 aus obiger Liste) alternativ lassen sich durch Komma getrennt bis zu 3 Server angeben
  configTime("CET-1CEST,M3.5.0,M10.5.0/3", NTP_SERVER[1]);      // Zeitzone einstellen https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv
  server.on("/time", []() {
    server.send(200, "application/json", localTime());
  });
}

uint32_t sntp_update_delay_MS_rfc_not_less_than_15000() {       // Optionale Funktion, für den Individuellen SNTP Update Intervall. Standart ist jede Stunde.
  return SYNC_INTERVAL * 36e5;                                  // SNTP-Aktualisierungsverzögerung ändern.
}

String localTime() {
  static char buf[26];                                          // je nach Format von "strftime" eventuell anpassen
  static time_t previous;
  time_t now = time(&now);
  if (now != previous) {
    previous = now;
    localtime_r(&now, &tm);
    /* Verwendungbeispiele
      Serial.println(DAY_NAMES[tm.tm_wday]);                      // druckt den aktuellen Tag
      Serial.println(MONTH_NAMES[tm.tm_mon]);                     // druckt den aktuellen Monat
      Serial.println(DAY_SHORT[tm.tm_wday]);                      // druckt den aktuellen Tag (Abk.)
      Serial.println(MONTH_SHORT[tm.tm_mon]);                     // druckt den aktuellen Monat (Abk.)
    */
    strftime (buf, sizeof(buf), R"(["%T","%d.%m.%Y"])", &tm);   // http://www.cplusplus.com/reference/ctime/strftime/
  }
  return buf;
}

Esp8266 NTP Lokalzeit mit Abfrage ob die Zeit vom Server geholt werden konnte.

Lokalzeit.ino

// ****************************************************************
// Sketch Esp8266 NTP Lokalzeit Modular(Tab)
// created: Jens Fleischer, 2020-09-20
// last mod: Jens Fleischer, 2020-12-25
// For more information visit: https://fipsok.de
// ****************************************************************
// Hardware: Esp8266
// Software: Esp8266 Arduino Core 2.6.0 - 3.1.0
// Getestet auf: Nodemcu, Wemos D1 Mini Pro, Sonoff Switch, Sonoff Dual
/******************************************************************
  Copyright (c) 2020 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 <ESP8266WebServer.h> muss im Haupttab aufgerufen werden.
// Funktion "setupTime();" muss im setup() nach dem Verbindungsaufbau aufgerufen werden.
// Automatische Umstellung zwischen Sommer- und Normalzeit anhand der Zeitzone.
// Inclusive Abfrage ob die Zeit vom NTP Server geholt werden konnte.
/**************************************************************************************/

#include <time.h>
#include <coredecls.h>

struct tm tm;

constexpr uint32_t SYNC_INTERVAL = 12;                           // NTP Sync Interval in Stunden einstellen
bool timeSync;

const char* const PROGMEM NTP_SERVER[] = {"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 DAY_NAMES[] = {"Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"};
const char* const PROGMEM DAY_SHORT[] = {"So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"};
const char* const PROGMEM MONTH_NAMES[] = {"Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"};
const char* const PROGMEM MONTH_SHORT[] = {"Jan", "Feb", "Mrz", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez"};

void time_is_set() {                                             // Diese Funktion wird als Rückruf festgelegt, wenn Zeitdaten abgerufen wurden.
  timeSync = true;                                               // "timeSync" bleibt ab jetzt auf true um den Programmablauf nicht zu verzögern.
  Serial.println("********* NTP Server Timestap Synchronisation  *********");
}

// Eine schwache Funktion ist bereits definiert und gibt 0 zurück (RFC 4330 Best Practices Verletzung)
uint32_t sntp_startup_delay_MS_rfc_not_less_than_60000 () {      //  Optionale Funktion, SNTP-Startverzögerung ändern
  return random(INT32_MAX) % 2000;
}

uint32_t sntp_update_delay_MS_rfc_not_less_than_15000() {        // Optionale Funktion, für den Individuellen SNTP Update Intervall. Standart ist jede Stunde.
  return SYNC_INTERVAL * 36e5;                                   // SNTP-Aktualisierungsverzögerung ändern.
}

void setupTime() {      // deinen NTP Server einstellen (von 0 - 5 aus obiger Liste) alternativ lassen sich durch Komma getrennt bis zu 3 Server angeben
  configTime("CET-1CEST,M3.5.0,M10.5.0/3", NTP_SERVER[1]);       // Zeitzone einstellen https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv
  settimeofday_cb(time_is_set);                                  // Rückruf installieren - wird aufgerufen, wenn Settimeofday aufgerufen wird.
  server.on("/time", []() {
    server.send(200, "application/json", localTime());
  });
}

String localTime() {
  static char buf[26];                                           // je nach Format von "strftime" eventuell anpassen
  static time_t previous;
  time_t now = time(NULL);
  if (now != previous) {
    previous = now;
    if (timeSync) {
      localtime_r(&now, &tm);
      /* Verwendungbeispiele
        Serial.println(DAY_NAMES[tm.tm_wday]);                     // druckt den aktuellen Tag
        Serial.println(MONTH_NAMES[tm.tm_mon]);                    // druckt den aktuellen Monat
        Serial.println(DAY_SHORT[tm.tm_wday]);                     // druckt den aktuellen Tag (Abk.)
        Serial.println(MONTH_SHORT[tm.tm_mon]);                    // druckt den aktuellen Monat (Abk.)
      */
      strftime(buf, sizeof(buf), R"(["%T","%d.%m.%Y"])", &tm);   // http://www.cplusplus.com/reference/ctime/strftime/
      Serial.println(buf);
    }
    else {
      snprintf(buf, sizeof(buf), R"(["Warte","auf Sync"])");     // Optional für die Anzeige auf der Webseite
      Serial.println("Warten auf NTP Synchronisation!");
    }
  }
  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.

Der Aufruf der Funktion "localTime();" ist nach ausführen von "setupTime();" möglich.

Beispiel:

************** Zeitstempel im Setup ******************

void setup() {
 ......
 .........
  setupTime();
  Serial.println("Programmstart: " + localTime());
 ......
}

Du kannst den Aufruf der "localTime();" als Zeitstempel nutzen.

Beispiel:

******* Push Nachricht mit Text und Zeitstempel ******

pushbullet("Füllstand Minimum " + localTime());
Beispiel:

*************** Zeitstempel im Loop ******************

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

************* Logdatei mit Zeitstempel ***************

File f = LittleFS.open("/logdatei.txt", "a");
if (f) {
  f.printf("%s Event ausgelöst\n", localTime().c_str());
}
f.close();

Die Webseite zur Esp8266 Uhrzeit.

zeit.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.0">
    <link rel="stylesheet" href="style.css">
    <title>Uhrzeit</title>
    <script>
      function renew() {
        fetch('/time').then(function (response) {
          return response.json();
        }).then(function (array) {
          document.querySelector('span').innerHTML = array[0];;
        });
      }
      document.addEventListener('DOMContentLoaded', renew, setInterval(renew, 1000));
    </script>
    <style>
      body {
        padding: 10px;
        font-size: 3.2em;
      }
      main {
		display: flex;
        flex-direction: column;
        align-items: center;
        background-color: black;
        width: 280px;
        height: 100px;
        padding: .2em;
        border: .15em solid #aeaeab;
        box-shadow: 5px 10px 5px rgba(0, 0, 0, 0.7);
        border-radius: .2em;
      }
      span {
        color: #02fc07;
        position: relative;
        top: .5em;
        left: .1em;
        letter-spacing: .1em;
        font-weight: bold
      }
    </style>
  </head>
  <body>
    <main>
      <span></span>
    </main>
  </body>
</html>

Die Webseite zur Esp8266 Uhrzeit mit Datum.

zeitdatum.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.0">
    <link rel="stylesheet" href="style.css">
    <title>Uhrzeit</title>
    <script>
      function renew() {
        fetch('/time').then(response => {
          return response.json();
        }).then(array => {
		  document.querySelector('#time').innerHTML = array[0];
          document.querySelector('#date').innerHTML = array[1];
        });
      }
      document.addEventListener('DOMContentLoaded', renew, setInterval(renew, 1000));
    </script>
    <style>
      body {
        padding: 10px;
        font-size: 3.2em;
      }
      main {
		display: flex;
        flex-direction: column;
        align-items: center;
        background-color: black;
        width: 280px;
        height: 140px;
        padding: .2em;
        border: .15em solid #aeaeab;
        box-shadow: 5px 10px 5px rgba(0, 0, 0, 0.7);
        border-radius: .2em;
      }
      span {
        color: #00ff05;
        position: relative;
        top: .3em;
        left: .1em;
        letter-spacing: .1em;
        font-weight: bold
      }
	  #date {
        font-size: .7em;
        margin-top: .5em;
      }
    </style>
  </head>
  <body>
    <main>
      <span id="time"></span>
      <span id="date"></span>
    </main>
  </body>
</html>

NTP Update Demonstration.

NTPUpdateDemo.ino

// ****************************************************************
// Sketch Esp8266 WiFi NTP Update Demo
// created: Jens Fleischer, 2020-12-25
// last mod: Jens Fleischer, 2020-12-25
// For more information visit: https://fipsok.de
// ****************************************************************
// Hardware: Esp8266
// Software: Esp8266 Arduino Core 2.7.0 - 2.7.4
// Getestet auf: Nodemcu, Wemos D1 Mini Pro
/******************************************************************
  Copyright (c) 2020 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.
*******************************************************************/
// NTP Update Demonstration mittels im Esp Core enthaltenen Bibliotheken.
// Automatische Umstellung zwischen Sommer- und Normalzeit anhand der Zeitzone.
/**************************************************************************************/

#include <ESP8266WiFi.h>
#include <time.h>
#include <coredecls.h>

const char* ssid = "Netzwerkname";                          // << kann bis zu 32 Zeichen haben
const char* password = "PasswortvomNetzwerk";               // << mindestens 8 Zeichen jedoch nicht länger als 64 Zeichen

extern uint32_t sntp_real_timestamp;                        // Variable enthält den Unix Zeitstempel

void time_is_set() {                                        //Diese Funktion wird als Rückruf festgelegt, wenn Zeitdaten abgerufen wurden.
  Serial.println("********* NTP Server Timestap Synchronisation  *********");
}

uint32_t sntp_update_delay_MS_rfc_not_less_than_15000 () {  // SNTP-Aktualisierungsverzögerung ändern, ohne diese Funktion wird jede Stunde die Zeit geholt.
  return 18000;                                             // NTP Server Abfrage für diese Demo aller 18 Sekunden
}

void setup() {
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) yield();
  configTime("CET-1CEST,M3.5.0/02,M10.5.0/03", "de.pool.ntp.org");
  settimeofday_cb(time_is_set);                             // Rückruf installieren - wird aufgerufen, wenn Settimeofday aufgerufen wird.
  Serial.println("\nSNTP UPDATE DEMO");
}

void loop() {
  tm tm;
  char buf[20];
  constexpr uint32_t INTERVAL {1000};
  static uint32_t previousMillis;
  if (millis() - previousMillis >= INTERVAL) {
    previousMillis += INTERVAL;
    time_t now = time(nullptr);
    localtime_r(&now, &tm);
    strftime (buf, sizeof(buf), "%d.%m.%Y %T", &tm);
    Serial.println(buf);
    if (tm.tm_sec == 25) sntp_real_timestamp = 0;           // Internen Zeitstempel in Sekunde 25 zurücksetzen
  }
}