10

Ubuntu 12.04.3 LTSボックスで作業していると、プロセスの存続期間中にシステムのタイムゾーンが変更されると、 localtime() と localtime_r() の動作が異なることに気付きました: localtime() はタイムゾーンの変更をすぐに取得しますが、 localtime_r() は行いますそうではなく、プロセスの開始時のタイムゾーンに固執しているようです。これは予想される動作ですか?私はこれがカバーされているのを見たことがありません。

より正確には、次のコードを使用すると...

#include <stdio.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>

int main() {
  while (1) {
    time_t t = time(NULL);
    struct tm *tm = localtime(&t);
    printf("localtime:%02d/%02d/%02d-%02d:%02d:%02d\n",
           tm->tm_mon + 1, tm->tm_mday, tm->tm_year + 1900,
           tm->tm_hour, tm->tm_min, tm->tm_sec);
    sleep(1);
  }
  return 0;
}

...そして...経由でタイムゾーンをUTCから変更します

# echo 'Europe/Berlin' > /etc/timezone 
# sudo dpkg-reconfigure --frontend noninteractive tzdata

... 次に、コードは以下を生成します ...

localtime:10/04/2013-01:11:33
localtime:10/04/2013-01:11:34
localtime:10/04/2013-01:11:35
localtime:10/03/2013-23:11:36
localtime:10/03/2013-23:11:37
localtime:10/03/2013-23:11:38

...しかし、私が使用する場合:

#include <stdio.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>

int main() {
  while (1) {
    time_t t = time(NULL);
    struct tm local_tm;
    struct tm *tm = localtime_r(&t, &local_tm);    
    printf("localtime_r:%02d/%02d/%02d-%02d:%02d:%02d\n",
           tm->tm_mon + 1, tm->tm_mday, tm->tm_year + 1900,
           tm->tm_hour, tm->tm_min, tm->tm_sec);
    sleep(1);
  }
  return 0;
}

...その後、同様のタイムゾーンの変更を行っても変更はありません:

localtime_r:10/04/2013-01:15:37
localtime_r:10/04/2013-01:15:38
localtime_r:10/04/2013-01:15:39
localtime_r:10/04/2013-01:15:40
localtime_r:10/04/2013-01:15:41
localtime_r:10/04/2013-01:15:42

更新: localtime_r() を呼び出す前に tzset() への呼び出しを追加すると、期待される動作が生成されます。それが仕様/マンページから明らかであるかどうか(以下の説明を参照)は、mentalhealth.stackexchange.comの質問です...

4

1 に答える 1

8

次のドキュメントを参照してください。

localtime() 関数は、カレンダーの時刻 timep を、ユーザーが指定したタイムゾーンを基準にして表現される細分化された時刻表現に変換します。この関数は tzset(3) を呼び出したかのように動作し、外部変数 tzname に現在のタイムゾーンに関する情報、協定世界時 (UTC) と現地標準時との差 (秒単位) のタイムゾーン、および夏時間の場合は daylight をゼロ以外の値に設定します。節約時間の規則は、年の一部に適用されます。戻り値は、静的に割り当てられた構造体を指します。この構造体は、その後の日付および時刻関数の呼び出しによって上書きされる可能性があります。localtime_r() 関数は同じことを行いますが、ユーザー提供の構造体にデータを格納します。tzname、timezone、および daylight を設定する必要はありません。

から: http://linux.die.net/man/3/localtime_r

私が知る限り、コードは期待どおりに機能しているようです。

同じドキュメントからさらに追加するために編集されました:

POSIX.1-2004 によると、localtime() は tzset(3) が呼び出されたかのように動作する必要がありますが、localtime_r() にはこの要件がありません。移植可能なコードでは、localtime_r() の前に tzset(3) を呼び出す必要があります。

于 2013-10-03T23:29:22.307 に答える