Преобразование между местным временем и GMT / UTC в C / C ++

Какой лучший способ конвертировать дату и время между местным временем и UTC в C / C ++?

Под «datetime» я подразумеваю некоторое представление времени, которое содержит дату и время дня. Я буду доволен time_t, struct tm или любым другим представлением, которое делает это возможным.

Моя платформа - Linux.

Вот конкретная проблема, которую я пытаюсь решить: я получаю пару значений, содержащих дату по юлиану и количество секунд в дне. Эти значения указаны в GMT. Мне нужно преобразовать это в значение "ГГГГММДДЧЧММСС" местного часового пояса. Я знаю, как преобразовать юлианскую дату в Г-М-Д, и, очевидно, легко преобразовать секунды в ЧЧММСС. Однако сложная часть - это преобразование часового пояса. Я уверен, что смогу найти решение, но я бы предпочел найти «стандартный» или «общеизвестный» способ, а не спотыкаться.


Возможно, связанный с этим вопрос: Получить даты перехода на летнее время для времени Зоны в C


person Community    schedule 17.04.2009    source источник


Ответы (3)


Вы должны использовать комбинации _1 _ / _ 2_ и _3 _ / _ 4_. Это должно дать вам ортогональные инструменты для преобразования между struct tm и time_t.

Для UTC / GMT:

time_t t;
struct tm tm;
struct tm * tmp;
...
t = timegm(&tm);
...
tmp = gmtime(t);

По местному времени:

t = mktime(&tm);
...
tmp = localtime(t);

Все, что делает tzset(), устанавливает внутреннюю переменную часового пояса из переменной среды TZ. Я не думаю, что это должно называться более одного раза.

Если вы пытаетесь выполнить преобразование между часовыми поясами, вам следует изменить struct tm tm_gmtoff.

person Rick C. Petty    schedule 17.04.2009
comment
Спасибо! Я знал, что должно существовать что-то вроде timegm (), но не знал названия. - person Kristopher Johnson; 17.04.2009
comment
Рад помочь. Преобразование времени может быть довольно сложной задачей. Обычно рекомендуется хранить все в формате UTC, когда это возможно. Преобразование между часовыми поясами еще сложнее! - person Rick C. Petty; 17.04.2009
comment
Да, к сожалению, разработчики системы выбрали местное время в качестве стандартного формата метки времени для протокола обмена сообщениями. Ненавижу, когда люди так поступают. - person Kristopher Johnson; 17.04.2009
comment
В Windows нет timegm. - person stepancheg; 21.12.2009
comment
Скорее всего, я задам это как отдельный вопрос (сейчас копаюсь в вопросах, в которых упоминается tm_gmtoff, а список довольно короткий), но: Не могли бы вы привести пример изменения tm_gmtoff и получения от него чего-нибудь полезного? Похоже, что это не меняет вывод, например, strftime(buf, BUFSIZ, "%FT%T%z (%+ %z)", tm);, когда я это делаю. ?? - person lindes; 23.02.2011
comment
Не похоже, что tm_gmtoff является стандартным членом struct tm. cplusplus.com/reference/clibrary/ctime/tm - person Oscar; 28.11.2011
comment
Как упомянул @stepancheg, timegm является нестандартным расширением GNU / BSD и недоступно в Windows и т. Д. На странице руководства Linux для timegm показан переносимый подход, основанный на изменении TZ в среде. К сожалению, это тоже не сразу переносится в Windows из-за отсутствия setenv. - person Trevor Robinson; 16.01.2013
comment
В Windows вы можете использовать _mkgmtime(&tm);, он интерпретирует struct tm как время в формате UTC, а не в вашем текущем TZ. - person dash-tom-bang; 26.07.2016

Если в Windows вам недоступна функция timegm ():

struct tm *tptr;
time_t secs, local_secs, gmt_secs;
time( &secs );  // Current time in GMT
// Remember that localtime/gmtime overwrite same location
tptr = localtime( &secs );
local_secs = mktime( tptr );
tptr = gmtime( &secs );
gmt_secs = mktime( tptr );
long diff_secs = long(local_secs - gmt_secs);

или что-то подобное ...

person Community    schedule 24.06.2009
comment
Разве secs и gmt_secs не должны быть идентичными? Я думаю, вы могли бы немного упростить это. - person jowo; 17.01.2012
comment
Я пробовал это. Я попытался проверить это, сравнив результат с обратным. Иногда он работает, а иногда отключается на час. Я предполагаю, что это потому, что летнее время начинается и заканчивается в разные даты в разных местах, которые я пытаюсь (используя GMT, но конвертируя по местному времени PST). Есть ли способ это компенсировать? - person Chris Westin; 22.02.2012
comment
Эта версия, в которой используется библиотека времени Boost POSIX, похоже, работает, несмотря на разные даты перехода на летнее время в часовых поясах: stackoverflow.com/a/6849810/857029. - person Chris Westin; 22.02.2012

Если вам нужно беспокоиться о преобразовании даты / времени с помощью правил часового пояса, вы можете изучить ICU.

person chrish    schedule 18.04.2009