Preview build — page text is a draft awaiting human review. Code badges come from real compiles. The flasher is real but not yet hardware-tested; the Playground is still a preview.
Time · NTP

Fix ESP32/ESP8266 NTP time showing 1970 (or “Failed to obtain time”)

The clock was read before the first NTP reply arrived. Wait for sync after Wi-Fi connects, use IST (19800 s) and a reachable NTP server.

ESP32ESP32-C3ESP8266Updated 3 Nov 2026

Community draft — report a mistake

What you see

OutputOutput
Connecting to Airtel_Sharma_2.4G .... connected
Failed to obtain time
Thursday, January 01 1970 05:30:04
Thursday, January 01 1970 05:30:14

The ESP32 and ESP8266 have no battery-backed clock. Every boot starts at Unix time 0 — 1 January 1970 — until an NTP server answers. If your code reads the time before that, you get 1970 (shown as 05:30 with the IST offset) or the “Failed to obtain time” message.

configTime(19800, 0, "in.pool.ntp.org", "time.google.com");
struct tm t;
while (!getLocalTime(&t, 1000)) Serial.print('.');   // add a timeout in real code
Serial.println(&t, "%d %B %Y %H:%M:%S IST");

Quick fix — try in order

  1. 1

    Configure time after Wi-Fi connects

    Call configTime() once WiFi.status() == WL_CONNECTED. Before that, the NTP request goes nowhere.

  2. 2

    Wait for the first sync

    The reply takes 1–5 s. Loop on getLocalTime(&t, 1000) until it returns true (with a 30 s limit) before showing the time.

  3. 3

    Use the IST offset

    configTime(19800, 0, "in.pool.ntp.org", "time.google.com"). 19800 s = 5 h 30 min; India has no daylight saving, so the second number is 0.

  4. 4

    Give it more than one server

    Some college, office and ISP networks block or slow UDP port 123 to some servers. Listing two or three servers lets the core fall back.

  5. 5

    Re-sync after power cuts

    The ESP32’s clock starts at 1970 on every boot. Without Wi-Fi after a power cut, add a DS3231 RTC as backup.

Diagnostic sketch

Verified — core esp32 3.3.12, 3 Nov 2026Compile-only
fix-ntp-time-esp32.inoArduino C++Open in PlaygroundOpen in PlaygroundFlash
// NTP time for the ESP32 in Indian Standard Time — waits for the first sync instead of
// printing 1970, and says so if no NTP server answers.
#include <WiFi.h>
#include <time.h>
#include "fr_settings.h"

const char* WIFI_SSID = "YOUR_WIFI_NAME";
const char* WIFI_PASS = "YOUR_WIFI_PASSWORD";
const long GMT_OFFSET_S = 19800;  // IST = UTC + 5:30 = 19800 s. No daylight saving in India.
// Filled in from the FlashReady flasher over USB (kept on the board), or type the values above.
FrSetting SETTINGS[] = {
  {"wifi_ssid", &WIFI_SSID, true},
  {"wifi_pass", &WIFI_PASS, true},
};

bool timeValid = false;

void setup() {
  Serial.begin(115200);
  frSettingsBegin(SETTINGS);
  if (!*WIFI_SSID) {
    Serial.println("NTP off - no Wi-Fi name set. Flash from flashready.in or type it into the code.");
    return;
  }
  WiFi.begin(WIFI_SSID, WIFI_PASS);
  unsigned long t0 = millis();
  while (WiFi.status() != WL_CONNECTED && millis() - t0 < 20000) delay(300);
  if (WiFi.status() != WL_CONNECTED) {
    Serial.println("Wi-Fi did not connect - no NTP without it.");
    return;
  }

  // Three servers: if one is blocked or slow, the next is tried.
  configTime(GMT_OFFSET_S, 0, "in.pool.ntp.org", "time.google.com", "pool.ntp.org");

  struct tm now;
  Serial.print("Waiting for NTP");
  t0 = millis();
  while (!getLocalTime(&now, 1000) && millis() - t0 < 30000) Serial.print('.');
  Serial.println();
  timeValid = now.tm_year + 1900 >= 2024;
  if (!timeValid) {
    Serial.println("No NTP reply in 30 s - UDP port 123 blocked, or no internet on this Wi-Fi.");
    return;
  }
  Serial.println(&now, "Synced: %A, %d %B %Y %H:%M:%S IST");
}

void loop() {
  struct tm now;
  if (timeValid && getLocalTime(&now)) Serial.println(&now, "%H:%M:%S");
  delay(10000);
}

Why it happens

Why exactly 05:30 on 1 January 1970?

Unix time starts at 00:00 UTC on 1 Jan 1970. With the IST offset applied, “no time yet” prints as 05:30. Seeing that means the offset works and NTP hasn’t answered.

NTPClient library shows 1970 too

timeClient.update() returns false until a reply arrives. Call timeClient.begin() after Wi-Fi, setTimeOffset(19800), and retry update() until it returns true.

Time is right but 5:30 off

The offset was applied twice (configTime and your own maths) or not at all. Use one place only.

Board-specific notes

ESP8266: configTime(19800, 0, "pool.ntp.org") works too; time(nullptr) returns a small number (seconds since boot) until synced — wait until it is above 1700000000.

ESP32: Before sync, getLocalTime() waits up to 5 s and returns false, which the common example prints as “Failed to obtain time”.

Project: A clock that keeps time through power cuts: NTP LCD clock.

↑↓ to move · Enter to open