Zum Inhalt springen
ESP8266 Projekte Fortgeschrittene · 1 Std. · Aktualisiert am 22. Juli 2026

Die aktuelle Uhrzeit mit ESP8266 und ESP32 abfragen

aktuelle Uhrzeit mit dem ESP8266 abfragen

Ein ESP8266 oder ESP32 hat keine Ahnung, wie spät es ist. Nach jedem Neustart glaubt er, es sei der 1. Januar 1970 – und dabei bliebe es auch, wenn du ihm nicht auf die Sprünge hilfst. Die gute Nachricht: Wenn dein Board ohnehin im WLAN hängt, brauchst du dafür kein einziges zusätzliches Bauteil und keine Bibliothek. Ein paar Zeilen Code genügen, und dein ESP holt sich die sekundengenaue Uhrzeit aus dem Internet.

In diesem Tutorial erfährst du, wie das funktioniert – inklusive automatischer Sommerzeit-Umstellung. Der Sketch läuft unverändert auf dem ESP8266 und auf dem ESP32.

Falls dein Projekt gar nicht ins Internet kommt oder auch ohne WLAN die Zeit kennen muss, ist eine Real Time Clock die bessere Wahl. Dazu haben wir ein eigenes Tutorial über den Anschluss einer RTC.

Woher die Uhrzeit kommt

Im Internet stehen tausende Zeitserver, die nichts anderes tun, als auf Anfrage die aktuelle Uhrzeit herauszurücken. Sie sprechen dabei das Network Time Protocol, kurz NTP. Dein ESP schickt ein winziges Päckchen los, bekommt eine Zahl zurück und weiß Bescheid.

Die Adresse, die du dabei fast immer verwendest, ist pool.ntp.org. Dahinter steckt kein einzelner Server, sondern ein weltweiter Verbund von Freiwilligen – bei jeder Anfrage antwortet ein anderer. Das verteilt die Last und sorgt dafür, dass immer jemand erreichbar ist.

Der entscheidende Punkt: Diese Server liefern ausschließlich UTC – die koordinierte Weltzeit, ohne Zeitzone und ohne Sommerzeit. Ein Server in Frankfurt und einer in Tokio nennen dir im selben Moment exakt dieselbe Zahl. Aus dieser Zahl deine Ortszeit zu machen, ist die eigentliche Aufgabe. Und genau dabei nimmt dir der ESP-Core die Arbeit ab.

Mehr braucht es nicht – keine Bibliothek, die du nachinstallieren müsstest. Falls dein ESP noch nie im Netz war: Hier lernst du, wie du deinen ESP8266 oder ESP32 mit dem Internet verbindest.

Eine Zeile für alles: configTzTime()

Sobald die WLAN-Verbindung steht, richtest du die Zeitsynchronisation mit einem einzigen Aufruf ein:

configTzTime("CET-1CEST,M3.5.0/02,M10.5.0/03", "pool.ntp.org", "time.nist.gov");

Das war es. Diese Funktion gibt es auf dem ESP8266 und auf dem ESP32 unter demselben Namen und mit denselben Parametern – dein Sketch läuft also auf beiden Boards. Ab jetzt holt sich dein ESP im Hintergrund selbstständig die Zeit, etwa einmal pro Stunde, ohne dass du im Loop irgendetwas aufrufen müsstest.

Die beiden Serveradressen am Ende sind Ersatzmänner füreinander: Ist der erste nicht erreichbar, fragt dein ESP den zweiten. Der spannende Teil steckt aber im ersten Parameter.

___STEADY_PAYWALL___

Der Zeitzonen-String, entschlüsselt

CET-1CEST,M3.5.0/02,M10.5.0/03 sieht aus, als wäre jemand auf der Tastatur eingeschlafen. Tatsächlich ist es eine vollständige Beschreibung der mitteleuropäischen Zeit – inklusive der Regel, wann auf Sommerzeit umgestellt wird. Zerlegt ergibt das:

  • CET-1 – Die Normalzeit heißt CET und liegt eine Stunde vor UTC. Das Minuszeichen fühlt sich verkehrt an, ist aber Absicht: Der POSIX-Standard notiert, wie viel man von der Ortszeit abziehen muss, um bei UTC zu landen.
  • CEST – So heißt die Sommerzeit. Ohne Zahl dahinter bedeutet das schlicht „eine Stunde mehr als die Normalzeit“.
  • M3.5.0/02 – Beginn der Sommerzeit: Monat 3, die 5. Woche (das steht für „die letzte“), Wochentag 0 (Sonntag), um 2 Uhr. Also: letzter Sonntag im März, 2 Uhr.
  • M10.5.0/03 – Ende der Sommerzeit: letzter Sonntag im Oktober, 3 Uhr.

Das ist der eigentliche Gewinn: Du trägst diese Regel einmal ein, und dein ESP stellt zweimal im Jahr von allein um. Kein Neuaufspielen des Sketches im März, kein Rätseln im Oktober, warum die Uhr eine Stunde falsch geht.

Wohnst du außerhalb Mitteleuropas, tauschst du einfach den String aus. Für Großbritannien wäre das GMT0BST,M3.5.0/01,M10.5.0/02, für New York EST5EDT,M3.2.0,M11.1.0. Und falls du gar keine Zeitzone möchtest, sondern lieber direkt mit UTC arbeitest, genügt UTC0.

Auf die erste Synchronisation warten

Ein Stolperstein bleibt: configTzTime() stößt die Synchronisation nur an, sie läuft danach im Hintergrund. Fragst du die Zeit sofort in der nächsten Zeile ab, bekommst du noch den 1. Januar 1970 – dein Sketch muss kurz warten.

Der übliche Trick dafür ist charmant simpel. Du fragst die Zeit wiederholt ab und prüfst, ob sie noch verdächtig nah am Jahr 1970 liegt:

time_t jetzt = time(nullptr);
while (jetzt < 100000) {
  delay(500);
  Serial.print(".");
  jetzt = time(nullptr);
}

Solange dein ESP noch nichts vom Zeitserver gehört hat, zählt sein interner Sekundenzähler bei null los. Sobald die Antwort da ist, springt der Wert schlagartig auf über 1,7 Milliarden – so viele Sekunden sind seit 1970 vergangen. Jede Schranke irgendwo dazwischen tut es also, 100.000 ist nur eine bequeme runde Zahl.

Der vollständige Sketch

Hier alles zusammen zum Rauskopieren. Trage oben dein WLAN ein, wähle in der Arduino IDE dein Board aus und lade den Sketch hoch – der Rest passiert von allein. Die ersten Zeilen sorgen dafür, dass der Sketch auf beiden Boards die jeweils richtige WLAN-Bibliothek einbindet.

#if defined(ESP8266)
  #include <ESP8266WiFi.h>
#else
  #include <WiFi.h>
#endif

#include <time.h>

const char *ssid     = "Name deines WiFi-Netzwerks";
const char *password = "Dein WiFi-Passwort";

// Mitteleuropäische Zeit inklusive automatischer Sommerzeit-Umstellung
const char *zeitzone = "CET-1CEST,M3.5.0/02,M10.5.0/03";

char wochentage[7][12] = {"Sonntag", "Montag", "Dienstag", "Mittwoch",
                          "Donnerstag", "Freitag", "Samstag"};

void setup() {
  Serial.begin(115200);
  delay(500);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("\nIch bin mit dem Internet verbunden!");

  // Zeitzone und Zeitserver festlegen
  configTzTime(zeitzone, "pool.ntp.org", "time.nist.gov");

  // Warten, bis die Zeit vom Server angekommen ist
  Serial.print("Ich hole die Uhrzeit");
  time_t jetzt = time(nullptr);
  while (jetzt < 100000) {
    delay(500);
    Serial.print(".");
    jetzt = time(nullptr);
  }
  Serial.println(" fertig!");
}

void loop() {
  time_t jetzt = time(nullptr);

  struct tm zeit;
  localtime_r(&jetzt, &zeit);

  Serial.print(wochentage[zeit.tm_wday]);
  Serial.print(", ");

  if (zeit.tm_hour < 10) Serial.print("0");
  Serial.print(zeit.tm_hour);
  Serial.print(":");
  if (zeit.tm_min < 10) Serial.print("0");
  Serial.print(zeit.tm_min);
  Serial.print(":");
  if (zeit.tm_sec < 10) Serial.print("0");
  Serial.println(zeit.tm_sec);

  delay(1000);
}

Im Seriellen Monitor tickt jetzt sekündlich die aktuelle Uhrzeit vor sich hin – und zwar deine Ortszeit, im Sommer wie im Winter.

Beachte, dass im Loop kein einziger Aufruf mehr steht, der irgendetwas nachlädt. time() liest nur die interne Uhr deines ESP aus, die im Hintergrund mit dem Zeitserver abgeglichen wird. Du kannst diese Funktion also bedenkenlos so oft aufrufen, wie du möchtest.

Was in struct tm steckt

Die Zeile localtime_r(&jetzt, &zeit); ist das Herzstück. Sie nimmt die nackte Sekundenzahl, wendet deine Zeitzone samt Sommerzeit-Regel darauf an und legt das Ergebnis fein säuberlich zerlegt in der Struktur zeit ab. Darin findest du:

  • tm_hour, tm_min, tm_sec – Stunde (0–23), Minute und Sekunde
  • tm_mday – Tag im Monat (1–31)
  • tm_wday – Wochentag, 0 ist Sonntag
  • tm_mon – Monat, beginnt bei 0
  • tm_year – Jahr, gezählt ab 1900
  • tm_yday – Tag im Jahr (0–365)

Die beiden fett markierten Felder sind die klassische Falle. Wer sie übersieht, bekommt im Juli den Monat 6 angezeigt und schreibt sich das Jahr 126 ins Display. Richtig ist:

Serial.print(zeit.tm_mday);
Serial.print(".");
Serial.print(zeit.tm_mon + 1);      // + 1, weil Januar = 0
Serial.print(".");
Serial.println(zeit.tm_year + 1900); // + 1900, weil ab 1900 gezählt wird

Bequemer formatieren mit strftime()

Das ständige Abfragen einzelner Felder und das Voranstellen führender Nullen wird schnell mühsam. Dafür gibt es strftime(): Du gibst eine Vorlage vor, die Funktion füllt sie aus und legt das Ergebnis in einem Text-Puffer ab.

char puffer[64];
strftime(puffer, sizeof(puffer), "%d.%m.%Y – %H:%M:%S", &zeit);
Serial.println(puffer);

Das ergibt zum Beispiel 21.07.2026 – 20:15:03. Führende Nullen sind schon drin, der Monat ist korrekt umgerechnet. Nützliche Platzhalter sind %H:%M für die Uhrzeit ohne Sekunden, %d.%m. für Tag und Monat und %Y für die vierstellige Jahreszahl.

Einen Haken gibt es: Der Platzhalter %A für den Wochentag liefert dir „Monday“ statt „Montag“ – dein ESP kennt nur englische Namen. Deshalb steht im Sketch oben das Array wochentage. Mit zeit.tm_wday als Index greifst du dir daraus den deutschen Namen, und weil die Zählung bei beiden am Sonntag beginnt, passt die Reihenfolge ohne Umrechnung. Für Monatsnamen legst du dir bei Bedarf ein zweites Array an – dort ist dann aber tm_mon der Index, der ja schon bei 0 beginnt.

Die Unix Time abfragen

Ein hübsch formatiertes Datum ist ideal fürs Display, aber ungeeignet, sobald du rechnen willst. Wie viele Stunden sind es noch bis Freitag? Wie lange ist der letzte Sensorwert her? Mit „Dienstag, 20:15″ kommst du da nicht weit.

Hier kommt die Unix Time ins Spiel (auch Epoch Time, deutsch: Unixzeit). Das sind schlicht die vergangenen Sekunden seit dem 1. Januar 1970, 00:00 Uhr UTC – eine einzige große Zahl, mit der du ganz normal rechnen kannst. Der 24. August 2020 um 08:00 UTC entspricht zum Beispiel der Zahl 1598256000.

Und du hast sie längst im Sketch stehen. time(nullptr) gibt genau diesen Wert zurück:

Serial.println(time(nullptr));

Eine Differenz von 3600 bedeutet dann immer eine Stunde – egal, ob dazwischen die Zeitumstellung lag. Genau das macht die Unix Time für Countdowns und Zeitmessungen so angenehm.

Wichtig zu wissen: Dieser Wert ist immer UTC und ändert sich nicht, wenn du eine andere Zeitzone einstellst. Die Zeitzone wirkt ausschließlich in localtime_r(). Das ist kein Mangel, sondern der eigentliche Sinn der Sache: Deine Berechnungen bleiben von Zeitzonen völlig unberührt, und erst ganz am Ende – beim Anzeigen – kommt die Ortszeit ins Spiel.

Was passiert bei einem Neustart oder Netzausfall?

Zwei Situationen, über die du früher oder später stolperst:

Nach einem Neustart ist die Zeit weg. Dein ESP hat keine Batterie, die eine Uhr am Laufen hält – trennst du ihn vom Strom, beginnt er wieder bei 1970. Deshalb steht die Warteschleife im Setup: Sie sorgt dafür, dass dein Sketch erst weitermacht, wenn die Zeit wirklich da ist. Wenn dein Projekt auch ohne Netz sofort die richtige Zeit kennen muss, führt kein Weg an einer RTC mit Knopfzelle vorbei.

Fällt das WLAN aus, läuft die Uhr weiter. Dein ESP zählt die Sekunden selbst und braucht den Server nur zum gelegentlichen Nachjustieren. Ein paar Stunden ohne Internet überbrückt er problemlos, er geht dabei lediglich langsam ein wenig nach. Sobald die Verbindung zurück ist, kann er die Zeit wieder abgleichen.

Solange dein Sketch also nur die Zeit anzeigt, ist ein kurzer Aussetzer kein Drama. Kritisch wird es erst, wenn du auf eine exakte Uhrzeit hin schaltest – dann lohnt es sich, zusätzlich WiFi.status() im Auge zu behalten.

Der klassische Weg: die Bibliothek NTPClient

Vielleicht bist du schon über Sketche gestolpert, die stattdessen die Bibliothek <NTPClient.h> verwenden – auch in einigen älteren Projekten hier bei Pollux Labs. Damit du sie einordnen kannst, hier das Muster in Kurzform:

#include <NTPClient.h>
#include <WiFiUdp.h>

const long utcOffsetInSeconds = 3600;  // Winterzeit; im Sommer 7200

WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", utcOffsetInSeconds);

// im Setup:  timeClient.begin();
// im Loop:   timeClient.update();
//            Serial.println(timeClient.getFormattedTime());

Das funktioniert nach wie vor. Der Kommentar in der dritten Zeile zeigt aber schon das Problem: Du müsstest zweimal im Jahr diesen Wert ändern und den Sketch neu hochladen. Die Bibliothek kennt keine Zeitzonen, nur eine feste Verschiebung in Sekunden.

Und noch eine Tücke lauert dort: timeClient.getEpochTime() heißt zwar so, liefert dir aber nicht die echte Unix Time, sondern die bereits um deinen Offset verschobene Zahl. Rechnest du damit gegen einen Zeitstempel aus einer API, bist du je nach Jahreszeit ein bis zwei Stunden daneben – ein Fehler, der sich hervorragend versteckt.

Für neue Projekte gibt es deshalb keinen Grund mehr, zu dieser Bibliothek zu greifen. configTzTime() ist bereits an Bord, kennt die Sommerzeit und liefert saubere Unix-Zeitstempel. Falls du doch einmal in die Bibliothek schauen möchtest: Hier findest du eine Übersicht ihrer Funktionen.

Wie es weitergeht

Mit der Uhrzeit im Sketch öffnen sich eine Menge Projekte: eine Wortuhr, ein Wecker, ein Datenlogger, der jeden Messwert mit einem Zeitstempel versieht, oder eine Bewässerung, die morgens um sechs anspringt.

Und wenn dein Projekt mit Batterie laufen soll, ist der Deep Sleep mit dem ESP32 oder dem ESP8266 der nächste sinnvolle Schritt: aufwachen, Uhrzeit holen, Messwert senden, weiterschlafen.

Mehr Projekte für Arduino, ESP32, Raspi & Co
Werde Mitglied bei Pollux Labs und finde dein nächstes Projekt. Zum Beispiel:
Über 100 Maker sind bereits Mitglied bei Pollux Labs
  • ESP32 Internetradio
  • Arduino Wetterstation
  • ESP8266 & Raspi Webserver
  • Automatische Bewässerung
  • ... und viele mehr!