標準の mktime
関数を使用してstruct tm
をエポック時間値に。 tm
フィールドはローカルに入力されており、エポック時間をGMTとして取得する必要があります。 tm
にはgmtoff
フィールドがあり、この目的のためだけにローカルGMTオフセットを秒単位で設定できます。
しかし、その情報を取得する方法がわかりません。確かに、オフセットを返す標準関数がどこかになければなりませんか? localtime
はどのように実行しますか?
私は尋ねる前にもう少し検索を行うべきだったと思います。少し知られている timegm
関数があり、これはgmtime
の反対を行います。これは、GNU=とBSDでサポートされており、私の目的には十分です。よりポータブルなソリューションは、TZ
環境変数の値を一時的に "UTC"に設定して使用することです。 mktime
、次にTZ
を元に戻します。
しかし、timegm
は私にとってはうまくいきます。
次のようにしてください:
_#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
manページによると
Localtime()関数は、tzset(3)を呼び出したかのように動作し、外部変数tznameに現在のタイムゾーンに関する情報を設定しますtimezone協定世界時(UTC)とローカル標準時の差(秒単位)
したがって、localtime()
を呼び出すと、timezone
に違いがあるか、tzset()
を呼び出すことができます。
_extern long timezone;
....
tzset();
printf("%ld\n", timezone);
_
注:localtime_r()
を使用する場合は、これらの変数を設定する必要がないことに注意してください。timezone
を設定するには、最初にtzset()
を呼び出す必要があります。
POSIX.1-2004によれば、localtime()はtzset()が呼び出されたかのように動作する必要があります一方、localtime_r()にはこの要件はありません。移植可能なコードの場合、tzset()はlocaltime_r()の前に呼び出す必要があります
ローカル時間オフセット関数を取得するユニバーサルバージョンはこちらです。
statckoverflowの 答え からコードを借りました。
int time_offset()
{
time_t gmt, rawtime = time(NULL);
struct tm *ptm;
#if !defined(WIN32)
struct tm gbuf;
ptm = gmtime_r(&rawtime, &gbuf);
#else
ptm = gmtime(&rawtime);
#endif
// Request that mktime() looksup dst in timezone database
ptm->tm_isdst = -1;
gmt = mktime(ptm);
return (int)difftime(rawtime, gmt);
}
Linuxでは少なくとも次のことが当てはまると思います。タイムゾーン情報は/ usr/share/zoneinfo /から取得されます。 localtimeは、zoneinfoから適切なファイルのコピーである/ etc/localtimeを読み取ります。タイムゾーンファイルでzdump -v
を実行すると、内部を確認できます(zdumpはsbinにある場合がありますが、タイムゾーンファイルを読み取るために昇格したアクセス許可は必要ありません)。以下はその一部です:
/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が実行していることのようです。
@Hillと@friedoの回答に触発された2つのライナーがあります。
#include <time.h>
...
time_t rawtime = time(0);
timeofs = timegm(localtime(&rawtime)) - rawtime;
UTCからのオフセットを秒単位で返します。
_GNU_SOURCE
を定義する必要はありませんが、timegm
はPOSIX標準ではないため、GNUおよびBSD以外では使用できない場合があります。