ESP32 NTP время – настройка часовых поясов и летнего времени

В этом руководстве вы узнаете, как правильно получать время на ESP32 для вашего часового пояса с учётом перехода на летнее время (если это применимо). ESP32 запрашивает время у NTP-сервера, и оно автоматически корректируется для вашего часового пояса с учётом или без учёта летнего времени.

ESP32 часовые пояса и летнее время

Быстрый ответ: вызовите setenv(«TZ», timezone, 1), где timezone – одна из строк часовых поясов, перечисленных здесь. Затем вызовите tzset() для обновления часового пояса.


Если вы только начинаете, рекомендуем сначала ознакомиться со следующим руководством, чтобы узнать, как получить дату и время с NTP-сервера:

В предыдущем руководстве мы показали вариант настройки часового пояса. Однако тот пример не учитывает переход на летнее время. Продолжайте читать это руководство, чтобы узнать, как правильно настроить часовой пояс и летнее время.

Благодарим одного из наших читателей (Hardy Maxa), который поделился этой информацией с нами.

Настройка часового пояса ESP32 с учётом летнего времени

Согласно документации:

«Для установки локального часового пояса используйте POSIX-функции setenv и tzset. Сначала вызовите setenv, чтобы установить переменную окружения TZ в правильное значение в зависимости от местоположения устройства. Формат строки времени описан в документации libc. Затем вызовите tzset, чтобы обновить данные библиотеки C для нового часового пояса. После выполнения этих шагов функция localtime будет возвращать правильное местное время с учётом смещения часового пояса и летнего времени.»

Вы можете просмотреть список строковых переменных часовых поясов здесь.

Например, я живу в Порту. Часовой пояс – Europe/Lisbon. Из списка строковых переменных часовых поясов я вижу, что строковая переменная для моего местоположения – WET0WEST,M3.5.0/1,M10.5.0, поэтому после подключения к NTP-серверу, чтобы получить время для моего местоположения, мне нужно вызвать:

setenv("TZ","WET0WEST,M3.5.0/1,M10.5.0",1);

А затем:

tzset();

Давайте рассмотрим демонстрационный скетч, чтобы понять, как это работает и как использовать это в вашем проекте ESP32.

Пример скетча ESP32 с часовым поясом и DST

Следующий пример был предоставлен одним из наших подписчиков (Hardy Maxa), мы лишь внесли несколько изменений.

Скопируйте следующий код в вашу Arduino IDE.

// RTC demo for ESP32, that includes TZ and DST adjustments
// Get the POSIX style TZ format string from  https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv
// Created by Hardy Maxa
// Complete project details at: https://RandomNerdTutorials.com/esp32-ntp-timezones-daylight-saving/

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

const char * ssid="REPLACE_WITH_YOUR_SSID";
const char * wifipw="REPLACE_WITH_YOUR_PASSWORD";

void setTimezone(String timezone){
  Serial.printf("  Setting Timezone to %s\n",timezone.c_str());
  setenv("TZ",timezone.c_str(),1);  //  Now adjust the TZ.  Clock settings are adjusted to show the new local time
  tzset();
}

void initTime(String timezone){
  struct tm timeinfo;

  Serial.println("Setting up time");
  configTime(0, 0, "pool.ntp.org");    // First connect to NTP server, with 0 TZ offset
  if(!getLocalTime(&timeinfo)){
    Serial.println("  Failed to obtain time");
    return;
  }
  Serial.println("  Got the time from NTP");
  // Now we can set the real timezone
  setTimezone(timezone);
}

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

void  startWifi(){
  WiFi.begin(ssid, wifipw);
  Serial.println("Connecting Wifi");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(500);
  }
  Serial.print("Wifi RSSI=");
  Serial.println(WiFi.RSSI());
}

void setTime(int yr, int month, int mday, int hr, int minute, int sec, int isDst){
  struct tm tm;

  tm.tm_year = yr - 1900;   // Set date
  tm.tm_mon = month-1;
  tm.tm_mday = mday;
  tm.tm_hour = hr;      // Set time
  tm.tm_min = minute;
  tm.tm_sec = sec;
  tm.tm_isdst = isDst;  // 1 or 0
  time_t t = mktime(&tm);
  Serial.printf("Setting time: %s", asctime(&tm));
  struct timeval now = { .tv_sec = t };
  settimeofday(&now, NULL);
}

void setup(){
  Serial.begin(115200);
  Serial.setDebugOutput(true);
  startWifi();

  initTime("WET0WEST,M3.5.0/1,M10.5.0");   // Set for Melbourne/AU
  printLocalTime();
}

void loop() {
  int i;

  // put your main code here, to run repeatedly:
  Serial.println("Lets show the time for a bit.  Starting with TZ set for Melbourne/Australia");
  for(i=0; i<10; i++){
    delay(1000);
    printLocalTime();
  }
  Serial.println();
  Serial.println("Now - change timezones to Berlin");
  setTimezone("CET-1CEST,M3.5.0,M10.5.0/3");
  for(i=0; i<10; i++){
    delay(1000);
    printLocalTime();
  }

  Serial.println();
  Serial.println("Now - Lets change back to Lisbon and watch Daylight savings take effect");
  setTimezone("WET0WEST,M3.5.0/1,M10.5.0");
  printLocalTime();

  Serial.println();
  Serial.println("Now change the time.  1 min before DST takes effect. (1st Sunday of Oct)");
  Serial.println("AEST = Australian Eastern Standard Time. = UTC+10");
  Serial.println("AEDT = Australian Eastern Daylight Time. = UTC+11");
  setTime(2021,10,31,0,59,50,0);    // Set it to 1 minute before daylight savings comes in.

  for(i=0; i<20; i++){
    delay(1000);
    printLocalTime();
  }

  Serial.println("Now change the time.  1 min before DST should finish. (1st Sunday of April)");
  setTime(2021,3,28,1,59,50,1);    // Set it to 1 minute before daylight savings comes in.  Note. isDst=1 to indicate that the time we set is in DST.

  for(i=0; i<20; i++){
    delay(1000);
    printLocalTime();
  }

  // Now lets watch the time and see how long it takes for NTP to fix the clock
  Serial.println("Waiting for NTP update (expect in about 1 hour)");
  while(1) {
    delay(1000);
    printLocalTime();
  }
}

Просмотреть исходный код

Как работает код

Сначала вам нужно подключить библиотеку WiFi для подключения ESP32 к интернету (NTP-серверу) и библиотеку time для работы со временем.

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

Для установки часового пояса мы создали функцию setTimezone(), которая принимает в качестве аргумента строку часового пояса.

void setTimezone(String timezone){

Внутри этой функции мы вызываем setenv() для параметра TZ (часовой пояс), чтобы установить часовой пояс тем значением, которое вы передали в качестве аргумента функции setTimezone().

setenv("TZ",timezone.c_str(),1);  //  Now adjust the TZ.  Clock settings are adjusted to show the new local time

После этого вызываем функцию tzset(), чтобы изменения вступили в силу.

tzset();

Мы не будем подробно описывать остальные функции, объявленные в коде, так как они уже были объяснены в предыдущем руководстве:

setup()

В setup() мы инициализируем Wi-Fi, чтобы ESP32 мог подключиться к интернету для связи с NTP-сервером.

initWifi();

Затем вызываем функцию initTime() и передаём в качестве аргумента строку часового пояса. В нашем случае – для часового пояса Lisbon/PT.

initTime("WET0WEST,M3.5.0/1,M10.5.0");   // Set for Lisbon/PT

После этого выводим текущее местное время.

printLocalTime();

loop()

В loop() показываем местное время в течение десяти секунд.

Serial.println("Lets show the time for a bit.  Starting with TZ set for Lisbon/Portugal");
for(i=0; i<10; i++){
  delay(1000);
  printLocalTime();
}

Если в какой-то момент в вашем коде вам нужно сменить часовой пояс, вы можете сделать это, вызвав функцию setTimezone() и передав в качестве аргумента строку часового пояса. Например, следующие строки меняют часовой пояс на Берлин и отображают время в течение десяти секунд.

Serial.println();
Serial.println("Now - change timezones to Berlin");
setTimezone("CET-1CEST,M3.5.0,M10.5.0/3");
for(i=0; i<10; i++){
  delay(1000);
  printLocalTime();
}

Затем мы возвращаемся к нашему местному времени, снова вызывая функцию setTimezone() со строковой переменной часового пояса Lisbon/PT.

Serial.println();
Serial.println("Now - Lets change back to Lisbon and watch Daylight savings take effect");
setTimezone("WET0WEST,M3.5.0/1,M10.5.0");
printLocalTime();

Чтобы проверить, работает ли переход на летнее/зимнее время, мы изменим время на 10 секунд до перехода на зимнее время. В нашем случае это происходит в последнее воскресенье октября (для вашего местоположения это может быть иначе).

Serial.println();
Serial.println("Now change the time.  1 min before DST takes effect. (Last Sunday of Oct)");
setTime(2021,10,31,0,59,50,0);    // Set it to 1 minute before daylight savings comes in.

Затем показываем время некоторое время, чтобы убедиться, что оно корректируется с учётом DST.

for(i=0; i<20; i++){
  delay(1000);
  printLocalTime();
}

После этого снова изменим время, чтобы проверить, происходит ли переход на летнее время. В нашем случае это последнее воскресенье марта.

Serial.println("Now change the time.  1 min before DST should finish. (Last Sunday of March)");
setTime(2021,3,28,1,59,50,1);    // Set it to 1 minute before daylight savings comes in.  Note. isDst=1 to indicate that the time we set is in DST.

Показываем время некоторое время, чтобы убедиться, что произошёл переход на летнее время.

for(i=0; i<20; i++){
  delay(1000);
  printLocalTime();
}

Демонстрация

Теперь давайте протестируем код. После ввода ваших сетевых данных загрузите код на ESP32.

После этого откройте Serial Monitor на скорости 115200 бод и нажмите кнопку RST на ESP32, чтобы запустить выполнение кода.

Сначала отображается ваше местное время с часовым поясом, который вы установили в коде.

ESP32 NTP время -- установка часового пояса

После этого произойдёт смена на другой часовой пояс, который вы указали в коде. В нашем случае мы установили Берлин.

ESP32 NTP время -- переключение между часовыми поясами

Затем вы должны увидеть переход на зимнее время. В нашем случае, когда наступает 2 часа ночи, часы переводятся на один час назад.

ESP32 NTP время -- автоматический переход на зимнее время

Мы также проверяем, корректируется ли время при переходе на летнее время. В примере ниже вы можете видеть, что часы переводятся на один час вперёд для установки летнего времени.

ESP32 NTP время -- автоматический переход на летнее время

Заключение

Это краткое руководство научило вас настраивать часовой пояс с учётом летнего времени с помощью функций setenv() и tzset().

Надеемся, что это руководство оказалось для вас полезным. У нас есть другие руководства, связанные со временем, которые могут вам понравиться:


Источник: Random Nerd Tutorials – ESP32 NTP Time – Setting Up Timezones and Daylight Saving Time