web-dev-qa-db-ja.com

CのタイムゾーンGMTオフセットを取得します。

標準の mktime 関数を使用してstruct tmをエポック時間値に。 tmフィールドはローカルに入力されており、エポック時間をGMTとして取得する必要があります。 tmにはgmtoffフィールドがあり、この目的のためだけにローカルGMTオフセットを秒単位で設定できます。

しかし、その情報を取得する方法がわかりません。確かに、オフセットを返す標準関数がどこかになければなりませんか? localtimeはどのように実行しますか?

15
friedo

私は尋ねる前にもう少し検索を行うべきだったと思います。少し知られている timegm 関数があり、これはgmtimeの反対を行います。これは、GNU=とBSDでサポートされており、私の目的には十分です。よりポータブルなソリューションは、TZ環境変数の値を一時的に "UTC"に設定して使用することです。 mktime、次にTZを元に戻します。

しかし、timegmは私にとってはうまくいきます。

6
friedo

次のようにしてください:

_#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, &lt);

  printf("Offset to GMT is %lds.\n", lt.tm_gmtoff);
  printf("The time zone is '%s'.\n", lt.tm_zone);

  return 0;
}
_

注:time()によって返されるエポックからの秒数は、グリニッジの場合と同様に測定されます。

20
alk

現地時間はそれをどのように行うのですか?

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()の前に呼び出す必要があります

7
iabdalkader

ローカル時間オフセット関数を取得するユニバーサルバージョンはこちらです。
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);
}
4
Hill

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が実行していることのようです。

1
frankc

@Hillと@friedoの回答に触発された2つのライナーがあります。

#include <time.h>
...
time_t rawtime = time(0);
timeofs = timegm(localtime(&rawtime)) - rawtime;

UTCからのオフセットを秒単位で返します。

_GNU_SOURCEを定義する必要はありませんが、timegmはPOSIX標準ではないため、GNUおよびBSD以外では使用できない場合があります。

0
Duke Nukem