ESP8266 mktime(timeinfo) возвращает другую дату

jack_k
Offline
Зарегистрирован: 08.12.2016

Здравствуйте, помогите пока я с ума не сошел. Почему даты отличаются?! Понятно, что сам дурак, но где?

#include <time.h>

void loop{


  struct tm * ti;
  time(&now);
  //текущая дата Mon Dec 11 17:26:21 2017
  ti = localtime(&now);  
  time_t t = mktime(ti);
  Serial.println(ctime(&t));
 // возвращает Wed Apr 10 05:35:05 1957

}

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Можно скетч целиком? Хочется видеть как Вы текущую дату установили.

jack_k
Offline
Зарегистрирован: 08.12.2016
 
после преобразования 
time_t now; //объявление, 
time(&now); //Now Mon Dec 11 17:50:11 2017
ti = localtime(&now); 
time_t t = mktime(ti);
Serial.println(ctime(&t)); // возвращает Wed Apr 10 05:35:05 1957

получаю не ту дату, которая на входе

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Вы не поняли вопроса. Меня интересует как Вы устанавливали текущую дату. Давайте скетч целиком.

jack_k
Offline
Зарегистрирован: 08.12.2016
#include <FS.h>                   //this needs to be first, or it all crashes and burns...
//#include <ESP8266WiFi.h>
#include <WiFiManager.h>          //https://github.com/tzapu/WiFiManager
#include <time.h>


time_t now;
time_t te;
time_t td;

 
void wifimanstart() { // Волшебная процедура начального подключения к Wifi.
                      // Если не знает к чему подцепить - создает точку доступа ESP8266 и настроечную таблицу http://192.168.4.1
                      // Подробнее: https://github.com/tzapu/WiFiManager
  WiFiManager wifiManager;
  wifiManager.setDebugOutput(1);
  wifiManager.setMinimumSignalQuality();
  if (!wifiManager.autoConnect("ESP8266")) {
  if (1) Serial.println("failed to connect and hit timeout");
    delay(3000);
    //reset and try again, or maybe put it to deep sleep
    ESP.reset();
    delay(5000); }
if (1) Serial.println("connected...");
}



void setup() {

  Serial.begin(115200);
  Serial.println();
  wifimanstart();
  String Statuses[] =  { "WL_IDLE_STATUS=0", "WL_NO_SSID_AVAIL=1", "WL_SCAN_COMPLETED=2", "WL_CONNECTED=3", "WL_CONNECT_FAILED=4", "WL_CONNECTION_LOST=5", "WL_DISCONNECTED=6"};
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println(Statuses[WiFi.status()]);
  }
  delay(1000);
   
}

void loop() {
  configTime(7 * 3600, 0, "pool.ntp.org", "time.nist.gov");
  while (!time(nullptr)) {
    delay(1000);
  }  
  struct tm * ti;
  time(&now);
  ti = localtime(&now); 
  Serial.print("Today ");
  Serial.println(ctime(&now));
  
  Serial.println("year = " + String(ti->tm_year));
  Serial.println("month = " + String(ti->tm_mon));
  Serial.println("day of month = " + String(ti->tm_mday));

  time_t t = mktime(ti);

  Serial.println(ctime(&t));
  delay(10000);
 }

Результат вывода:

Today Mon Dec 11 18:19:39 2017
 
year = 117
month = 11
day of month = 11
Wed Apr 10 06:27:07 1957
 

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Вот теперь понятно.

Текущее время Вы взяли с NTP а потом используете его без преобразования. Дело в том, что NTP время - это количество секунд с 01.01.1900. А mktime ожидает, что ему дадут время, в зависимости от реализации библиотеки time, или в UNIX времени (секунды с 01.01.1970 года) или даже в Y2K времени (секунды с 01.01.2000 года).

Прежде, чем подсовывать время функции mktime, Вам необходимо его преобразовать, т.е. вычесть из него количество секунд между 01.01.1970 и 01.01.1900 (если у Вас время в UNIX) или между  01.01.2000 и 01.01.1900 (если у Вас время в Y2K).

Откройте Ваш файл time.h и поищите там константу NTP_OFFSET (или как-то похоже). Это именно то число, которое нужно вычесть.

Т.е. схема такая:

time_t now;
time(& now);
now -= NTP_OFFSET;
// теперь можно пользоваться mktime

Вот здесь ещё почитайте, подобная тема уже обсуждалась.

llaabbss
Offline
Зарегистрирован: 28.12.2017

ЕвгенийП, здравствуйте.

Вы уже разобрались с этой темой, а у меня есть вопрос. Пытаюсь задать два времени и высчитать разницу между ними, но результат получаю неправильный.

#include <time.h>

time_t tmConvert_t(int YYYY, byte MM, byte DD, byte hh, byte mm, byte ss){

  struct tm tmSet;
  tmSet.tm_year = YYYY - 1900;
  tmSet.tm_mon = MM;
  tmSet.tm_mday = DD;
  tmSet.tm_hour = hh;
  tmSet.tm_min = mm;
  tmSet.tm_sec = ss;
  return mktime(&tmSet); 
}

void setup() {
  
  Serial.begin(115200);
  
  time_t s_tm1 = tmConvert_t(2018,11,14,1,0,58);
  time_t s_tm2 = tmConvert_t(2018,11,14,1,0,59);

  uint32_t timeDiff = s_tm2 - s_tm1;

  Serial.print(F("timeDiff: ")); Serial.println(timeDiff);

}

void loop() {
  
}

Результат отличается от ожидаемой 1 секунды.

sadman41
Offline
Зарегистрирован: 19.10.2016

И что получается - 10 секунд?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

У меня не отличается

timeDiff: 1

IDE 1.8.6

llaabbss
Offline
Зарегистрирован: 28.12.2017

А у меня результаты такие:

s_tm1: 598048100
s_tm2: 598064459
timeDiff: 16359
 
IDE 1.8.7
ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

llaabbss пишет:

А у меня результаты такие:

s_tm1: 598048100
s_tm2: 598064459
timeDiff: 16359
 

Сравните код из поста #6 с Вашими "результатами". Они не могут быть такими, хотя бы потому. что в коде не печатаются s_tm1 и s_tm2.

Значит, Вы показываете нам один код, а результаты от другого. Зачем?

Код и поста #6 я только что запускал и результат Вам привёл.

llaabbss
Offline
Зарегистрирован: 28.12.2017

Я задал разницу в 1 сутки (ровно 24 часа):

time_t s_tm1 = tmConvert_t(2018,11,14,1,0,58);
time_t s_tm2 = tmConvert_t(2018,11,13,1,0,58);

В результате разница в моей системе составляет 4294880896 секунд. А ожидаемое значение должно быть 86400 секунд.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

llaabbss пишет:

Я задал разницу в 1 сутки (ровно 24 часа):

time_t s_tm1 = tmConvert_t(2018,11,14,1,0,58);
time_t s_tm2 = tmConvert_t(2018,11,13,1,0,58);

Вы из меньшего вычитаете большее и получаете именно то, что должны получить, т.е. -86400, но в беззнаковом варианте. Это легко проверить: 2 в 32 степени равно 4294967296. Вычтете из этого полученный Вами результат

4294967296 - 4294880896 = 86400

Всё путём!

llaabbss
Offline
Зарегистрирован: 28.12.2017

Да, все верно. Я даже не обратил внимание на то, что из меньшего пытаюсь вычесть большее )).

Спасибо огромное за отзывчивость и помощь!

Хорошего дня

llaabbss
Offline
Зарегистрирован: 28.12.2017

И все же есть еще что спросить у вас ))

Как только я добавляю вывод в последовательный порт любых других данных, то результат сразу оказывается неверным. Например:

#include <time.h>

time_t tmConvert_t(int YYYY, byte MM, byte DD, byte hh, byte mm, byte ss){

  struct tm tmSet;
  tmSet.tm_year = YYYY - 1900;
  tmSet.tm_mon = MM;
  tmSet.tm_mday = DD;
  tmSet.tm_hour = hh;
  tmSet.tm_min = mm;
  tmSet.tm_sec = ss;
  return mktime(&tmSet); 
}

void setup() {
  
  Serial.begin(115200);
  
  time_t lesserTime = tmConvert_t(2018,11,14,1,0,50);
  time_t biggerTime = tmConvert_t(2018,11,14,1,0,59);

  time_t timeDiff = biggerTime - lesserTime;

  Serial.print(F("lesserTime: ")); Serial.println(lesserTime);  // Это искажает результат
  Serial.print(F("biggerTime: ")); Serial.println(biggerTime);  // Это искажает результат
  Serial.print(F("timeDiff: ")); Serial.println(timeDiff); // Это не влияет на правильность результата (правильно: 9)
  Serial.println(F("The end")); // Это не влияет на правильность результата

}

void loop() {
  
}

В чем тут может быть дело? Если закомментировать строки 24 И 25, тогда результат выводится верным.

sadman41
Offline
Зарегистрирован: 19.10.2016

 Serial.println((uint32_t) lesserTime) ?

llaabbss
Offline
Зарегистрирован: 28.12.2017

Это дает такой результат:

598048092
timeDiff: 16367
The end
 
ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

llaabbss пишет:

В чем тут может быть дело? Если закомментировать строки 24 И 25, тогда результат выводится верным.

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

lesserTime: 598064450
biggerTime: 598064459
timeDiff: 9
The end

Давайте подробно и всё по проядку, что за ардуина,как загружаете скетч, что за IDE - все подробности.

llaabbss
Offline
Зарегистрирован: 28.12.2017

Это клон УНО. Загружаю через USB напрямую от компа, IDE 1.8.7

llaabbss
Offline
Зарегистрирован: 28.12.2017

Все, кажется я все понял. Проблема, похоже, именно в клоне UNO. Залил этот же скетч на ESP32 и там все работает как надо. Так что тему можно закрывать. Всем спасибо ))

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Так не бывает. Дело в каких-то программа и библиотеках. Сама по себе плата (микросхема) так шутить не может. Дайте-ка я скачаю 1.8.7 ... минутку

Какую плату Вы ей указываете в меню "Tools"? Uno?

llaabbss
Offline
Зарегистрирован: 28.12.2017

Указываю это:

Плата: Arduino/Genuino UNO

Программатор: AVRISP mkll

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Но программатором Вы не пользуетесь, через USB заливаете, так?

Ну, скачал, запустил - нормально всё.

Только вот всё равно не понимаю, чем клон виноват.У меня есть "самогонный" клон (просто голый микроконтроллер с парой конденсаторов) и на нём всё нормально. И на Тини86 - тоже.

В общем, Вам, наверное, вот в эту тему надо.

llaabbss
Offline
Зарегистрирован: 28.12.2017

Согласен, странно и вроде быть не должно, но мне важнее работа скетча на ESP32 ))

На УНО я решил проверить отдельный блок. 

В любом случае спасибо ))