In this tutorial, you’ll create an ESP32 internet-connected digital clock that you can adjust for your timezone, and that automatically handles daylight saving time. The ESP32 gets the current time from an NTP server and displays it on a TM1637 4-digit 7-segment LED display, similar to classic digital clocks. The ESP32 will be programmed using Arduino IDE.

This is a great tutorial to learn about the TM1637 7-segment display and about getting time from an NTP server. For in-depth tutorials about these subjects, check the following articles:
- ESP32 NTP Time – Setting Up Timezones and Daylight Saving Time
- ESP32 with TM1637 4-Digit LED 7-Segment Display (Arduino IDE)
Prerequisites
Before proceeding, make sure you have the Arduino IDE installed and the ESP32 boards. Follow the next tutorial if you haven’t already:
Project Overview
In this tutorial, we’ll get the time from the NTP server and display it on the TM1637 4-Digit 7-Segment Display.

TM1637 4-Digit LED 7-Segment Display
The TM1637 4-Digit LED 7-Segment display is a display module that combines four 7-segment digits in a single display that can be controlled via the TM1637 driver. The particular module we’re using here has four digits separated by a colon between the second and third digits. This layout is ideal for creating a digital clock, with the hour on one side of the colon and the minutes on the other.

NTP (Network Time Protocol)
We’ll get the time for your timezone using NTP (network time protocol) with adjustment for daylight saving time.
NTP stands for Network Time Protocol, and it is a networking protocol for clock synchronization between computer systems. In other words, it is used to synchronize computer clock times in a network.

There are NTP servers like pool.ntp.org that anyone can use to request time as a client. In this case, the ESP32 is an NTP Client that requests time from an NTP Server (pool.ntp.org).
To learn more about getting time with the ESP32, you can read the following guides:
- ESP32 NTP Client-Server: Get Date and Time (Arduino IDE)
- ESP32 NTP Time – Setting Up Timezones and Daylight Saving Time
Project Layout
Here’s a quick overview of the steps we need to follow to create this project:
- Initialize the display.
- Initialize Wi-Fi and connect the ESP32 to your local network so that it can get data from the internet.
- Initialize time for your specified timezone (takes into account daylight saving time).
- Show the time on the display (blink the colon between the numbers every second).
- Every hour, connect to the NTP server to resync the timer—prevents drifting from the ESP32 internal clock.
Parts Required
For this project, you need the following parts:

- ESP32 board – any model of your choice
- TM1637 4-Digit 7-Segment Display
- Jumper Wires
You can use the preceding links or go directly to MakerAdvisor.com/tools to find all the parts for your projects at the best price!
Wiring the TM1637 4-Digit 7-Segment Display to the ESP32

Wiring the display to the ESP32 is quite simple, as it only requires two digital pins: CLK and DI/O.
| TM1637 Display | ESP32 |
| CLK | Any digital pin (for example: GPIO 19)* |
| DIO | Any digital pin (for example: GPIO 18)* |
| VCC | VIN |
| GND | GND |
* you can use any other suitable GPIOs. Check the ESP32 Pinout Guide:
- ESP32 Pinout Reference: Which GPIO pins should you use?
- ESP32-S3 DevKitC Pinout Reference Guide: GPIOs Explained
We’ll connect the CLK pin to GPIO 19, and the DIO pin to GPIO 18, but you can use a different combination of pins.

Installing the TM1637 Library
There are several libraries to interface the TM1637 display with the ESP32. We’ll use the TM1637.h library by avishorp (even though it hasn’t been updated for several years, it still works well, and it’s very easy to use).
You can install the library via the Arduino IDE library Manager. Search for TM1637 and install the library by avishorp.

Code – ESP32 with TM1637 Digital Clock
You can upload the following code to your ESP32 board. You need to:
- Insert your SSID and password
- Insert your timezone string. A list can be found on nayarsystems github’s
/*
Rui Santos & Sara Santos - Random Nerd Tutorials
Complete project details at https://RandomNerdTutorials.com/esp32-tm1637-4-digit-7-segment-display-arduino/
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/
#include <WiFi.h>
#include "time.h"
#include <TM1637Display.h>
// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
// TM1637 pins
#define CLK 19
#define DIO 18
TM1637Display display(CLK, DIO);
// Timezone (Lisbon / Portugal)
// Change if needed - See list of timezones strings: https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv
const char* TZ_INFO = "WET0WEST,M3.5.0/1,M10.5.0";
// Init Wifi
void initWiFi() {
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi..");
}
}
// Initialize Time with the specified timezone
void initTime() {
configTime(0, 0, "pool.ntp.org");
setenv("TZ", TZ_INFO, 1);
tzset();
}
// display the time on the screen
void displayTime() {
// blinking colon
static bool colon = false;
colon = !colon;
// get the current time
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
return;
}
int hours = timeinfo.tm_hour; // get hours (0–23)
int minutes = timeinfo.tm_min; // get minutes (0–59)
// move hours to the left two digits
int hourPart = hours * 100;
// combine hours and minutes into HHMM
int value = hourPart + minutes;
// control the colon (for blinking colon)
uint8_t colonMask;
if (colon == true) {
colonMask = 0b01000000; // turn colon ON
} else {
colonMask = 0; // turn colon OFF
}
display.showNumberDecEx(
value,
colonMask, // blink colon
true // leading zeros
);
}
void setup() {
Serial.begin(115200);
display.setBrightness(7);
display.clear();
initWiFi();
initTime();
}
void loop() {
displayTime();
delay(1000);
}
How Does the Code Work?
Let’s take a quick look at the code to see how it works.
Include Libraries
Start by including the required libraries.
#include <WiFi.h>
#include "time.h"
#include <TM1637Display.h>
Network Credentials
Insert your network credentials on the following lines.
// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
FreeRTOS Timer Handle
We create a handle for the FreeRTOS timer we’ll create in the code. This timer will periodically call a callback function every hour (SYNC_INTERVAL) that will make a new request to the NTP server to get the time.
// Resync clock
TimerHandle_t syncTimer = NULL;
const unsigned long SYNC_INTERVAL = 3600000UL; // 1 hour (3600000 ms)
To learn more about FreeRTOS timers, check this tutorial: ESP32 with FreeRTOS: Software Timers/Timer Interrupts (Arduino IDE).
Initialize the Display
Set the TM1637 pins and create an instance for the display called display.
// TM1637 pins
#define CLK 19
#define DIO 18
TM1637Display display(CLK, DIO);
Timezone
Insert your timezone string in the following line. You can find a list of timezone strings. In my case, my timezone is Lisbon/Portugal, so it will look as follows:
const char* TZ_INFO = "WET0WEST,M3.5.0/1,M10.5.0";
Initialize Wi-Fi
The following function initializes Wi-Fi and connects the ESP32 to your local network. This will be called later on in the setup().
// Init Wifi
void initWiFi() {
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi..");
}
}
You can learn more about the ESP32 Wi-Fi function in the following tutorial:
Initialize Time
The initTime() function initializes NTP time and adjusts it to your timezone—notice the setenv() and tzset() functions.
// Initialize Time with the specified timezone
void initTime() {
configTime(0, 0, "pool.ntp.org");
setenv("TZ", TZ_INFO, 1);
tzset();
}
To learn more about getting the date and time with timezone adjustment, check out this tutorial:
The displayTime() function will display the date and time on the screen.
void displayTime() {
We have a boolean variable called colon to determine whether the colon is showing up or not (to create the blinking effect).
// blinking colon
static bool colon = false;
colon = !colon;
We get the current time and save it in the timeinfo structure.
// get the current time
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
return;
}
Then, we can get the hour and minutes as follows:
int hours = timeinfo.tm_hour; // get hours (0–23)
int minutes = timeinfo.tm_min; // get minutes (0–59)
Now, to display the numbers on the screen, we need to combine the date and time in a single number with four digits that will be split in the middle by the colon.
We can do that by multiplying the hour by 100 and then adding the minutes.
// move hours to the left two digits
int hourPart = hours * 100;
// combine hours and minutes into HHMM
int value = hourPart + minutes;
For example, imagine the hour is 12 and the minutes are 30. We want to get 12:30. So, we need to get the 1230 number and display the colon in the middle.
12*100+30 will give the desired 1230. This number is saved in the value variable.
Finally, we adjust the bitmask to display the colon depending on whether it is time to display the colon.
// control the colon (for blinking colon)
uint8_t colonMask;
if (colon == true) {
colonMask = 0b01000000; // turn colon ON
} else {
colonMask = 0; // turn colon OFF
}
We can use the showNumberDecEx() to display the time on the screen. Pass as an argument the value, the bit mask for the colon, and whether we have leading zeros.
display.showNumberDecEx(
value,
colonMask, // blink colon
true // leading zeros
);
Now that we have all the essential functions declared, it is easy to set up our code.
syncTimeCallback()
The syncTimeCallback() function will be called by the FreeRTOS timer every hour. This function simply calls the initTime() function we created previously to resync the time with the NTP server. This prevents time drifting from the ESP32 internal clock.
void syncTimeCallback(TimerHandle_t xTimer) {
Serial.println("Resyncing time with NTP...");
initTime();
}
setup()
In the setup() initialize the Serial Monitor, set the display brightness, initialize Wi-Fi, and time.
void setup() {
Serial.begin(115200);
display.setBrightness(7);
display.clear();
initWiFi();
initTime();
Still in the setup(), we create the FreeRTOS timer and start it with xTimerStart().
//Create timer to sync time periodically
syncTimer = xTimerCreate(
"syncTimer", // Timer name
pdMS_TO_TICKS(SYNC_INTERVAL), // Period in ticks
pdTRUE, // Auto-reload (periodic timer)
NULL, // Timer ID
syncTimeCallback // Callback function
);
if (syncTimer == NULL) {
Serial.println("Failed to create timer!");
while (1);
}
xTimerStart(syncTimer, 0); // Start timer immediately
Again, to learn more about the FreeRTOS timers, you can check this tutorial.
loop()
Finally, in the loop(), you just need to call the displayTime() function to display the time on the 4-digit 7-segment display module.
void loop() {
displayTime();
delay(1000);
}
Demonstration
After inserting your network credentials and your timezone information, you can upload the code to the ESP32.
It should start displaying the current time for your timezone.

The colon should be blinking every second to resemble those old digital clocks. Additionally, every hour, the ESP32 should reconnect to the NTP server to request and sync the time.
Wrapping Up
In this tutorial, you learned how to create an internet digital clock with the ESP32 and the TM1637 7-Segment Display. This tutorial can easily be adjusted to use a different display, like an OLED, LCD, or even a TFT display.
Similar projects:
- Arduino Digital Clock with DS3231 RTC and OLED Display (easily adjusted to use with an ESP32)
- ESP32 TFT with LVGL: Digital Clock with Time and Date
Learn more about the ESP32 with our resources:




