Getting Date & Time From NTP Server With ESP32

Every once in a while you’ll come across an idea where keeping time a prime concern. For example, imagine a relay that has to be activated at a certain time or a data logger that has to store values at precise intervals.

The first thing that comes in your mind is to use an RTC (Real Time Clock) chip. But these chips are not perfectly accurate so, you need to do manual adjustments over and over again to keep them synchronized.

The solution here is to use Network Time Protocol (NTP). If your ESP32 project has access to the Internet, you can get date and time (with a precision within a few milliseconds of UTC) for FREE. You don’t need any additional hardware.

What is an NTP?

An NTP stands for Network Time Protocol. It’s a standard Internet Protocol (IP) for synchronizing the computer clocks to some reference over a network.

The protocol can be used to synchronize all networked devices to Coordinated Universal Time (UTC) within a few milliseconds ( 50 milliseconds over the public Internet and under 5 milliseconds in a LAN environment).

Coordinated Universal Time (UTC) is a world-wide time standard, closely related to GMT (Greenwich Mean Time). UTC does not vary, it is the same world wide.

NTP sets the clocks of computers to UTC, any local time zone offset or day light saving time offset is applied by the client. In this manner clients can synchronize to servers regardless of location and time zone differences.

NTP Architecture

NTP uses a hierarchical architecture. Each level in the hierarchy is known as a stratum.

At the very top are high-precision timekeeping devices, such as atomic clocks, GPS or radio clocks, known as stratum 0 hardware clocks.

Stratum 1 servers have a direct connection to a stratum 0 hardware clock and therefore have the most accurate time.

NTP Hierarchical Architecture With Stratums

Each stratum in the hierarchy synchronizes to the stratum above and act as servers for lower stratum computers.

How NTP Works?

NTP can operate in a number of ways. The most common configuration is to operate in client-server mode. The basic working principle is as follows:

  1. The client device such as ESP32 connects to the server using the User Datagram Protocol (UDP) on port 123.
  2. A client then transmits a request packet to a NTP server.
  3. In response to this request the NTP server sends a time stamp packet.
  4. A time stamp packet contains multiple information like UNIX timestamp, accuracy, delay or timezone.
  5. A client can then parse out current date & time values.
NTP Server Working - Request & Timestamp Packet Transfer

Preparing the Arduino IDE

Enough of the theory, Let’s Go Practical!

But before venturing further into this tutorial, you should have the ESP32 add-on installed in your Arduino IDE. Follow below tutorial to prepare your Arduino IDE to work with the ESP32, if you haven’t already.

Tutorial of Programming ESP32 in Arduino IDE
Insight Into ESP32 Features & Using It With Arduino IDE
Few years back, ESP8266 took the embedded IoT world by storm. For less than $3, you could get a programmable, WiFi-enabled microcontroller being able to...

Getting Date and Time from NTP Server

The following sketch will give you complete understanding on how to get date and time from the NTP Server.

Before you head for uploading the sketch, you need to make some changes to make it work for you.

  • You need to modify the following two variables with your network credentials, so that ESP32 can establish a connection with existing network.
    const char* ssid       = "YOUR_SSID";
    const char* password   = "YOUR_PASS";
  • You need to adjust the UTC offset for your timezone in milliseconds. Refer the list of UTC time offsets. Here are some examples for different timezones:
    • For UTC -5.00 : -5 * 60 * 60 : -18000
    • For UTC +1.00 : 1 * 60 * 60 : 3600
    • For UTC +0.00 : 0 * 60 * 60 : 0
    const long  gmtOffset_sec = 3600;
  • Change the Daylight offset in milliseconds. If your country observes Daylight saving time set it to 3600. Otherwise, set it to 0.
    const int   daylightOffset_sec = 3600;

Once you are done, go ahead and try the sketch out.

#include <WiFi.h>
#include "time.h"

const char* ssid       = "YOUR_SSID";
const char* password   = "YOUR_PASS";

const char* ntpServer = "pool.ntp.org";
const long  gmtOffset_sec = 3600;
const int   daylightOffset_sec = 3600;

void printLocalTime()
{
  struct tm timeinfo;
  if(!getLocalTime(&timeinfo)){
    Serial.println("Failed to obtain time");
    return;
  }
  Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S");
}

void setup()
{
  Serial.begin(115200);
  
  //connect to WiFi
  Serial.printf("Connecting to %s ", ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      Serial.print(".");
  }
  Serial.println(" CONNECTED");
  
  //init and get the time
  configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
  printLocalTime();

  //disconnect WiFi as it's no longer needed
  WiFi.disconnect(true);
  WiFi.mode(WIFI_OFF);
}

void loop()
{
  delay(1000);
  printLocalTime();
}

After uploading the sketch, press the EN button on your ESP32, and you should get the date and time every second as shown below.

ESP32 Reads Date & Time From NTP Server Output On Serial monitor

Code Explanation

Let’s take a quick look at the code to see how it works. First, we include the libraries needed for this project.

  • WiFi.h library provides ESP32 specific WiFi methods we are calling to connect to network.
  • time.h is the ESP32 native time library which does graceful NTP server synchronization.
#include <WiFi.h>
#include "time.h"

Next, we set up a few constants like SSID, WiFi password, UTC Offset & Daylight offset that you are already aware of.

Along with that we need to specify the address of the NTP Server we wish to use. pool.ntp.org is an open NTP project great for things like this.

const char* ntpServer = "pool.ntp.org";

The pool.ntp.org automatically picks time servers which are geographically close for you. But if you want to choose explicitly, use one of the sub-zones of pool.ntp.org.

AreaHostName
Worldwidepool.ntp.org
Asiaasia.pool.ntp.org
Europeeurope.pool.ntp.org
North Americanorth-america.pool.ntp.org
Oceaniaoceania.pool.ntp.org
South Americasouth-america.pool.ntp.org

In setup section, we first initialize serial communication with PC and join the WiFi network using WiFi.begin() function.

Serial.begin(115200);

//connect to WiFi
Serial.printf("Connecting to %s ", ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
  delay(500);
  Serial.print(".");
}
Serial.println(" CONNECTED");

Once ESP32 is connected to the network, we initialize the NTP client using configTime() function to get date and time from an NTP server.

//init and get the time
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);

Now we can simply call the printLocalTime() custom function whenever we want to print current date & time.

getLocalTime() function is used to transmit a request packet to a NTP server and parse the received time stamp packet into to a readable format. It takes time structure as a parameter.

You can access the date & time information by accessing members of this time structure.

%Areturns day of week
%Breturns month of year
%dreturns day of month
%Yreturns year
%Hreturns hour
%Mreturns minutes
%Sreturns seconds
void printLocalTime()
{
  struct tm timeinfo;
  if(!getLocalTime(&timeinfo)){
    Serial.println("Failed to obtain time");
    return;
  }
  Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S");
}