PR 記事には広告が含まれています
スポンサーリンク
Translate

ESP32は2038年問題に未対応ではないだろうか

スポンサーリンク

スポンサーリンク

getLocalTime()がエラーになる

GPSから取得した時刻を、システム時刻として取り入た後、getLocalTime()関数を呼ぶとエラーが返ってくることがありました。

GPSから得た年月日と日時は、以下のようなプログラムでシステム時刻に設定しています。

  struct tm t;
  t.tm_year = gps.date.year() - 1900;
  t.tm_mon = gps.date.month() - 1;
  t.tm_mday = gps.date.day();
  t.tm_hour = gps.time.hour();
  t.tm_min =  gps.time.minute();
  t.tm_sec = gps.time.second();
  time_t timertc = mktime(&t) + JST;
  struct timeval tv = {  .tv_sec = timertc };
  settimeofday(&tv, NULL);

この後、getLocalTime()関数を呼ぶと、電源投入後しばらくの間エラーが返ってきてしまいます。

原因を調べていくと、エラーになる条件はGPSモジュールがコールドスタートした時に、しばらくの間、適当な年月日を返していて、年が2080年になっている時でした。

2080年が設定されたtm構造体でシステム時刻を設定しようとすると、おかしいことになるようです。

試しに、2080年が設定されたtm構造体をmktime()でUNIX Timeに変換した結果を見てみました。

Serial.println( mktime(&t) );

すると、結果は

-823177642

マイナスの値が表示されました。

スポンサーリンク

ESP32のtime_tは2038年問題が起こる?

負の値が返ってくるということは、もしかすると2038年問題に遭遇してしまうということです。

2038年問題は、時刻の情報をsigned int(32bit)の型で保持したシステムが、2038年1月19日3時14分8秒になった途端にsigned intが負の値になってしまい、正しく時刻の処理ができなくなる問題です。

最近のシステムは64bit化したり32bitでもunsignedにしたりして、対策を進めているようですが、ESP32の場合はsigned int(32bit)のままなのかもしれません。

試しに以下のプログラムを実行してみました。

#define Y2038_BUG 2147483648  //2038年1月19日3時14分8秒

time_t now;

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

  now = Y2038_BUG;

  Serial.println("");
  Serial.print("Time_t:");
  Serial.println(now);
  Serial.print("Time_t size:");
  Serial.print( sizeof(now) );
  Serial.print(" Bytes");
}

void loop() {
}

time_tを、問題の発生する2038年1月19日3時14分8秒にして、time_tと、time_tのバイト数を見てみます。

結果は

Time_t:-2147483648
Time_t size:4 Bytes

time_tはマイナスの値になってしまいました。型のサイズも4バイトなので32bitということですね。

マイナスになるということは、singed int(32bit)ということでしょう。

これが本当ならば、ESP32でtime_tを使うプログラムは、2038年にバグが発生してしまいます。NTPを使ったプログラムなんかも、対象になってしまうでしょう。

今回のGPSモジュールを使った時計の場合、2038年以降、getLocalTime()がエラーを返すため、時刻の表示できなくなってしまいます。とりあえず、time_tを使わないプログラムへ変更しようと思います。

signed なのか unsigned なのかは、time_tの定義を見ればはっきりとわかるのですが、見つけられませんでした。

ESP32のtime_tにはご注意ください。