Skip to content

rawify/NTP-Client

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

NTP Client for ESP32 and ESP8266

A tiny NTP client for ESP32 and ESP8266 that:

  • Talks to NTP servers via UDP (e.g. pool.ntp.org)
  • Keeps time locally using millis() between synchronizations
  • Supports time zones via a simple offset in seconds
  • Exposes both a Unix timestamp and a human-readable date/time struct

It is designed to be:

  • Small - only depends on Arduino’s UDP interface
  • Portable - works with WiFiUDP, EthernetUDP, etc.
  • Friendly to NTP servers - you decide how often to sync

Quickstart Example (ESP32, WiFi events)

#include <WiFi.h>
#include <WiFiUdp.h>
#include <ntp.h>

// WiFi settings
const char *ssid   = "...";
const char *passwd = "...";

// --- Time settings ---
constexpr int32_t  TIME_OFFSET_SECONDS   = 2 * 3600;              // UTC+2
constexpr uint32_t NTP_SYNC_INTERVAL_MS  = 60UL * 60UL * 1000UL;  // 1 hour

WiFiUDP udp;
NTP ntp(udp);

bool     connected = false;
uint32_t lastSync  = 0;

// ESP32 WiFi event handler
void WiFiEvent(system_event_id_t event) {
  switch (event) {
    case SYSTEM_EVENT_STA_GOT_IP:
      connected = true;
      ntp.begin();                   // start UDP for NTP
      break;

    case SYSTEM_EVENT_STA_DISCONNECTED:
      connected = false;
      ntp.end();                     // stop UDP when WiFi is down
      WiFi.reconnect();              // optional: auto reconnect
      break;

    default:
      break;
  }
}

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

  WiFi.onEvent(WiFiEvent);
  WiFi.begin(ssid, passwd);

  // Set time offset to GMT+2:00
  ntp.setTimeOffset(TIME_OFFSET_SECONDS);
}

void loop() {
  if (!connected) {
    return;
  }

  uint32_t nowMs = millis();

  // Sync with NTP once per hour (or on first successful connection)
  if (!ntp.isValid() || (nowMs - lastSync >= NTP_SYNC_INTERVAL_MS)) {
    if (ntp.update()) {
      lastSync = nowMs;
      Serial.println(F("NTP time updated"));
    } else {
      Serial.println(F("NTP update failed"));
    }
  }

  // Print current local time once per second
  if (ntp.isValid()) {
    static uint32_t lastPrint = 0;
    if (nowMs - lastPrint >= 1000) {
      lastPrint = nowMs;

      ntp_datetime_t t = ntp.getDateTime();
      Serial.printf("%02u.%02u.%04u  %02u:%02u:%02u\n",
                    t.day, t.month, t.year,
                    t.hour, t.minute, t.second);
    }
  }

  // put your other logic here (no delay() needed)
}

Note You should not call update() every second in production. Synchronize periodically (e.g. every 30-60 minutes) and use the library’s internal millis()-based timekeeping between syncs.

Data Type

The library returns a simple struct for human-readable time:

typedef struct {
  uint8_t  day;
  uint8_t  month;
  uint16_t year;
  uint8_t  hour;
  uint8_t  minute;
  uint8_t  second;
} ntp_datetime_t;

Constructors

You must pass an existing UDP instance (e.g. WiFiUDP):

NTP(UDP& udp);
NTP(UDP& udp, const char *address);
  • udp - any object implementing the UDP interface (e.g. WiFiUDP, EthernetUDP)
  • address - optional NTP server hostname or IP (default: "pool.ntp.org")

You can also change the server later:

void setServer(const char *address);

Methods

begin

Create a local UDP socket for NTP:

void begin(uint16_t port = NTP_DEFAULT_LOCAL_PORT);
  • port - local UDP port to bind (default: 9876)

Call this when the network connection is up (WiFi.status() == WL_CONNECTED or WiFi event SYSTEM_EVENT_STA_GOT_IP).

end

Close the UDP socket:

void end();

Call this when the network goes down or before shutting down.

update

Query the NTP server and update the internal UTC timestamp:

bool update(uint16_t timeoutMs = NTP_DEFAULT_TIMEOUT_MS);
  • timeoutMs - maximum time to wait for a response (default: 1000 ms)
  • Returns true on success, false on timeout or invalid response.

The library:

  • Sends one NTP request packet
  • Waits for a valid NTP response
  • Extracts the server’s transmit timestamp (seconds since 1900-01-01)
  • Converts it to Unix time (seconds since 1970-01-01)
  • Stores this as the reference time and remembers the millis() value at that moment

Between calls to update(), the current time is derived from the last synced time plus the elapsed millis().

isValid

Check if the client has ever synchronized successfully:

bool isValid() const;

Returns true after the first successful update(). Use this to avoid printing bogus times before the first sync.

getTimestamp

Get the current UTC time (no time offset applied):

uint32_t getTimestamp() const;
  • Returns seconds since 1970-01-01 00:00:00 UTC
  • Uses the last NTP sync plus elapsed millis().

getEpochTime

Get the current local epoch time (UTC + time offset):

uint32_t getEpochTime() const;
  • Returns seconds since 1970-01-01 00:00:00 local time
  • Local time = UTC + time offset set via setTimeOffset().

getDateTime

Get a human-readable local date/time:

ntp_datetime_t getDateTime() const;
  • Uses getEpochTime() internally
  • Returns {day, month, year, hour, minute, second} for your local time zone
  • If there has not been a valid sync yet, all fields will be 0.

setTimeOffset

Set your time zone offset in seconds relative to UTC:

void setTimeOffset(int32_t timeOffsetSeconds);

Examples:

  • UTC → 0
  • UTC+1 (CET) → 1 * 3600
  • UTC+2 → 2 * 3600
  • UTC−5 → -5 * 3600

This offset is applied by getEpochTime() and getDateTime().

Best Practices

  • Do not spam NTP servers: Synchronize at most every few minutes, preferably every 30-60 minutes for most IoT use-cases.
  • Use isValid() before trusting the time: Only print or act on timestamps after the first successful update().
  • Let the MCU keep time between syncs: The library already uses millis() to advance the time, so you do not need an external RTC for many applications.
  • Handle WiFi dropouts: If WiFi disconnects, stop NTP (end()), reconnect WiFi, and then call begin() again when the connection is restored.

Copyright and licensing

Copyright (c) 2025, Robert Eisele Licensed under the MIT license.

About

NTP Client for ESP32 and ESP8266

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages