標準mktime
関数を使用して astruct tm
をエポック時間値に変換しています。フィールドはtm
ローカルで入力され、エポック時間を GMT として取得する必要があります。この目的のためにローカル GMT オフセットを秒単位で設定できるフィールドがtm
あります。gmtoff
しかし、その情報を取得する方法がわかりません。確かに、オフセットを返す標準関数がどこかにあるはずですか? それはどのようにlocaltime
行うのですか?
次の手順を実行してください。
#define _GNU_SOURCE /* for tm_gmtoff and tm_zone */
#include <stdio.h>
#include <time.h>
/* Checking errors returned by system calls was omitted for the sake of readability. */
int main(void)
{
time_t t = time(NULL);
struct tm lt = {0};
localtime_r(&t, <);
printf("Offset to GMT is %lds.\n", lt.tm_gmtoff);
printf("The time zone is '%s'.\n", lt.tm_zone);
return 0;
}
注:によって返されたエポックからの秒数はtime()
、グリニッジの場合と同様に測定されます。
localtime はどのようにそれを行いますか?
localtime
マニュアルページによると
localtime() 関数は、あたかも tzset(3) を呼び出したかのように動作し、外部変数 tzname に現在のタイムゾーンに関する情報を設定します。 タイムゾーン は、協定世界時 (UTC) とローカル標準時間の差 (秒単位) を使用します。
したがって、どちらかを呼び出すことができ、または呼び出しlocaltime()
の違いがあります。timezone
tzset()
extern long timezone;
....
tzset();
printf("%ld\n", timezone);
localtime_r()
注:これらの変数を設定する必要がないことに注意して選択する場合は、tzset()
最初に setを呼び出す必要がありtimezone
ます。
POSIX.1-2004 によると、localtime() は tzset() が呼び出されたかのように動作する必要がありますが、localtime_r() にはこの要件がありません。移植可能なコードの場合、localtime_r() の前に tzset() を呼び出す必要があります。
尋ねる前にもう少し検索をするべきだったと思います。timegm
の反対を行うほとんど知られていない関数があることがわかりましたgmtime
。それは私の目的には十分なGNUとBSDでサポートされています。より移植性の高い解決策は、環境変数の値を一時的TZ
に「UTC」にmktime
設定してから、を使用してから元にTZ
戻すことです。
しかしtimegm
、私のために働きます。
少なくとも Linux では次のことが当てはまると思います: タイムゾーン情報は /usr/share/zoneinfo/ から取得されます。localtime は、zoneinfo からの適切なファイルのコピーである /etc/localtime を読み取ります。タイムゾーン ファイルで実行することにより、内部の内容を確認できzdump -v
ます (zdump は sbin にある場合がありますが、タイムゾーン ファイルを読み取るために昇格されたアクセス許可は必要ありません)。ここに1つの抜粋があります:
/usr/share/zoneinfo/EST5EDT Sun Nov 6 05:59:59 2033 UTC = Sun Nov 6 01:59:59 2033 EDT isdst=1 gmtoff=-14400 /usr/share/zoneinfo/EST5EDT Sun Nov 6 06:00:00 2033 UTC = Sun Nov 6 01:00:00 2033 EST isdst=0 gmtoff=-18000 /usr/share/zoneinfo/EST5EDT Sun Mar 12 06:59:59 2034 UTC = Sun Mar 12 01:59:59 2034 EST isdst=0 gmtoff=-18000 /usr/share/zoneinfo/EST5EDT Sun Mar 12 07:00:00 2034 UTC = Sun Mar 12 03:00:00 2034 EDT isdst=1 gmtoff=-14400 /usr/share/zoneinfo/EST5EDT Sun Nov 5 05:59:59 2034 UTC = Sun Nov 5 01:59:59 2034 EDT
必要に応じて、これを自分で解析できると思います。gmtoffを返すだけのstdlib関数があるかどうかはわかりません(あるかもしれませんが、わかりません...)
編集: man tzfile は、zoneinfo ファイルの形式を説明しています。適切なタイプの構造に簡単に mmap できるはずです。それは、そのトレースに基づいて zdump が行っていることのようです。
これが私のやり方です:
time_t z = 0;
struct tm * pdt = gmtime(&z);
time_t tzlag = mktime(pdt);
の自動ローカル ストレージによる代替struct tm
:
struct tm dt;
memset(&dt, 0, sizeof(struct tm));
dt.tm_mday=1; dt.tm_year=70;
time_t tzlag = mktime(&dt);
tzlag
、秒単位で、UTC オフセットの負の値になります。UTC と比較した標準時のタイムゾーンの遅れ:
LocalST + tzlag = UTC
「夏時間」も考慮したい場合 は、 を特定の現地時間に適用した後 (または で取得した後)tm_isdst
から減算します。tzlag
tm_isdst
struct tm
mktime
localtime
機能する理由:
このセットstruct tm
は 1970 年 1 月 1 日の「エポック」の瞬間であり、これtime_t
は 0 に対応します。その日付を呼び出すmktime()
と、それが UTC であるかのように変換さtime_t
れ (したがって 0 になります)、それから UTC オフセットが減算されます。出力を生成する順序time_t
。したがって、UTC_offset のマイナスを生成します。