Получить часовой пояс GMT в C
Я использую стандартную функцию mktime
, чтобы превратить struct tm
в значение времени эпохи. Поля tm
заполняются локально, и мне нужно получить эпоху в качестве GMT. tm
имеет поле gmtoff
, позволяющее вам установить локальное смещение GMT в секундах только для этой цели.
Но я не могу понять, как получить эту информацию. Разумеется, где-то должна быть стандартная функция, которая вернет смещение? Как это сделать localtime
?
Ответы
Ответ 1
Думаю, я должен был немного поработать, прежде чем спрашивать. Оказывается, существует небольшая известная функция timegm
, которая делает противоположное от gmtime
. Он поддерживает GNU и BSD, что достаточно хорошо для моих целей. Более портативное решение - временно установить значение переменной среды TZ
в "UTC", а затем использовать mktime
, а затем установить TZ
назад.
Но timegm
работает для меня.
Ответ 2
Просто выполните следующие действия:
#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()
, измеряются как в Гринвиче.
Ответ 3
Как это делает локальное время?
В соответствии с localtime
справочной страницей
Функция localtime() действует так, как если бы она называлась tzset (3), и устанавливает внешние переменные tzname с информацией о текущем часовом поясе, часовой пояс с разницей между координированным универсальным Время (UTC) и локальное стандартное время в секундах
Итак, вы можете либо вызвать localtime()
, и вы будете иметь разницу в timezone
или вызовите tzset()
:
extern long timezone;
....
tzset();
printf("%ld\n", timezone);
Примечание: если вы решите пойти с localtime_r()
, обратите внимание на то, что вам не нужно устанавливать эти переменные, вам нужно сначала вызвать tzset()
, чтобы установить timezone
:
В соответствии с POSIX.1-2004, localtime() требуется вести себя так, как будто tzset() был вызван, , тогда как localtime_r() не имеет этого требование. Для переносного кода tzset() следует вызывать перед localtime_r()
Ответ 4
Универсальная версия получения локальной функции смещения по времени находится здесь.
Я заимствовал фрагменты кода из ответа в 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);
}
Ответ 5
Я полагаю, что в Linux по крайней мере верно: информация о часовом поясе поступает из /usr/share/zoneinfo/. localtime читает /etc/localtime, который должен быть копией соответствующего файла из зоныinfo. Вы можете увидеть, что внутри, выполнив 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
Я думаю, вы могли бы разобрать это сами, если хотите. Я не уверен, есть ли функция stdlib, которая возвращает gmtoff (может быть, но я не знаю...)
edit: man tzfile описывает формат файла zoneinfo. Вы должны иметь возможность просто mmap в структуру соответствующего типа. Кажется, это то, что zdump делает на основе его strace.
Ответ 6
Вот двухслойный текст, вдохновленный ответами @Hill и @friedo:
#include <time.h>
...
time_t rawtime = time(0);
timeofs = timegm(localtime(&rawtime)) - rawtime;
Возвращает смещение от UTC в секундах.
Не требует определения _GNU_SOURCE
, но учтите, что timegm
не является стандартом POSIX и может быть недоступен за пределами GNU и BSD.