[ESP32]現在時刻の取得について(getLocalTime/time,localtime)

ESP32

現在時刻の取得について

気になる現象

現在時刻を取得する際に、getLocalTime()で取得すると数秒の時間がかかっていることがありました。

ESP32は、起動後のまだ時刻を設定していない時は1970年1月1日午前0時0分0秒(UNIXエポック)からスタートします。そのタイミングで、getLocalTime()を使用すると時間がかかるようです。

実験コード

現在時刻設定前と後に現在時刻を取得し、取得するのに要した時間を表示するプログラムを動かしてみました。取得方法は[getLocalTime()]と[time(),localtime()]の2つの方法です。

使用API:getLocalTime() vs time(),localtime()

#include <WiFi.h>

const char* ssid     = "xxxxxx";
const char* password = "xxxxxx";

const char* ntpServer1 = "ntp.nict.jp";
const char* ntpServer2 = "time.google.com";
const char* ntpServer3 = "ntp.jst.mfeed.ad.jp";
const long  gmtOffset_sec = 9 * 3600;
const int   daylightOffset_sec = 0;

bool timeset = 0;

// 現在時刻表示
void showLocalTime()
{
  char str[256];
  static const char *wd[7] = { "日", "月", "火", "水", "木", "金", "土" };
  unsigned long m;

  // timeとlocaltimeを使用して現在時刻取得
  time_t t;
  struct tm *tm;
  m = millis();
  t = time(NULL);
  tm = localtime(&t);
  sprintf(str, "[time localtime] %04d/%02d/%02d(%s) %02d:%02d:%02d : %d (ms)", tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, wd[tm->tm_wday], tm->tm_hour, tm->tm_min, tm->tm_sec, millis()-m);
  Serial.println(str);

  // getLocalTimeを使用して現在時刻取得
  struct tm timeInfo;
  m = millis();
  getLocalTime(&timeInfo);  
  sprintf(str, "[getLocalTime  ] %04d/%02d/%02d(%s) %02d:%02d:%02d : %d (ms)", timeInfo.tm_year+1900, timeInfo.tm_mon+1, timeInfo.tm_mday, wd[timeInfo.tm_wday], timeInfo.tm_hour, timeInfo.tm_min, timeInfo.tm_sec, millis()-m);
  Serial.println(str);
}

void timeavailable(struct timeval *t)
{
  Serial.println("Got time adjustment from NTP!");
  timeset = 1;
}

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

  // 時刻設定前の時刻取得
  Serial.println("<<時刻設定前の時刻取得>>");
  for(int i=0;i<3;i++) {
    showLocalTime();
    delay(1000);
  }

  // Wifi接続処理
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      Serial.print(".");
  }
  // NTP
  sntp_set_time_sync_notification_cb( timeavailable );
  configTime(gmtOffset_sec, daylightOffset_sec, ntpServer1, ntpServer2, ntpServer3);

  // 時刻設定後の時刻取得
  while( !timeset ) {
    delay(1000);
  }
  Serial.println("<<時刻設定後の時刻取得>>");
  for(int i=0;i<3;i++) {
    showLocalTime();
    delay(1000);
  }
}

void loop()
{
  // put your main code here, to run repeatedly:
}

実験結果

<<時刻設定前の時刻取得>>
[time localtime] 1970/01/01(木) 00:00:00 : 0 (ms)
[getLocalTime  ] 1970/01/01(木) 00:00:05 : 5010 (ms)
[time localtime] 1970/01/01(木) 00:00:06 : 0 (ms)
[getLocalTime  ] 1970/01/01(木) 00:00:11 : 5010 (ms)
[time localtime] 1970/01/01(木) 00:00:12 : 0 (ms)
[getLocalTime  ] 1970/01/01(木) 00:00:17 : 5010 (ms)
.....Got time adjustment from NTP!
<<時刻設定後の時刻取得>>
[time localtime] 2023/05/10(水) 10:25:25 : 0 (ms)
[getLocalTime  ] 2023/05/10(水) 10:25:25 : 0 (ms)
[time localtime] 2023/05/10(水) 10:25:26 : 0 (ms)
[getLocalTime  ] 2023/05/10(水) 10:25:26 : 0 (ms)
[time localtime] 2023/05/10(水) 10:25:27 : 0 (ms)
[getLocalTime  ] 2023/05/10(水) 10:25:27 : 0 (ms)

理由はわかりませんが、NTPにて時刻を設定する前は、getLocalTime()で取得すると5秒程度要するようです。

time()とlocaltime()を使用して取得する場合は、すぐに取得できていますね。

1度時刻を設定してしまえば、どちらもすぐに取得できています。

まとめ

1度時刻を設定すると問題なく取得できるため、そこまで問題にならないケースが多いかもしれませんが、予期せぬ問題にならないようにtime()とlocaltime()を使用して現在時刻を取得した方が良いのかもしれません。

この問題の参考にさせていただいたサイト。

ESP32 の 時刻取得のオフライン時の挙動 - Qiita
ESP32/Arduino の 時刻取得のオフライン時の挙動ESP32で現在時刻を取得するにはNTPを使いますが、オフライン/オフライン時の挙動が知りたかったので、軽くテストしてみました。なお、…

コメント

タイトルとURLをコピーしました