Подтвердить что ты не робот

Получить часовой пояс GMT в C

Я использую стандартную функцию mktime, чтобы превратить struct tm в значение времени эпохи. Поля tm заполняются локально, и мне нужно получить эпоху в качестве GMT. tm имеет поле gmtoff, позволяющее вам установить локальное смещение GMT ​​в секундах только для этой цели.

Но я не могу понять, как получить эту информацию. Разумеется, где-то должна быть стандартная функция, которая вернет смещение? Как это сделать localtime?

4b9b3361

Ответ 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, &lt);

  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.