DST with NodeMCU

Hi there,

I've been trying to work out how to get the time to automatically adjust in line with UK Daylight Savings Time.

I found some code, that gives me the time but it seems to do it on a temporary basis. For example, in the code below, I reference a field called "local" which displays the correct hour value. However, if I try to print the value a second time, it goes back to Epoch time.

I used to get the time by using the get.hours command but that is not working as expected.

Is there an easy way to get the uk local time without faffing around too much ?

Many thanks, in advance

TK

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

// Define your WiFi credentials
const char* ssid = "SSID";
const char* password = "Password";

// Define your timezone offset and whether it observes DST
TimeChangeRule BST = {"BST", Last, Sun, Mar, 1, 60}; // British Summer Time
TimeChangeRule GMT = {"GMT", Last, Sun, Oct, 2, 0};  // Greenwich Mean Time
Timezone UK(BST, GMT);

// Define NTP client and time server settings
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org");

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

  // Connect to WiFi
  WiFi.begin(ssid, password);
  Serial.print("Connecting to WiFi");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected.");

  // Initialize NTP client
  timeClient.begin();
  timeClient.setTimeOffset(0); // Set time offset to UTC (NTP servers return UTC time)
}

void loop() {
  // Update time from NTP server
  timeClient.update();
  unsigned long epochTime = timeClient.getEpochTime(); // Get Unix timestamp from NTP server
  time_t utc = epochTime;
  time_t local = UK.toLocal(utc); // Convert UTC time to local time (DST adjusted)

   int now_hour = timeClient.getHours(); // This is the command I usually use but it's become inaccurate as of a couple of days ago, when the clocks changed.

   Serial.print("now_hour ");
   Serial.println(now_hour);


  // Print the DST adjusted local time
  Serial.print("DST Adjusted Local time: ");
  digitalClockDisplay(local);
  Serial.print("DST Adjusted Local time TWO: ");
  Serial.println(local); // The line above prints the correct value, this line prints the Epoch value again!


  delay(1000);
}

void digitalClockDisplay(time_t t) {
  static char local[20];
  sprintf(local, "%02d:%02d:%02d", hour(t), minute(t), second(t));
  Serial.println(local);
}

Hello

There is a current thread that deals with all such issues
here

Edit
When you get to discussion about time zones (TZ)
The correct entry for London is

#define MY_TZ "GMT0BST,M3.5.0/1,M10.5.0"

Then it's later called in the sketch with

configTime(MY_TZ, "pool.ntp.org");

1 Like

Continuing the discussion from Recurring Updates to ESP32 Time on LED Clock Using NTP Server:

Hi There,

I have been directed to this page to discuss an issue I am having with DST on a UK NTP Server.

I've been using this code (below) but the local field only shows the correct hour once.

Any idea how I can resolve this, or is this a big issue ??

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

// Define your WiFi credentials
const char* ssid = "SSID";
const char* password = "Password";

// Define your timezone offset and whether it observes DST
TimeChangeRule BST = {"BST", Last, Sun, Mar, 1, 60}; // British Summer Time
TimeChangeRule GMT = {"GMT", Last, Sun, Oct, 2, 0};  // Greenwich Mean Time
Timezone UK(BST, GMT);

// Define NTP client and time server settings
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org");

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

  // Connect to WiFi
  WiFi.begin(ssid, password);
  Serial.print("Connecting to WiFi");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected.");

  // Initialize NTP client
  timeClient.begin();
  timeClient.setTimeOffset(0); // Set time offset to UTC (NTP servers return UTC time)
}

void loop() {
  // Update time from NTP server
  timeClient.update();
  unsigned long epochTime = timeClient.getEpochTime(); // Get Unix timestamp from NTP server
  time_t utc = epochTime;
  time_t local = UK.toLocal(utc); // Convert UTC time to local time (DST adjusted)

   int now_hour = timeClient.getHours();
   Serial.print("now_hour ");
   Serial.println(now_hour);


  // Print the DST adjusted local time
  Serial.print("DST Adjusted Local time: ");
  digitalClockDisplay(local);
  Serial.print("DST Adjusted Local time TWO: ");
  Serial.println(local);


  delay(1000);
}

void digitalClockDisplay(time_t t) {
  static char local[20];
  sprintf(local, "%02d:%02d:%02d", hour(t), minute(t), second(t));
  Serial.println(local);
}

This is the serial monitor log

16:31:05.571 -> DST Adjusted Local time: 16:31:05 **// correct value from void digitalClockDisplay **

16:31:05.571 -> DST Adjusted Local time TWO: 1712075465 // exactly the same field "local" printed a second time and it's reverted back to epoch time.

16:31:06.556 -> now_hour 15 // using get.Hours which does not take into consideration the clock change

I need the correct value to remain in a field, so I can manipulate it, with my code.

Many thanks

The problem that you have described is not really suitable for this thread.
(1) You appear to have an ESP8266 and (2) You are using the "Timezone.h" library.
The ESP32 code samples here use the ESP32 inbuilt internet time handling and time zone adjustments.
I'll flag your post so it can be moved to its own thread.

1 Like

@tk007b ,

Topic split from another topic. Please do not add your own questions to the end of other people's topics.

Could you take a few moments to Learn How To Use The Forum

It will help you get the best out of the forum in the future.

Thank you.

Try this sketch, with automatic DST.
It also has a WiFi manager that spins up a portal to enter your WiFi credentials (if needed).
Default update interval is 1 hour, which can be changed. See this page.
Leo..

#include <WiFiManager.h> // https://github.com/tzapu/WiFiManager install through the library manager of the IDE
#include <ESP8266WiFi.h>
unsigned long prevTime;
bool reSync;
time_t now;
tm tm;

/*
// uncomment this block to change NTP update interval (default is 1 hour)
uint32_t sntp_update_delay_MS_rfc_not_less_than_15000 () { 
  return 10 * 60 * 60 * 1000UL; // 10 hours
}
*/

void time_is_set() { // valid time string?
  Serial.println("time was updated");
  reSync = true;
}

void setup() {
  Serial.begin(74880); // native baud rate
  Serial.println("\nESP8266 Clock");
  WiFi.mode(WIFI_STA);
  WiFiManager wm;
  wm.autoConnect("Portal"); // open
  // https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv
  configTime("GMT0BST,M3.5.0/1,M10.5.0", "uk.pool.ntp.org"); // location, local pool
  settimeofday_cb(time_is_set); // enable callback
  while (!reSync) yield(); // wait here until a valid time string is received
}

void loop() {
  time(&now); // epoch
  localtime_r(&now, &tm); // local offset
  if (now != prevTime) { // only print if time has changed
    prevTime = now; // remember
    printf("%02u:%02u:%02u  %02u-%02u-%04u\n", tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_mday, tm.tm_mon + 1, tm.tm_year + 1900);
  }
}

Edit: added update interval block

Apologies,

I was pointed here by another user from a new post I created originally, in the Programming section, which I thought was correct.

comments respectfully noted :slight_smile:

TK

1 Like

Your code appears to be behaving correctly as it is written. It is, however, somewhat confusing that the same name, in this case local , has been used for two completely different variables in different contexts.

It is not completely clear what you are expecting but if you want the current hour in local time you can do something like this:

Change this block:

int now_hour = timeClient.getHours(); 
Serial.print("now_hour "); 
Serial.println(now_hour);

To:

int now_hour = timeClient.getHours(); 
Serial.print("now_hour UTC: "); 
Serial.println(now_hour);
int myLocalHour = hour( local ) ;  
Serial.print("  myLocalHour: "); 
Serial.println( myLocalHour  );
Serial.println();

Most of the code is "the old way".
A lot of the NTP time code is now included in the ESP core.
I have posted a complete sketch in your main (first) thread.
Leo..

We seem to be going around the houses here. I pointed you to the other thread so you could read
through the whole thing. Get some ideas as to how this is solved, by using a method that is available in the ESP8266 core libraries. Not with the library you are currently using. Maybe I should have pointed that out.

As @6v6gt points out, your original code is doing exactly what you have written. @Wawa has kindly popped over here and presented the 'modern' way of doing what you want at post#6. I myself have spent a lot of 'time' in recent months figuring the 'best way' to define a clock on ESP8266, the core functionality is the way to go.

So move away from <Timezone.h> and and at least try this.

Here is my version of the same with some added bells and whistles.

/*ESP8266_RTC_Example.ino*/
#include <ESP8266WiFi.h>

#define MY_TZ "GMT0BST,M3.5.0/1,M10.5.0"// Correct for UK

const char* ssid = "SSID";
const char* password = "PASSWORD";

const char * weekDays[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
const char * months[] = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"};
char ordInd[4][3] = { "th", "st", "nd", "rd" };  //Ordinal indicator
char isDst [4] = {"GMT"};


uint32_t startTime;
time_t now; // this are the seconds since Epoch (1970) - UTC
tm tm;

void time_is_set() {
  Serial.println(F("NTP time was set!"));
}

void printTime() {
  time(&now);
  localtime_r(&now, &tm);
  if (tm.tm_isdst) strcpy(isDst, "BST");
  else strcpy(isDst, "GMT");
  uint8_t  oi = ((tm.tm_mday + 90) % 100 - 10) % 10;//Ordinal indicator calculation
    if (oi > 3) oi = 0;
  Serial.print("Epoch ");
  Serial.println(now);
  printf(" %02d:%02d:%02d %s  %s %d%s %s %d\n\n", tm.tm_hour, tm.tm_min, tm.tm_sec, isDst, weekDays[tm.tm_wday], tm.tm_mday, ordInd[oi], months[tm.tm_mon], tm.tm_year + 1900);  
}

uint32_t sntp_update_delay_MS_rfc_not_less_than_15000 () {
  return 5 * 60 * 1000UL; // 5 mins NTP refresh for Demo only. Look for callback "NTP time was set!"
  //return 2 * 60 * 60 * 1000UL// every 2 hours is plenty for normal use
}

void setup() {
  Serial.begin(115200);
  delay(1000);
  WiFi.begin(ssid, password);
  Serial.print("\nConnecting");
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  Serial.println();
  Serial.print("Connected, IP address: ");
  Serial.println(WiFi.localIP());

  configTime(MY_TZ, "pool.ntp.org");//Simple system RTC
  startTime = millis();

  settimeofday_cb(time_is_set); // optional: callback if time was sent
}

void loop() {

  if (millis() - startTime > 15000) {
    startTime = millis();
    printTime();//Will print Time and Date in Serial monitor every 15 seconds
  }
}

Edit : Output should be as...

NTP time was set!
Epoch 1712133819
09:43:39 BST Wednesday 3rd April 2024

Epoch 1712133834
09:43:54 BST Wednesday 3rd April 2024

Epoch 1712133849
09:44:09 BST Wednesday 3rd April 2024

Epoch 1712133864
09:44:24 BST Wednesday 3rd April 2024

1 Like

Firstly,
I am VERY sorry for all of the confusion, I promise you it was not deliberate or due to laziness on my part. Just new to this and got a bit confused.

Secondly, thank you, your code works perfectly, I will study it carefully to better understand it and then integrate it into my main code.

I will also write to Wawa and apologise. ... I tried his code from my earlier thread but that did nothing sadly.

Thanks for your support and patience, it is appreciated.

TK :+1:t4:

1 Like

Hey Wawa,

Apologies for all of the confusion. I tried your code from the previous thread but sadly, it didn't work and did not prompt me for my WiFi Credentials either. The code that Indev2 has provided seems to work but happy to provide the messages / output from yours, when I tried it, if you like ?... thanks again :slight_smile:

TK

Note that an ESP32 and ESP8266 require totally different code. The code from post#6 works fine here on an ESP8266 NodeMCU. Note that it needs credentials, and waits to be synchronised before displaying the correct time. Those credentials could still be stored from a previous sketch, but it doesn't display the time (on boot-up) when no credentials are stored. Look at the WiFi page on your phone for a portal. If you want to see the portal, then set the IDE to "erase all flash content" before uploading. Make sure you set it back to "only sketch" afterwards.
Leo..

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.